diff --git a/cmd/panelcli/cli.go b/cmd/panelcli/cli.go index 8762a4b..55b23e6 100644 --- a/cmd/panelcli/cli.go +++ b/cmd/panelcli/cli.go @@ -1,12 +1,14 @@ package main import ( + "flag" "fmt" "io" "os" - "git.lattuga.net/boyska/feedpanel/db" + paneldb "git.lattuga.net/boyska/feedpanel/db" "github.com/go-pg/pg" + "github.com/howeyc/gopass" ) func getDB() paneldb.DB { @@ -19,9 +21,9 @@ func getDB() paneldb.DB { return db } -type commandFunc func() error +type commandFunc func([]string) error -func cmdSetup() error { +func cmdSetup(_args []string) error { db := getDB() err := db.Setup() if err != nil { @@ -33,8 +35,56 @@ func cmdSetup() error { return nil } -var cmdMap map[string]commandFunc = map[string]commandFunc{ - "setup": cmdSetup, +func askPassword() (string, error) { + fmt.Print("New password: ") + pass, err := gopass.GetPasswd() + if err != nil { + return "", err + } + fmt.Print("Retype new password: ") + pass2, err := gopass.GetPasswd() + if err != nil { + return "", err + } + if string(pass) != string(pass2) { + return "", fmt.Errorf("Passwords differ") + } + return string(pass), nil +} + +func cmdAddUser(args []string) error { + flagset := flag.NewFlagSet(args[0], flag.ExitOnError) + password := flagset.String("password", "", "set password from command line; INSECURE!") + flagset.Parse(args[1:]) + if len(flagset.Args()) < 2 { + fmt.Fprintf(os.Stderr, "Usage: %s [options] USER EMAIL\n", args[0]) + flagset.PrintDefaults() + os.Exit(2) + } + user := flagset.Args()[0] + email := flagset.Args()[1] + if *password == "" { + pass, err := askPassword() + if err != nil { + fmt.Fprintln(os.Stderr, "Error:", err) + os.Exit(1) + } + *password = string(pass) + } + db := getDB() + err := db.UserAdd(user, email, *password) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + fmt.Printf("Success: user %s added\n", user) + os.Exit(0) + return nil +} + +var cmdMap = map[string]commandFunc{ + "setup": cmdSetup, + "adduser": cmdAddUser, } func usage(w io.Writer) { @@ -46,19 +96,21 @@ func usage(w io.Writer) { } func main() { - if len(os.Args) < 2 { + flag.Parse() + fmt.Println(flag.Args()) + if len(flag.Args()) < 1 { fmt.Fprintln(os.Stderr, "Not enough arguments!") usage(os.Stderr) os.Exit(2) } - cmdName := os.Args[1] + cmdName := flag.Args()[0] cmdFunc, ok := cmdMap[cmdName] if !ok { - fmt.Fprintln(os.Stderr, "Invalid command") + fmt.Fprintf(os.Stderr, "Invalid command `%s`\n", cmdName) usage(os.Stderr) os.Exit(2) } - err := cmdFunc() + err := cmdFunc(flag.Args()) if err != nil { fmt.Fprintln(os.Stderr, "Error") fmt.Fprintln(os.Stderr, err) diff --git a/db/db.go b/db/db.go index b6ce65c..2d00a8e 100644 --- a/db/db.go +++ b/db/db.go @@ -5,6 +5,7 @@ import ( "github.com/go-pg/pg" "github.com/pkg/errors" + "golang.org/x/crypto/bcrypt" ) type DB struct { @@ -32,12 +33,16 @@ func (db *DB) Setup() error { return nil } -func (db *DB) UserAdd(username, email, pwhash string) error { - stmt, err := db.PgDB.Prepare("INSERT INTO users.users VALUES ($1, $2, $3)") +func (db *DB) UserAdd(username, email, pwd string) error { + stmt, err := db.PgDB.Prepare("INSERT INTO users.users (username, email, password) VALUES ($1, $2, $3)") if err != nil { panic("Bad statement in UserAdd") } - _, err = stmt.Exec(username, email, pwhash) + pwhash, err := bcrypt.GenerateFromPassword([]byte(pwd), bcrypt.DefaultCost) + if err != nil { + return errors.Wrap(err, "Error deriving password (with bcrypt)") + } + _, err = stmt.Exec(username, email, string(pwhash)) if err != nil { return errors.Wrapf(err, "Error adding user `%s`", email) } diff --git a/go.mod b/go.mod index 0e23214..e5cc2b0 100644 --- a/go.mod +++ b/go.mod @@ -2,11 +2,13 @@ module git.lattuga.net/boyska/feedpanel require ( github.com/go-pg/pg v6.15.0+incompatible + github.com/howeyc/gopass v0.0.0-20170109162249-bf9dde6d0d2c github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect github.com/kr/pretty v0.1.0 // indirect github.com/onsi/gomega v1.4.2 // indirect github.com/pkg/errors v0.8.0 github.com/vmihailenco/sasl v0.0.0-20180913092844-58bfd2104008 // indirect + golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect mellium.im/sasl v0.2.1 // indirect )