From 0e5c6715807833e50b5db681a8ce86afe31d99b0 Mon Sep 17 00:00:00 2001 From: teru Date: Sun, 14 Aug 2016 07:55:14 +0900 Subject: [PATCH] Implement subcommands: `userpasswd`, `usercheckpw` --- cmd/mailfull/command/usercheckpw.go | 100 +++++++++++++++++++++ cmd/mailfull/command/userpasswd.go | 131 ++++++++++++++++++++++++++++ cmd/mailfull/main.go | 8 ++ 3 files changed, 239 insertions(+) create mode 100644 cmd/mailfull/command/usercheckpw.go create mode 100644 cmd/mailfull/command/userpasswd.go diff --git a/cmd/mailfull/command/usercheckpw.go b/cmd/mailfull/command/usercheckpw.go new file mode 100644 index 0000000..6fd8e37 --- /dev/null +++ b/cmd/mailfull/command/usercheckpw.go @@ -0,0 +1,100 @@ +package command + +import ( + "fmt" + "strings" + + "github.com/directorz/mailfull-go" + "github.com/jsimonetti/pwscheme/ssha" +) + +// UserCheckPwCommand represents a UserCheckPwCommand. +type UserCheckPwCommand struct { + Meta +} + +// Synopsis returns a one-line synopsis. +func (c *UserCheckPwCommand) Synopsis() string { + return "Check user's password." +} + +// Help returns long-form help text. +func (c *UserCheckPwCommand) Help() string { + txt := fmt.Sprintf(` +Usage: + %s %s address [password] + +Description: + %s + +Required Args: + address + The email address that you want to check the password. + +Optional Args: + password + Specify the password instead of your typing. + This option is not recommended because the password will be visible in your shell history. +`, + c.CmdName, c.SubCmdName, + c.Synopsis()) + + return txt[1:] +} + +// Run runs the command and returns the exit status. +func (c *UserCheckPwCommand) Run(args []string) int { + if len(args) != 1 && len(args) != 2 { + fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help()) + return 1 + } + + address := args[0] + words := strings.Split(address, "@") + if len(words) != 2 { + fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help()) + return 1 + } + + userName := words[0] + domainName := words[1] + + rawPassword := "" + if len(args) == 2 { + rawPassword = args[1] + } + + repo, err := mailfull.OpenRepository(".") + if err != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err) + return 1 + } + + user, err := repo.User(domainName, userName) + if err != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err) + return 1 + } + if user == nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", mailfull.ErrUserNotExist) + return 1 + } + + if len(args) != 2 { + input, err1 := c.UI.AskSecret(fmt.Sprintf("Enter password for %s:", address)) + if err1 != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err1) + return 1 + } + + rawPassword = input + } + + if ok, _ := ssha.Validate(rawPassword, user.HashedPassword()); !ok { + fmt.Fprintf(c.UI.Writer, "The password you entered is incorrect.\n") + return 1 + } + + fmt.Fprintf(c.UI.Writer, "The password you entered is correct.\n") + return 0 +} diff --git a/cmd/mailfull/command/userpasswd.go b/cmd/mailfull/command/userpasswd.go new file mode 100644 index 0000000..5f5be57 --- /dev/null +++ b/cmd/mailfull/command/userpasswd.go @@ -0,0 +1,131 @@ +package command + +import ( + "fmt" + "strings" + + "github.com/directorz/mailfull-go" + "github.com/jsimonetti/pwscheme/ssha" +) + +// UserPasswdCommand represents a UserPasswdCommand. +type UserPasswdCommand struct { + Meta +} + +// Synopsis returns a one-line synopsis. +func (c *UserPasswdCommand) Synopsis() string { + return "Update user's password." +} + +// Help returns long-form help text. +func (c *UserPasswdCommand) Help() string { + txt := fmt.Sprintf(` +Usage: + %s %s address [password] + +Description: + %s + +Required Args: + address + The email address that you want to update the password. + +Optional Args: + password + Specify the password instead of your typing. + This option is not recommended because the password will be visible in your shell history. +`, + c.CmdName, c.SubCmdName, + c.Synopsis()) + + return txt[1:] +} + +// Run runs the command and returns the exit status. +func (c *UserPasswdCommand) Run(args []string) int { + if len(args) != 1 && len(args) != 2 { + fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help()) + return 1 + } + + address := args[0] + words := strings.Split(address, "@") + if len(words) != 2 { + fmt.Fprintf(c.UI.ErrorWriter, "%v\n", c.Help()) + return 1 + } + + userName := words[0] + domainName := words[1] + + rawPassword := "" + if len(args) == 2 { + rawPassword = args[1] + } + + repo, err := mailfull.OpenRepository(".") + if err != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err) + return 1 + } + + user, err := repo.User(domainName, userName) + if err != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err) + return 1 + } + if user == nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", mailfull.ErrUserNotExist) + return 1 + } + + if len(args) != 2 { + input1, err1 := c.UI.AskSecret(fmt.Sprintf("Enter new password for %s:", address)) + if err1 != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err1) + return 1 + } + input2, err2 := c.UI.AskSecret("Retype new password:") + if err2 != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err2) + return 1 + } + if input1 != input2 { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] inputs do not match.\n") + return 1 + } + rawPassword = input1 + } + + hashedPassword := mailfull.NeverMatchHashedPassword + if rawPassword != "" { + str, errHash := ssha.Generate(rawPassword, 4) + if errHash != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", errHash) + return 1 + } + hashedPassword = str + } + + user.SetHashedPassword(hashedPassword) + + if err := repo.UserUpdate(domainName, user); err != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err) + return 1 + } + + mailData, err := repo.MailData() + if err != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err) + return 1 + } + + err = repo.GenerateDatabases(mailData) + if err != nil { + fmt.Fprintf(c.UI.ErrorWriter, "[ERR] %v\n", err) + return 1 + } + + return 0 +} diff --git a/cmd/mailfull/main.go b/cmd/mailfull/main.go index 5f61a5d..5d2cad0 100644 --- a/cmd/mailfull/main.go +++ b/cmd/mailfull/main.go @@ -79,6 +79,14 @@ func main() { meta.SubCmdName = c.Subcommand() return &command.UserDelCommand{Meta: meta}, nil }, + "userpasswd": func() (cli.Command, error) { + meta.SubCmdName = c.Subcommand() + return &command.UserPasswdCommand{Meta: meta}, nil + }, + "usercheckpw": func() (cli.Command, error) { + meta.SubCmdName = c.Subcommand() + return &command.UserCheckPwCommand{Meta: meta}, nil + }, "commit": func() (cli.Command, error) { meta.SubCmdName = c.Subcommand() return &command.CommitCommand{Meta: meta}, nil