diff --git a/README.md b/README.md index 969988a..a0d8b07 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ After installing, please review the [usage guide](https://github.com/rwinkhart/M - [ ] Re-implement init menu - [ ] Implement tweak menu ### Release v0.4.0 -- [ ] Switch to fully-compliant Markdown (do not preserve new lines) +- [ ] Switch to fully compliant Markdown (do not preserve new lines) - [ ] Evaluate defaulting to building w/Bean over Glamour - [ ] Verify having Glamour in go.mod does not impact binary size/speed (drop it if it does) ### Release v0.5.0 diff --git a/go.mod b/go.mod index 1a10514..f3d3b34 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/Trojan2021/BEAN v0.0.0-20241210230804-8f294833b514 github.com/charmbracelet/glamour v0.7.0 github.com/rwinkhart/go-boilerplate v0.0.0-20250529185306-e2e64d7fa43b - github.com/rwinkhart/libmutton v0.3.2-0.20250529233550-74b8261bc88f + github.com/rwinkhart/libmutton v0.3.2-0.20250530020557-a1c47b06a13e golang.org/x/term v0.32.0 ) diff --git a/go.sum b/go.sum index 699ba3d..6f6e216 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/rwinkhart/go-boilerplate v0.0.0-20250529185306-e2e64d7fa43b h1:ENgsUl github.com/rwinkhart/go-boilerplate v0.0.0-20250529185306-e2e64d7fa43b/go.mod h1:cnzIF45I0FCOvE4YIB+26pLCUx2kWyY2llKYZruNaRY= github.com/rwinkhart/go-winio-easy-pipe-handles v0.0.0-20250407031321-96994a0e8410 h1:NhHwFM3Pgm6zRUfFKvi0p5ndjfFbVWsRwmmhyFlG4PE= github.com/rwinkhart/go-winio-easy-pipe-handles v0.0.0-20250407031321-96994a0e8410/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/rwinkhart/libmutton v0.3.2-0.20250529233550-74b8261bc88f h1:HL3z/oTAqssmILfA3Z0IAscK1sbxFp8/g9GnhHSNLSY= -github.com/rwinkhart/libmutton v0.3.2-0.20250529233550-74b8261bc88f/go.mod h1:uIz4AJcXW7ZHvvoPlLNWQofTBIbFa1UJ2JI6O+FSQ60= +github.com/rwinkhart/libmutton v0.3.2-0.20250530020557-a1c47b06a13e h1:b+4AzdZj5gEbIg8riqP5W4Y5LG7tIZTbiV69af846jI= +github.com/rwinkhart/libmutton v0.3.2-0.20250530020557-a1c47b06a13e/go.mod h1:uIz4AJcXW7ZHvvoPlLNWQofTBIbFa1UJ2JI6O+FSQ60= github.com/rwinkhart/peercred-mini v0.1.0 h1:TiS6u8cEWzW55S9X4iVpU72Iuy/NG6rMUJMtUEVEFLw= github.com/rwinkhart/peercred-mini v0.1.0/go.mod h1:+x4Mxc2veE+YePSOpcUasjimh7n799c1KraLuQwHR20= github.com/rwinkhart/rcw v0.2.0 h1:/rFgJ+20OSThipKAX5KPwW2xbPpgh1zl49THmEkkPis= diff --git a/mutn.go b/mutn.go index dbf71ef..38aa753 100644 --- a/mutn.go +++ b/mutn.go @@ -44,7 +44,10 @@ func main() { case "show", "-s": cli.EntryReaderDecrypt(targetLocation, false) case "copy": - core.CopyArgument(targetLocation, 0) + err := core.CopyArgument(targetLocation, 0) + if err != nil { + back.PrintError("Failed to copy passphrase to clipboard: "+err.Error(), global.ErrorClipboard, true) + } case "edit": cli.EditEntryField(targetLocation, true, 0) case "gen": @@ -52,7 +55,10 @@ func main() { case "add": cli.AddEntry(targetLocation, true, 0) case "shear": - syncclient.ShearRemoteFromClient(args[1], false) // pass the incomplete path as the server and all clients (reading from the deletions directory) will have a different home directory + err := syncclient.ShearRemoteFromClient(args[1], false) // pass the incomplete path as the server and all clients (reading from the deletions directory) will have a different home directory + if err != nil { + back.PrintError("Failed to shear target: "+err.Error(), back.ErrorWrite, true) + } default: cli.HelpMain() } @@ -88,7 +94,10 @@ func main() { default: cli.HelpCopy() } - core.CopyArgument(targetLocation, field) + err := core.CopyArgument(targetLocation, field) + if err != nil { + back.PrintError("Failed to copy field to clipboard: "+err.Error(), global.ErrorClipboard, true) + } case "edit": var field int // indicates which (numbered) field to edit switch args[3] { @@ -151,7 +160,10 @@ func main() { case "note", "-n": cli.AddEntry(targetLocation, true, 2) case "folder", "-f": - syncclient.AddFolderRemoteFromClient(args[1], false) // pass the incomplete path as the server will have a different home directory + err := syncclient.AddFolderRemoteFromClient(args[1], false) // pass the incomplete path as the server will have a different home directory + if err != nil { + back.PrintError("Failed to add folder: "+err.Error(), back.ErrorWrite, true) + } default: cli.HelpAdd() } @@ -164,13 +176,18 @@ func main() { } else { switch args[1] { case "clipclear": - core.ClipClearArgument() + err := core.ClipClearArgument() + if err != nil { + back.PrintError("Failure occurred in clipboard clearing process: "+err.Error(), global.ErrorClipboard, true) + } case "startrcwd": crypt.RCWDArgument() case "sync": - syncclient.RunJob(true, false) + _, err := syncclient.RunJob(true, false) + if err != nil { + back.PrintError("Failed to sync entries: "+err.Error(), global.ErrorSyncProcess, true) + } case "init": - const fallbackEditor = "vi" // TODO "edit" for Windows var rcwPass []byte for { // get master passphrase rcwPass = front.InputHidden("Master passphrase:") @@ -181,7 +198,7 @@ func main() { break } err := core.LibmuttonInit(front.Input, - [][3]string{{"MUTN", "textEditor", cmp.Or(front.Input("Text editor (leave blank for $EDITOR, falls back to \""+fallbackEditor+"\"):"), os.Getenv("EDITOR"), fallbackEditor)}}, + [][3]string{{"MUTN", "textEditor", cmp.Or(front.Input("Text editor (leave blank for $EDITOR, falls back to \""+cli.FallbackEditor+"\"):"), os.Getenv("EDITOR"), cli.FallbackEditor)}}, rcwPass, false) if err != nil { back.PrintError("Initialization failed: "+err.Error(), 0, true) diff --git a/src/cli/add.go b/src/cli/add.go index 13cb81b..0769fe8 100644 --- a/src/cli/add.go +++ b/src/cli/add.go @@ -1,6 +1,7 @@ package cli import ( + "github.com/rwinkhart/go-boilerplate/back" "github.com/rwinkhart/go-boilerplate/front" "github.com/rwinkhart/libmutton/core" ) @@ -9,7 +10,10 @@ import ( // Requires: entryType (0 = standard password entry, 1 = auto-generated password entry, 2 = note-only entry). func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) { // ensure targetLocation is valid - core.EntryAddPrecheck(targetLocation) + _, err := core.EntryAddPrecheck(targetLocation) + if err != nil { + back.PrintError("Failed to add entry: "+err.Error(), back.ErrorWrite, true) + } var unencryptedEntry []string diff --git a/src/cli/edit.go b/src/cli/edit.go index 9e0db88..201c2e5 100644 --- a/src/cli/edit.go +++ b/src/cli/edit.go @@ -17,7 +17,10 @@ import ( func RenameCli(oldLocationIncomplete string) { // prompt user for new location and rename newLocationIncomplete := front.Input("New location:") - syncclient.RenameRemoteFromClient(oldLocationIncomplete, newLocationIncomplete, false) + err := syncclient.RenameRemoteFromClient(oldLocationIncomplete, newLocationIncomplete, false) + if err != nil { + back.PrintError("Failed to rename entry: "+err.Error(), back.ErrorWrite, true) + } // exit is done from sync.RenameRemoteFromClient } @@ -25,7 +28,10 @@ func RenameCli(oldLocationIncomplete string) { // EditEntryField edits a field of an entry at targetLocation (user input). func EditEntryField(targetLocation string, hideSecrets bool, field int) { // fetch old entry data (with all required lines present) - unencryptedEntry := core.GetOldEntryData(targetLocation, field) + unencryptedEntry, err := core.GetOldEntryData(targetLocation, field) + if err != nil { + back.PrintError("Failed to fetch entry data: "+err.Error(), back.ErrorRead, true) + } // edit the field switch field { @@ -57,7 +63,10 @@ func EditEntryField(targetLocation string, hideSecrets bool, field int) { // GenUpdate generates a new password for an entry at targetLocation (user input). func GenUpdate(targetLocation string, hideSecrets bool) { // fetch old entry data - unencryptedEntry := core.GetOldEntryData(targetLocation, 0) + unencryptedEntry, err := core.GetOldEntryData(targetLocation, 0) + if err != nil { + back.PrintError("Failed to fetch entry data: "+err.Error(), back.ErrorRead, true) + } // generate a new password unencryptedEntry[0] = inputPasswordGen() diff --git a/src/cli/entryList.go b/src/cli/entryList.go index a2bcf9c..2354a81 100644 --- a/src/cli/entryList.go +++ b/src/cli/entryList.go @@ -79,7 +79,10 @@ func printFileEntry(entry string, lastSlash, charCounter, indent int, colorAlter // EntryListGen generates and displays the full libmutton entry list. func EntryListGen() { - fileList, dirList := synccommon.WalkEntryDir() + fileList, dirList, err := synccommon.WalkEntryDir() + if err != nil { + back.PrintError("Failed to generate entry list: "+err.Error(), back.ErrorRead, true) + } // print header bar w/total entry count fmt.Print("\n"+ansiBlackOnWhite, len(fileList), " libmutton entries:"+back.AnsiReset) diff --git a/src/cli/entryReader.go b/src/cli/entryReader.go index 40088d3..0c2ed27 100644 --- a/src/cli/entryReader.go +++ b/src/cli/entryReader.go @@ -6,6 +6,7 @@ import ( "github.com/rwinkhart/go-boilerplate/back" "github.com/rwinkhart/libmutton/crypt" + "github.com/rwinkhart/libmutton/global" "github.com/rwinkhart/libmutton/syncclient" ) @@ -65,7 +66,10 @@ fieldLoop: } if syncEnabled { - syncclient.RunJob(false, false) + _, err := syncclient.RunJob(false, false) + if err != nil { + back.PrintError("Failed to sync entries: "+err.Error(), global.ErrorSyncProcess, true) + } } os.Exit(0) @@ -74,7 +78,11 @@ fieldLoop: // EntryReaderDecrypt is a wrapper for EntryReader that first decrypts an RCW-wrapped file before sending it to EntryReader. func EntryReaderDecrypt(targetLocation string, hideSecrets bool) { if isFile, _ := back.TargetIsFile(targetLocation, true, 2); isFile { - EntryReader(crypt.DecryptFileToSlice(targetLocation), hideSecrets, false) // never sync if decrypting straight to EntryReader, as this means the entry could not have been modified + decBytes, err := crypt.DecryptFileToSlice(targetLocation) + if err != nil { + back.PrintError("Failed to decrypt entry: "+err.Error(), global.ErrorDecryption, true) + } + EntryReader(decBytes, hideSecrets, false) // never sync if decrypting straight to EntryReader, as this means the entry could not have been modified } // do not exit, as this is the job of EntryReader } diff --git a/src/cli/initUNIX.go b/src/cli/initUNIX.go index 0712ed1..360b390 100644 --- a/src/cli/initUNIX.go +++ b/src/cli/initUNIX.go @@ -2,4 +2,4 @@ package cli -const fallbackEditor = "vi" // vi is pre-installed on most UNIX-like systems +const FallbackEditor = "vi" // vi is pre-installed on most UNIX-like systems diff --git a/src/cli/initWIN.go b/src/cli/initWIN.go index 5b49d2c..486c679 100644 --- a/src/cli/initWIN.go +++ b/src/cli/initWIN.go @@ -2,4 +2,4 @@ package cli -const fallbackEditor = "edit" // "edit" is the Microsoft-developed CLI text editor +const FallbackEditor = "edit" // "edit" is the Microsoft-developed CLI text editor diff --git a/src/cli/utilitiesMisc.go b/src/cli/utilitiesMisc.go index 1d94935..2a71b4a 100644 --- a/src/cli/utilitiesMisc.go +++ b/src/cli/utilitiesMisc.go @@ -31,7 +31,10 @@ func inputPasswordGen() string { func writeEntryCLI(targetLocation string, unencryptedEntry []string, hideSecrets bool) { if core.EntryIsNotEmpty(unencryptedEntry) { // write the entry to the target location - core.WriteEntry(targetLocation, []byte(strings.Join(unencryptedEntry, "\n"))) + err := core.WriteEntry(targetLocation, []byte(strings.Join(unencryptedEntry, "\n"))) + if err != nil { + back.PrintError("Failed to write entry: "+err.Error(), back.ErrorWrite, true) + } // preview the entry fmt.Println(back.AnsiBold + "\nEntry Preview:" + back.AnsiReset) EntryReader(unencryptedEntry, hideSecrets, true)