diff --git a/.gitignore b/.gitignore index 723ef36..25c3120 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -.idea \ No newline at end of file +.idea +bin \ No newline at end of file diff --git a/cmd/pwdmg/config/config.go b/cmd/pwdmg/config/config.go index 1378704..16a182e 100644 --- a/cmd/pwdmg/config/config.go +++ b/cmd/pwdmg/config/config.go @@ -6,7 +6,9 @@ import ( "github.com/atotto/clipboard" "github.com/swicherwich/pwdmg/internal/app/command/get" "github.com/swicherwich/pwdmg/internal/app/command/importpwd" + "github.com/swicherwich/pwdmg/internal/app/command/remove" "github.com/swicherwich/pwdmg/internal/app/command/save" + "github.com/swicherwich/pwdmg/internal/app/command/update" "github.com/urfave/cli/v2" "golang.org/x/crypto/ssh/terminal" "syscall" @@ -19,6 +21,8 @@ func PwdCommand() *cli.Command { Subcommands: []*cli.Command{ getCommand(), saveCommand(), + updateCommand(), + removeCommand(), importCommand(), }, } @@ -56,6 +60,30 @@ func getCommand() *cli.Command { } } +func removeCommand() *cli.Command { + return &cli.Command{ + Name: "remove", + Aliases: []string{"rm"}, + Usage: "pwdmg pwd remove ", + Description: "Remove domain and login record", + Action: func(c *cli.Context) error { + domain := c.Args().Get(0) + login := c.Args().Get(1) + + if domain == "" || login == "" { + return errors.New("domain or login cannot be empty") + } + + fmt.Println("Login removed") + + if err := remove.RemoveAccount(domain, login); err != nil { + return err + } + return nil + }, + } +} + func saveCommand() *cli.Command { return &cli.Command{ Name: "save", @@ -88,6 +116,40 @@ func saveCommand() *cli.Command { } } +func updateCommand() *cli.Command { + return &cli.Command{ + Name: "update", + Aliases: []string{"upd"}, + Usage: "pwdmg pwd update ", + Description: "Update password for provided domain and login account", + Action: func(c *cli.Context) error { + domain := c.Args().Get(0) + login := c.Args().Get(1) + + if domain == "" || login == "" { + return errors.New("domain or login cannot be empty") + } + + fmt.Print("Password: ") + pwdB, err := terminal.ReadPassword(syscall.Stdin) + pwd := string(pwdB) + + if err != nil { + return errors.New("error reading password") + } + + if pwd == "" { + return errors.New("empty pwd") + } + + if err := update.UpdatePassword(domain, login, pwd); err != nil { + return err + } + return nil + }, + } +} + func importCommand() *cli.Command { return &cli.Command{ Name: "import", diff --git a/cmd/pwdmg/main.go b/cmd/pwdmg/main.go index 2dea2e7..7884ff3 100644 --- a/cmd/pwdmg/main.go +++ b/cmd/pwdmg/main.go @@ -17,8 +17,6 @@ func main() { }, } - fmt.Println(app.Command("pwd").Command("get").Names()) - err := app.Run(os.Args) if err != nil { fmt.Println(err) diff --git a/internal/app/command/remove/remove.go b/internal/app/command/remove/remove.go new file mode 100644 index 0000000..574e13b --- /dev/null +++ b/internal/app/command/remove/remove.go @@ -0,0 +1,46 @@ +package remove + +import ( + "errors" + "fmt" + "github.com/swicherwich/pwdmg/internal/app/domain" + "github.com/swicherwich/pwdmg/internal/pkg/fsutil" + "github.com/swicherwich/pwdmg/internal/pkg/secutil" + "time" +) + +func RemoveAccount(d, acc string) error { + pwdmgDir, _ := fsutil.GetPwdmgDir() + + dHash := secutil.HashStr(d) + accHash := secutil.HashStr(acc) + dFile := fmt.Sprintf("%s/%s%s", pwdmgDir, dHash, ".json") + + if fsutil.FileExists(dFile) { + var d domain.Domain + + if err := fsutil.ReadData(dFile, &d); err != nil { + return err + } + + for i := range d.Accounts { + account := &d.Accounts[i] + if account.Login == accHash { + d.Metadata = domain.Metadata{ + Entries: d.Metadata.Entries - 1, + LastModified: time.Now().Format(time.DateTime), + } + + d.Accounts = append(d.Accounts[:i], d.Accounts[i+1:]...) + + if err := fsutil.PersistDataToFile(dFile, d); err != nil { + return err + } + + return nil + } + } + } + + return errors.New("no such login") +} diff --git a/internal/app/command/update/update.go b/internal/app/command/update/update.go new file mode 100644 index 0000000..e90f9fb --- /dev/null +++ b/internal/app/command/update/update.go @@ -0,0 +1,45 @@ +package update + +import ( + "errors" + "fmt" + "github.com/swicherwich/pwdmg/internal/app/domain" + "github.com/swicherwich/pwdmg/internal/pkg/fsutil" + "github.com/swicherwich/pwdmg/internal/pkg/secutil" + "time" +) + +func UpdatePassword(d, acc, pwd string) error { + pwdmgDir, _ := fsutil.GetPwdmgDir() + + dHash := secutil.HashStr(d) + accHash := secutil.HashStr(acc) + pwd64 := secutil.EncodeBase64(pwd) + dFile := fmt.Sprintf("%s/%s%s", pwdmgDir, dHash, ".json") + + if fsutil.FileExists(dFile) { + var d domain.Domain + + if err := fsutil.ReadData(dFile, &d); err != nil { + return err + } + + for i := range d.Accounts { + account := &d.Accounts[i] + if account.Login == accHash { + d.Metadata = domain.Metadata{ + LastModified: time.Now().Format(time.DateOnly), + } + account.Password = pwd64 + + if err := fsutil.PersistDataToFile(dFile, d); err != nil { + return err + } + + return nil + } + } + } + + return errors.New("no such login") +} diff --git a/internal/pkg/fsutil/fsutil.go b/internal/pkg/fsutil/fsutil.go index 7f1ca89..ce39937 100644 --- a/internal/pkg/fsutil/fsutil.go +++ b/internal/pkg/fsutil/fsutil.go @@ -30,7 +30,7 @@ func PersistDataToFile(dFile string, d any) error { fmt.Println("Error creating file:", err) return err } - defer file.Close() + defer func() { _ = file.Close() }() jData, err := json.MarshalIndent(d, "", " ") if err != nil { @@ -43,11 +43,6 @@ func PersistDataToFile(dFile string, d any) error { fmt.Println("Error writing to file:", err) return err } - _, err = fmt.Fprintf(file, "") - if err != nil { - fmt.Println("Error writing to file:", err) - return err - } return nil }