From 9606bf6af6019ec01a715d0ac4cc2d646805d417 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Tue, 5 Mar 2024 17:11:53 -0500 Subject: [PATCH] Implement notes editor (required rewrite of offline.ReadConfig) --- src/cli/add.go | 23 +++++++++++++++-------- src/cli/entryReader.go | 24 +++++++++++++++--------- src/cli/utilitiesMisc.go | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/cli/add.go b/src/cli/add.go index 8de1c5f..476cddb 100644 --- a/src/cli/add.go +++ b/src/cli/add.go @@ -6,21 +6,28 @@ import ( "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) { +// AddEntry creates a new entry at targetLocation by taking user input via CLI prompts +func AddEntry(targetLocation string, hidePassword bool, isNote 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 := "" + var unencryptedEntry []string + + if !isNote { + username := input("Username: ") + password := inputHidden("Password: ") + url := input("URL: ") + // TODO prompt for optional note + unencryptedEntry = []string{password, username, url} + } else { + note := newNote() + unencryptedEntry = append([]string{"", "", ""}, note...) + fmt.Println() + } - 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/entryReader.go b/src/cli/entryReader.go index 0fd3d0c..92efc9a 100644 --- a/src/cli/entryReader.go +++ b/src/cli/entryReader.go @@ -13,7 +13,7 @@ func EntryReader(decryptedEntry []string, hidePassword bool) { fmt.Println() // track if extended notes have been printed (to avoid printing an extra newline) - notesFlag := false + var notesFlag bool for i := range decryptedEntry { @@ -46,26 +46,32 @@ func EntryReader(decryptedEntry []string, hidePassword bool) { // if the fourth field (notes begin) is not empty, print it if decryptedEntry[3] != "" { fmt.Println(ansiDirectoryHeader + "Notes:" + offline.AnsiReset + "\n" + decryptedEntry[3]) - } - default: - // print extended notes line - fmt.Println(decryptedEntry[i]) - - // indicate that extended notes have been printed - if !notesFlag { + // indicate that the first notes line was printed (not empty) notesFlag = true } + default: + // print notes header if first notes line was blank + if !notesFlag { + fmt.Println(ansiDirectoryHeader + "Notes:" + offline.AnsiReset) + // indicate that notes have been printed + notesFlag = true + } + + // print extended notes line + fmt.Println(decryptedEntry[i]) } } - // print trailing newline if extended notes were printed + // print trailing newline if notes were printed if notesFlag { fmt.Println() } os.Exit(0) } +// EntryReaderShortcut is a shortcut for EntryReader that decrypts a GPG-encrypted file and prints the contents func EntryReaderShortcut(targetLocation string, hidePassword bool) { if isFile, _ := offline.TargetIsFile(targetLocation, true, 2); isFile { EntryReader(offline.DecryptGPG(targetLocation), hidePassword) } + // do not exit, as this is the job of EntryReader } diff --git a/src/cli/utilitiesMisc.go b/src/cli/utilitiesMisc.go index 41f53f0..2022bbf 100644 --- a/src/cli/utilitiesMisc.go +++ b/src/cli/utilitiesMisc.go @@ -1,9 +1,12 @@ package cli import ( + "bufio" "fmt" + "github.com/rwinkhart/MUTN/src/offline" "golang.org/x/crypto/ssh/terminal" "os" + "os/exec" ) // input prompts the user for input and returns the input as a string @@ -22,3 +25,34 @@ func inputHidden(prompt string) string { fmt.Println() return password } + +// newNote uses the user-specified text editor to create a new note and returns the note as a slice of strings +func newNote() []string { + tempFile := offline.CreateTempFile() + defer os.Remove(tempFile.Name()) + editor := offline.ReadConfig([]string{"textEditor"})[0] + cmd := exec.Command(editor, tempFile.Name()) + cmd.Stdout = os.Stdout + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + fmt.Println(offline.AnsiError + "Failed to write note with " + editor + offline.AnsiReset) + os.Exit(1) + } + + file, err := os.Open(tempFile.Name()) + if err != nil { + fmt.Println(offline.AnsiError + "Failed to open temporary file (\"" + tempFile.Name() + "\") " + err.Error() + offline.AnsiReset) + os.Exit(1) + } + defer file.Close() + + var note []string + scanner := bufio.NewScanner(file) + for scanner.Scan() { + note = append(note, scanner.Text()) + } + + return offline.RemoveTrailingEmptyStrings(note) +}