Skip to content

Commit

Permalink
booty repo server and client
Browse files Browse the repository at this point in the history
  • Loading branch information
alexadhy committed Mar 25, 2021
1 parent c7fcff8 commit 90f0121
Show file tree
Hide file tree
Showing 11 changed files with 648 additions and 151 deletions.
6 changes: 5 additions & 1 deletion cmd/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import (

// Simple wrapper for git
func GitWrapperCmd(gw dep.GitWrapper) *cobra.Command {
gitCmd := &cobra.Command{Use: "gw", DisableFlagParsing: true, Short: "Gee Dubs (gw) is a simple wrapper for git, see -help for subcommands"}
gitCmd := &cobra.Command{
Use: "gw",
DisableFlagParsing: true,
Short: "Gee Dubs (gw) is a simple wrapper for git, see -help for subcommands",
}
gitCmd.DisableFlagParsing = true
gitCmd.Flags().SetInterspersed(true)
tagCmd := &cobra.Command{Use: "tag <subcommand>", Short: "tag a release"}
Expand Down
79 changes: 79 additions & 0 deletions cmd/repo.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package cmd

import (
"fmt"
"github.com/spf13/cobra"
"go.amplifyedge.org/booty-v2/internal/repoclient"
"go.amplifyedge.org/booty-v2/internal/reposerver"
"net/http"
)

const (
defaultPort = 8085
defaultServerAddr = "http://localhost:8085"
)

var (
port int
serverAddr string
)

func PkgRepoServerCmd() *cobra.Command {

serveCmd := &cobra.Command{
Use: "serve",
Short: "Start package repository server",
}
serveCmd.Flags().IntVarP(&port, "port", "p", defaultPort, "default port to run the repository package server")
serveCmd.RunE = func(cmd *cobra.Command, args []string) error {
r := reposerver.NewServer()
return http.ListenAndServe(fmt.Sprintf(":%d", port), r)
}
return serveCmd
}

func PkgRepoClientCmd() *cobra.Command {
clientCmd := &cobra.Command{
Use: "client",
Short: "Run upload/download client to the server.",
}
clientCmd.Flags().StringVarP(&serverAddr, "server", "s", defaultServerAddr, "server address")

subcmds := []*cobra.Command{
{
Use: "auth",
Short: "authenticate request",
Example: "auth <user> <password>",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
return repoclient.AuthCli(serverAddr, args[0], args[1])
},
},
{
Use: "ul",
Short: "upload file to repository",
Example: "ul <location_to_file>",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
name, err := repoclient.UploadCli(serverAddr, args[0])
if err != nil {
return err
}
fmt.Println("uploaded id: " + name)
return nil
},
},
{
Use: "dl",
Short: "download file from package repository",
Example: "dl <file_id> <target_dir>",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
return repoclient.DownloadCli(serverAddr, args[0], args[1])
},
},
}

clientCmd.AddCommand(subcmds...)
return clientCmd
}
2 changes: 2 additions & 0 deletions dep/orchestrator/orchestrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ func (o *Orchestrator) Command() *cobra.Command {
cmd.CleanCacheCmd(o),
cmd.CompletionCommand(o),
cmd.HugoCommand(o),
cmd.PkgRepoServerCmd(),
cmd.PkgRepoClientCmd(),
}
if o.cfg.DevMode {
extraCmds = append(
Expand Down
7 changes: 6 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ require (
github.com/cheggaaa/pb/v3 v3.0.6
github.com/fatih/color v1.10.0
github.com/fsnotify/fsnotify v1.4.9 // indirect
github.com/go-chi/chi v1.5.4
github.com/go-chi/jwtauth v1.2.0
github.com/go-git/go-git/v5 v5.2.0
github.com/golang/protobuf v1.5.1 // indirect
github.com/google/go-github v17.0.0+incompatible
Expand All @@ -15,6 +17,7 @@ require (
github.com/inconshreveable/go-update v0.0.0-20160112193335-8152e7eb6ccf
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0
github.com/kardianos/service v1.2.0
github.com/lestrrat-go/jwx v1.1.0
github.com/magiconair/properties v1.8.4 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/otiai10/copy v1.5.0
Expand All @@ -26,12 +29,14 @@ require (
github.com/spf13/viper v1.7.1 // indirect
github.com/stretchr/testify v1.7.0
github.com/tidwall/pretty v1.1.0 // indirect
github.com/tus/tusd v1.5.1
go.amplifyedge.org/shared-v2/tool/bs-crypt v0.0.0-20210219053301-6556f04a088c
go.amplifyedge.org/shared-v2/tool/bs-lang v0.0.0-20210320051439-7e70b8c840c1
go.uber.org/zap v1.16.0
golang.org/x/crypto v0.0.0-20210218145215-b8e89b74b9df
golang.org/x/mod v0.4.1
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4 // indirect
golang.org/x/sys v0.0.0-20210319071255-635bc2c9138d // indirect
golang.org/x/sys v0.0.0-20210324051608-47abb6519492 // indirect
google.golang.org/api v0.42.0 // indirect
google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6 // indirect
gopkg.in/ini.v1 v1.62.0 // indirect
Expand Down
196 changes: 51 additions & 145 deletions go.sum

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions internal/downloader/dl2.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ func Download(dlUrl string, targetDir string) error {

if notex, err = IsEmptyDir(targetDir); notex || err != nil {
httpGetter := getter.HttpGetter{Netrc: true}
pbar := progressBar{}
pbar := ProgressBar{}
progress := []getter.ClientOption{getter.WithProgress(&pbar)}
if osutil.GetOS() == "windows" {
progress = []getter.ClientOption{}
Expand All @@ -45,7 +45,7 @@ func Download(dlUrl string, targetDir string) error {
return nil
}

type progressBar struct {
type ProgressBar struct {
lock sync.Mutex
progress *pb.ProgressBar
}
Expand All @@ -56,7 +56,7 @@ type progressBar struct {

const pbTpl pb.ProgressBarTemplate = `{{ string . "prefix" }} {{counters . | green }} {{ bar . "<" "=" (cycle . "↖" "↗" "↘" "↙" ) "." ">" | cyan }} {{speed . | green }} {{percent .}} {{ string . "suffix" }}`

func (cpb *progressBar) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser {
func (cpb *ProgressBar) TrackProgress(src string, currentSize, totalSize int64, stream io.ReadCloser) io.ReadCloser {
cpb.lock.Lock()
defer cpb.lock.Unlock()
if cpb.progress == nil {
Expand Down
9 changes: 8 additions & 1 deletion internal/osutil/osdetect.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func init() {

func setupDirs() (appDirs, error) {
prefix := getInstallPrefix()
dirs := []string{"bin", "etc", "data", "cache", "include"}
dirs := []string{"bin", "etc", "data", "cache", "include", "uploads"}
ad := appDirs{}
for i := range dirs {
dirPath := filepath.Join(prefix, dirs[i])
Expand All @@ -47,6 +47,8 @@ func setupDirs() (appDirs, error) {
ad.cache = dirPath
case "include":
ad.include = dirPath
case "uploads":
ad.include = dirPath
}
}
return ad, nil
Expand All @@ -59,6 +61,7 @@ type appDirs struct {
etc string // contains configurations
include string // contains shared library
cache string // contains downloaded tarballs
uploads string // contains uploaded binaries
}

// runtimeInfo for the whole application
Expand Down Expand Up @@ -172,6 +175,10 @@ func GetDownloadDir() string {
return dirs.cache
}

func GetUploadDir() string {
return dirs.uploads
}

func GetIncludeDir() string {
return dirs.include
}
Expand Down
110 changes: 110 additions & 0 deletions internal/pass/pass.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
// package pass
// provides password generation and verification using argon2id
// encoded passwords are stored in the format of:
// $<ARGON_ALGO (i'm using argon2id)>$<version>:$MEM,ITER,PAR:$<SALT>:$<KEY>
package pass

import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"errors"
"fmt"
"strings"

"golang.org/x/crypto/argon2"
)

var (
ErrWrongHash = errors.New("error: incorrect hash format")
ErrIncompatibleVersion = errors.New("error: incompatible version of argon algorithm")
)

// Hashing Parameter
// TODO: Parameterize this
const (
MEM = 64 * 1024
ITER = 1
PAR = 2
SLENGTH = 16
KLENGTH = 32
)

func GenHash(password string) (hash string, err error) {
s, err := genRandBytes(SLENGTH)
if err != nil {
return "", err
}

k := argon2.IDKey([]byte(password), s, ITER, MEM, PAR, KLENGTH)

salt := base64.RawStdEncoding.EncodeToString(s)
key := base64.RawStdEncoding.EncodeToString(k)

hash = fmt.Sprintf(
"$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s",
argon2.Version, MEM, ITER, PAR, salt, key)
return base64.RawStdEncoding.Strict().EncodeToString([]byte(hash)), nil
}

func VerifyHash(password, hash string) (match bool, err error) {
salt, key, err := decodeHash(hash)
if err != nil {
return false, err
}

otherKey := argon2.IDKey([]byte(password), salt, ITER, MEM, PAR, KLENGTH)

keyLen := int32(len(key))
otherKeyLen := int32(len(otherKey))

if subtle.ConstantTimeEq(keyLen, otherKeyLen) == 0 {
return false, nil
}
if subtle.ConstantTimeCompare(key, otherKey) == 1 {
return true, nil
}
return false, nil
}

func genRandBytes(n uint64) ([]byte, error) {
b := make([]byte, n)
_, err := rand.Read(b)
if err != nil {
return nil, err
}

return b, nil
}

func decodeHash(hash string) (salt, key []byte, err error) {
v, err := base64.RawStdEncoding.DecodeString(hash)
if err != nil {
return nil, nil, ErrWrongHash
}
vals := strings.Split(string(v), "$")
if len(vals) != 6 {
return nil, nil, ErrWrongHash
}

var version int
_, err = fmt.Sscanf(vals[2], "v=%d", &version)
if err != nil {
return nil, nil, err
}
if version != argon2.Version {
return nil, nil, ErrIncompatibleVersion
}

salt, err = base64.RawStdEncoding.DecodeString(vals[4])
if err != nil {
return nil, nil, err
}

key, err = base64.RawStdEncoding.DecodeString(vals[5])
if err != nil {
return nil, nil, err
}

return salt, key, nil
}
41 changes: 41 additions & 0 deletions internal/pass/pass_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package pass_test

import (
"github.com/stretchr/testify/require"
"go.amplifyedge.org/booty-v2/internal/pass"
"testing"
)

type hashAndSalt struct {
Unhashed string
Hash string
}

func TestSec(t *testing.T) {
t.Log("Given the need to produce hash and salt from plain text password, and verifies it thus.")
{
hs := hashAndSalt{
Unhashed: "MostSecurePassword",
}
t.Log("\tHandling hashing and updating hash and salt record.")
{
h, err := pass.GenHash(hs.Unhashed)
require.NoError(t, err)
hs.Hash = h
t.Logf("Successfully created hash: %s\t from plain text password: %s\n", hs.Hash, hs.Unhashed)
}
t.Log("\tHandling verification of hash and salt")
{
valid, err := pass.VerifyHash(hs.Unhashed, hs.Hash)
require.NoError(t, err)
require.True(t, valid)
t.Log("Successfully verified password.")

valid, err = pass.VerifyHash("RudolfTheRednoseReindeer", hs.Hash)
require.NoError(t, err)
require.False(t, valid)
t.Log("Successfully invalidates invalid password.")
}
}

}
Loading

0 comments on commit 90f0121

Please sign in to comment.