diff --git a/main.go b/main.go index 4defd89..72c7f73 100644 --- a/main.go +++ b/main.go @@ -46,7 +46,7 @@ func main() { cli.HelpMain() } - } else if argsCount == 4 { + } else if argsCount >= 4 { // declare entry field to perform target operation on @@ -84,19 +84,24 @@ func main() { } // TODO offline.EditEntry(targetLocation, field), exit after run case "add": - var field bool // indicates whether to add a password or note - field = field // TODO temporary to avoid unused variable error switch args[3] { case "password", "-p": - field = true - case "note", "-n": - field = false + if argsCount == 4 { + cli.AddPasswordEntry(targetLocation, true) + } else { + switch args[4] { + case "show", "-s": + cli.AddPasswordEntry(targetLocation, false) + default: + cli.AddPasswordEntry(targetLocation, true) + } + } + case "note", "-n": // TODO cli.AddNoteEntry(targetLocation) case "folder", "-f": offline.AddFolder(targetLocation) default: cli.HelpAdd() } - // TODO offline.AddEntry(targetLocation, field), exit after run case "gen": var field rune field = field // TODO temporary to avoid unused variable error diff --git a/src/cli/add.go b/src/cli/add.go new file mode 100644 index 0000000..8de1c5f --- /dev/null +++ b/src/cli/add.go @@ -0,0 +1,27 @@ +package cli + +import ( + "fmt" + "github.com/rwinkhart/MUTN/src/offline" + "os" +) + +// AddPasswordEntry prompts the user for all information relevant to a password entry and writes the entry to an encrypted file at targetLocation +func AddPasswordEntry(targetLocation string, hidePassword bool) { + _, isAccessible := offline.TargetIsFile(targetLocation, false, 0) + if isAccessible { + fmt.Println(offline.AnsiError + "Target location already exists" + offline.AnsiReset) + os.Exit(1) + } + + username := input("Username: ") + password := inputHidden("Password: ") + url := input("URL: ") + // TODO implement notes editor + notes := "" + + unencryptedEntry := []string{password, username, url, notes} + offline.WriteEntry(targetLocation, unencryptedEntry) + fmt.Println(ansiBold + "\nEntry Preview:" + offline.AnsiReset) + EntryReader(unencryptedEntry, hidePassword) +} diff --git a/src/cli/utilitiesMisc.go b/src/cli/utilitiesMisc.go new file mode 100644 index 0000000..41f53f0 --- /dev/null +++ b/src/cli/utilitiesMisc.go @@ -0,0 +1,24 @@ +package cli + +import ( + "fmt" + "golang.org/x/crypto/ssh/terminal" + "os" +) + +// input prompts the user for input and returns the input as a string +func input(prompt string) string { + fmt.Print("\n" + prompt) + var input string + fmt.Scanln(&input) + return input +} + +// inputHidden prompts the user for input and returns the input as a string, hiding the input from the terminal +func inputHidden(prompt string) string { + fmt.Print("\n" + prompt) + byteInput, _ := terminal.ReadPassword(int(os.Stdin.Fd())) + password := string(byteInput) + fmt.Println() + return password +} diff --git a/src/offline/add.go b/src/offline/add.go index eb103a1..bd220d2 100644 --- a/src/offline/add.go +++ b/src/offline/add.go @@ -5,6 +5,7 @@ import ( "os" ) +// AddFolder creates a new directory at targetLocation func AddFolder(targetLocation string) { // create the directory specified by targetLocation err := os.Mkdir(targetLocation, 0700) @@ -20,3 +21,13 @@ func AddFolder(targetLocation string) { // TODO If in online mode, create the directory on the server os.Exit(0) } + +// WriteEntry writes entryData to an encrypted file at targetLocation +func WriteEntry(targetLocation string, entryData []string) { + encryptedBytes := EncryptGPG(entryData) + err := os.WriteFile(targetLocation, encryptedBytes, 0600) + if err != nil { + fmt.Println(AnsiError + "Failed to write to file: " + err.Error() + AnsiReset) + os.Exit(1) + } +} diff --git a/src/offline/gpg.go b/src/offline/gpg.go index 14592ba..aa65163 100644 --- a/src/offline/gpg.go +++ b/src/offline/gpg.go @@ -24,3 +24,16 @@ func DecryptGPG(targetLocation string) []string { } return outputSlice } + +// EncryptGPG encrypts a slice of strings using GPG and returns the encrypted data as a byte slice +func EncryptGPG(input []string) []byte { + ReadConfig() + cmd := exec.Command("gpg", "-q", "-r", Config["gpgID"].(string), "-e") + writeToStdin(cmd, strings.Join(input, "\n")) + encryptedBytes, err := cmd.Output() + if err != nil { + fmt.Println(AnsiError + "Failed to encrypt data - ensure that your GPG key is valid and that you have a valid GPG ID set in libmutton.ini" + AnsiReset) + os.Exit(1) + } + return encryptedBytes +}