From a23ae4a4b93bd96d568eb9b620104f766ca52a66 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Thu, 8 Aug 2024 17:24:48 -0400 Subject: [PATCH] Switch to dependence on github.com/rwinkhart/libmutton --- go.mod | 11 ++++---- go.sum | 2 ++ libmuttonserver.go | 20 +++++++------- mutn.go | 18 ++++++------ src/cli/add.go | 10 +++---- src/cli/edit.go | 22 +++++++-------- src/cli/entryList.go | 15 +++++----- src/cli/entryReader.go | 22 +++++++-------- src/cli/init.go | 28 +++++++++---------- src/cli/printInfo.go | 60 ++++++++++++++++++++-------------------- src/cli/utilitiesMisc.go | 16 +++++------ 11 files changed, 114 insertions(+), 110 deletions(-) diff --git a/go.mod b/go.mod index ef75ba6..394cffd 100644 --- a/go.mod +++ b/go.mod @@ -4,12 +4,8 @@ go 1.22.6 require ( github.com/charmbracelet/glamour v0.7.0 - github.com/fortis/go-steam-totp v0.0.0-20171114202746-18e928674727 - github.com/pkg/sftp v1.13.6 - github.com/pquerna/otp v1.4.1-0.20231130234153-3357de7c0481 - golang.org/x/crypto v0.26.0 + github.com/rwinkhart/libmutton v0.0.0-20240808205713-d82188f56655 golang.org/x/term v0.23.0 - gopkg.in/ini.v1 v1.67.0 ) require ( @@ -18,6 +14,7 @@ require ( github.com/aymerick/douceur v0.2.0 // indirect github.com/boombuler/barcode v1.0.2 // indirect github.com/dlclark/regexp2 v1.11.4 // indirect + github.com/fortis/go-steam-totp v0.0.0-20171114202746-18e928674727 // indirect github.com/gorilla/css v1.0.1 // indirect github.com/kr/fs v0.1.0 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -27,10 +24,14 @@ require ( github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.2 // indirect github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/pkg/sftp v1.13.6 // indirect + github.com/pquerna/otp v1.4.1-0.20231130234153-3357de7c0481 // indirect github.com/rivo/uniseg v0.4.7 // indirect github.com/stretchr/testify v1.8.4 // indirect github.com/yuin/goldmark v1.7.4 // indirect github.com/yuin/goldmark-emoji v1.0.3 // indirect + golang.org/x/crypto v0.26.0 // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sys v0.23.0 // indirect + gopkg.in/ini.v1 v1.67.0 // indirect ) diff --git a/go.sum b/go.sum index 3ce42b3..f2006cb 100644 --- a/go.sum +++ b/go.sum @@ -52,6 +52,8 @@ github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rwinkhart/libmutton v0.0.0-20240808205713-d82188f56655 h1:nlvJc8lkwZcuIWsiIl1qh6g7A/oCLnRz7mnR7oEdlyA= +github.com/rwinkhart/libmutton v0.0.0-20240808205713-d82188f56655/go.mod h1:treJ/J2D6+LuDQQ435Jg3fsXRHlBnoKlMYExo3VzUKc= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= diff --git a/libmuttonserver.go b/libmuttonserver.go index 6f2c313..235ce0e 100644 --- a/libmuttonserver.go +++ b/libmuttonserver.go @@ -7,9 +7,9 @@ import ( "strconv" "strings" - "github.com/rwinkhart/MUTN/src/backend" "github.com/rwinkhart/MUTN/src/cli" - "github.com/rwinkhart/MUTN/src/sync" + "github.com/rwinkhart/libmutton/core" + "github.com/rwinkhart/libmutton/sync" ) func main() { @@ -55,13 +55,13 @@ func main() { case "register": // register a new device ID // stdin[0] is expected to be the device ID - _, _ = os.Create(backend.ConfigDir + backend.PathSeparator + "devices" + backend.PathSeparator + stdin[0]) // error ignored; failure unlikely to occur if init was successful; "register" is not a user-facing argument and thus the error would not be visible + _, _ = os.Create(core.ConfigDir + core.PathSeparator + "devices" + core.PathSeparator + stdin[0]) // error ignored; failure unlikely to occur if init was successful; "register" is not a user-facing argument and thus the error would not be visible // print EntryRoot and bool indicating OS type to stdout for client to store in config - fmt.Print(backend.EntryRoot + sync.FSSpace + strconv.FormatBool(backend.IsWindows)) + fmt.Print(core.EntryRoot + sync.FSSpace + strconv.FormatBool(core.IsWindows)) case "init": // create the necessary directories for libmuttonserver to function - backend.DirInit(false) - _ = os.MkdirAll(backend.ConfigDir+backend.PathSeparator+"deletions", 0700) // error ignored; failure would have occurred by this point in backend.DirInit + core.DirInit(false) + _ = os.MkdirAll(core.ConfigDir+core.PathSeparator+"deletions", 0700) // error ignored; failure would have occurred by this point in core.DirInit fmt.Println("libmuttonserver directories initialized") case "version": versionServer() @@ -71,13 +71,13 @@ func main() { } func helpServer() { - fmt.Print(cli.AnsiBold + "\nlibmuttonserver | Copyright (c) 2024 Randall Winkhart\n" + backend.AnsiReset + ` + fmt.Print(cli.AnsiBold + "\nlibmuttonserver | Copyright (c) 2024 Randall Winkhart\n" + core.AnsiReset + ` This software exists under the MIT license; you may redistribute it under certain conditions. This program comes with absolutely no warranty; type "libmuttonserver version" for details. -` + cli.AnsiBold + "Usage:" + backend.AnsiReset + ` libmuttonserver +` + cli.AnsiBold + "Usage:" + core.AnsiReset + ` libmuttonserver -` + cli.AnsiBold + "Arguments (user):" + backend.AnsiReset + ` +` + cli.AnsiBold + "Arguments (user):" + core.AnsiReset + ` help Bring up this menu version Display version and license information init Create the necessary directories for libmuttonserver to function` + "\n\n") @@ -86,7 +86,7 @@ This program comes with absolutely no warranty; type "libmuttonserver version" f func versionServer() { cli.MITLicense() - fmt.Print(cli.AnsiBold + "\n\n libmuttonserver" + backend.AnsiReset + " Version " + backend.LibmuttonVersion + ` + fmt.Print(cli.AnsiBold + "\n\n libmuttonserver" + core.AnsiReset + " Version " + core.LibmuttonVersion + ` Copyright (c) 2024 Randall Winkhart` + "\n\n") } diff --git a/mutn.go b/mutn.go index d9d40dc..b15b607 100644 --- a/mutn.go +++ b/mutn.go @@ -5,9 +5,9 @@ import ( "os" "strings" - "github.com/rwinkhart/MUTN/src/backend" "github.com/rwinkhart/MUTN/src/cli" - "github.com/rwinkhart/MUTN/src/sync" + "github.com/rwinkhart/libmutton/core" + "github.com/rwinkhart/libmutton/sync" ) func main() { @@ -25,7 +25,7 @@ func main() { if strings.HasPrefix(args[1], "/") { // store location of target entry - targetLocation := backend.TargetLocationFormat(args[1]) + targetLocation := core.TargetLocationFormat(args[1]) // entry reader shortcut (if no other arguments are supplied) if argsCount == 2 { @@ -38,7 +38,7 @@ func main() { case "show", "-s": cli.EntryReaderDecrypt(targetLocation, false) case "copy": - backend.CopyArgument(args[0], targetLocation, 0) + core.CopyArgument(args[0], targetLocation, 0) case "edit": cli.EditEntryField(targetLocation, true, 0) case "gen": @@ -82,7 +82,7 @@ func main() { default: cli.HelpCopy() } - backend.CopyArgument(args[0], targetLocation, field) + core.CopyArgument(args[0], targetLocation, field) case "edit": var field int // indicates which (numbered) field to edit switch args[3] { @@ -97,8 +97,8 @@ func main() { case "note", "-n": field = 4 case "rename", "-r": - backend.TargetIsFile(targetLocation, true, 0) // ensure location exists before prompting for new location - cli.RenameCli(args[1]) // pass the incomplete path as the server and all clients (reading from the deletions directory) will have a different home directory + core.TargetIsFile(targetLocation, true, 0) // ensure location exists before prompting for new location + cli.RenameCli(args[1]) // pass the incomplete path as the server and all clients (reading from the deletions directory) will have a different home directory default: cli.HelpEdit() } @@ -158,13 +158,13 @@ func main() { } else { switch args[1] { case "clipclear": - backend.ClipClearArgument() + core.ClipClearArgument() case "sync": sync.RunJob(true) case "init": cli.TempInitCli() case "tweak": - fmt.Println(backend.AnsiError + "\"tweak\" is not yet implemented" + backend.AnsiReset) + fmt.Println(core.AnsiError + "\"tweak\" is not yet implemented" + core.AnsiReset) os.Exit(0) case "copy": cli.HelpCopy() diff --git a/src/cli/add.go b/src/cli/add.go index 7e6370e..62ebcf6 100644 --- a/src/cli/add.go +++ b/src/cli/add.go @@ -5,21 +5,21 @@ import ( "os" "strings" - "github.com/rwinkhart/MUTN/src/backend" + "github.com/rwinkhart/libmutton/core" ) // AddEntry creates a new entry at targetLocation by taking user input via CLI prompts // entryType: 0 = standard (password), 1 = auto-generated password, 2 = note func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) { // ensure target location does not already exist - _, isAccessible := backend.TargetIsFile(targetLocation, false, 0) + _, isAccessible := core.TargetIsFile(targetLocation, false, 0) if isAccessible { - fmt.Println(backend.AnsiError + "Target location already exists" + backend.AnsiReset) + fmt.Println(core.AnsiError + "Target location already exists" + core.AnsiReset) os.Exit(1) } // ensure target containing directory exists and is a directory (not a file) - backend.TargetIsFile(targetLocation[:strings.LastIndex(targetLocation, "/")], true, 1) + core.TargetIsFile(targetLocation[:strings.LastIndex(targetLocation, "/")], true, 1) var unencryptedEntry []string @@ -31,7 +31,7 @@ func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) { if entryType == 0 { password = inputHidden("Password:") } else { - password = backend.StringGen(inputInt("Password length:", -1), inputBinary("Generate a complex (special characters) password?"), 0.2, false) + password = core.StringGen(inputInt("Password length:", -1), inputBinary("Generate a complex (special characters) password?"), 0.2, false) } totp := inputHidden("TOTP secret:") diff --git a/src/cli/edit.go b/src/cli/edit.go index 35ec0fc..ca08e2b 100644 --- a/src/cli/edit.go +++ b/src/cli/edit.go @@ -8,8 +8,8 @@ import ( "reflect" "strings" - "github.com/rwinkhart/MUTN/src/backend" - "github.com/rwinkhart/MUTN/src/sync" + "github.com/rwinkhart/libmutton/core" + "github.com/rwinkhart/libmutton/sync" ) // RenameCli renames an entry at oldLocationIncomplete to a new location (user input) on both the client and the server @@ -24,7 +24,7 @@ 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 := backend.GetOldEntryData(targetLocation, field) + unencryptedEntry := core.GetOldEntryData(targetLocation, field) // edit the field switch field { @@ -44,7 +44,7 @@ func EditEntryField(targetLocation string, hideSecrets bool, field int) { // edit the note editedNote, noteEdited := editNote(noteData) if !noteEdited { // exit early if the note was not edited - fmt.Println(backend.AnsiError + "Entry is unchanged" + backend.AnsiReset) + fmt.Println(core.AnsiError + "Entry is unchanged" + core.AnsiReset) os.Exit(1) } unencryptedEntry = append(nonNoteData, editedNote...) @@ -57,10 +57,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 := backend.GetOldEntryData(targetLocation, 0) + unencryptedEntry := core.GetOldEntryData(targetLocation, 0) // generate a new password - unencryptedEntry[0] = backend.StringGen(inputInt("Password length:", -1), inputBinary("Generate a complex (special characters) password?"), 0.2, false) + unencryptedEntry[0] = core.StringGen(inputInt("Password length:", -1), inputBinary("Generate a complex (special characters) password?"), 0.2, false) // write and preview the modified entry writeEntryCLI(targetLocation, unencryptedEntry, hideSecrets, false) @@ -69,13 +69,13 @@ func GenUpdate(targetLocation string, hideSecrets bool) { // editNote uses the user-specified text editor to edit an existing note (or create a new one if baseNote is empty) // returns the edited note and a boolean indicating whether the note was edited func editNote(baseNote []string) ([]string, bool) { - tempFile := backend.CreateTempFile() + tempFile := core.CreateTempFile() defer func(name string) { _ = os.Remove(name) // error ignored; if the file could be created, it can probably be removed }(tempFile.Name()) // fetch the user's text editor - editor := backend.ParseConfig([][2]string{{"MUTN", "textEditor"}}, "")[0] + editor := core.ParseConfig([][2]string{{"MUTN", "textEditor"}}, "")[0] // write baseNote to tempFile (if it is not empty) if len(baseNote) > 0 { @@ -94,13 +94,13 @@ func editNote(baseNote []string) ([]string, bool) { cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { - panic(backend.AnsiError + "Failed to write note with " + editor + backend.AnsiReset) // panic is used to ensure the tempFile is removed, as per the defer statement + panic(core.AnsiError + "Failed to write note with " + editor + core.AnsiReset) // panic is used to ensure the tempFile is removed, as per the defer statement } // open the tempFile for reading tempFile, err = os.Open(tempFile.Name()) if err != nil { - panic(backend.AnsiError + "Failed to read note written with " + editor + backend.AnsiReset) // panic is used to ensure the tempFile is removed, as per the defer statement + panic(core.AnsiError + "Failed to read note written with " + editor + core.AnsiReset) // panic is used to ensure the tempFile is removed, as per the defer statement } // read the edited note from the tempFile @@ -114,7 +114,7 @@ func editNote(baseNote []string) ([]string, bool) { _ = tempFile.Close() // error ignored; if the file could be opened, it can probably be closed // remove trailing empty strings from the edited note - note = backend.RemoveTrailingEmptyStrings(note) + note = core.RemoveTrailingEmptyStrings(note) // trim trailing whitespace from each note line for i, line := range note { diff --git a/src/cli/entryList.go b/src/cli/entryList.go index cae5c26..7c7ad9f 100644 --- a/src/cli/entryList.go +++ b/src/cli/entryList.go @@ -2,10 +2,11 @@ package cli import ( "fmt" - "github.com/rwinkhart/MUTN/src/backend" - "github.com/rwinkhart/MUTN/src/sync" "os" "strings" + + "github.com/rwinkhart/libmutton/core" + "github.com/rwinkhart/libmutton/sync" ) // global constants used only in this file @@ -71,7 +72,7 @@ func printFileEntry(entry string, lastSlash, charCounter, indent int, colorAlter } // print fileEntryName to screen - fmt.Printf("%s%s%s ", colorCode, fileEntryName, backend.AnsiReset) + fmt.Printf("%s%s%s ", colorCode, fileEntryName, core.AnsiReset) return charCounter, colorAlternator } @@ -81,7 +82,7 @@ func EntryListGen() { fileList, dirList := sync.WalkEntryDir() // print header bar w/total entry count - fmt.Print("\n"+ansiBlackOnWhite, len(fileList), " libmutton entries:"+backend.AnsiReset) + fmt.Print("\n"+ansiBlackOnWhite, len(fileList), " libmutton entries:"+core.AnsiReset) // dirList iteration dirListLength := len(dirList) // save length for multiple references below @@ -127,7 +128,7 @@ func EntryListGen() { containsFiles = true skippedDirList[i] = false // the directory header is being printed, indicate that it is not being skipped indent, vanityDirectory = determineIndentation(skippedDirList, dirList, i) // calculate the final indentation multiplier - fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+backend.AnsiReset+"\n", vanityDirectory) + fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+core.AnsiReset+"\n", vanityDirectory) } charCounter, colorAlternator = printFileEntry(file, lastSlash, charCounter, indent, colorAlternator) @@ -139,8 +140,8 @@ func EntryListGen() { if dirListLength > 1 { // and directories besides the root-level exist... display directory header and empty directory warning skippedDirList[i] = false // the directory header is being printed, indicate that it is not being skipped indent, vanityDirectory = determineIndentation(skippedDirList, dirList, i) // calculate the final indentation multiplier - fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+backend.AnsiReset+"\n", vanityDirectory) - fmt.Print(strings.Repeat(" ", indent*2) + ansiEmptyDirectoryWarning + "-empty directory-" + backend.AnsiReset) + fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+core.AnsiReset+"\n", vanityDirectory) + fmt.Print(strings.Repeat(" ", indent*2) + ansiEmptyDirectoryWarning + "-empty directory-" + core.AnsiReset) } else { // warn if the only thing that exists is the root-level directory fmt.Print("\n\nNothing's here! For help creating your first entry, run \"mutn help\".") } diff --git a/src/cli/entryReader.go b/src/cli/entryReader.go index bd84fe9..e11b202 100644 --- a/src/cli/entryReader.go +++ b/src/cli/entryReader.go @@ -5,8 +5,8 @@ import ( "os" "strings" - "github.com/rwinkhart/MUTN/src/backend" - "github.com/rwinkhart/MUTN/src/sync" + "github.com/rwinkhart/libmutton/core" + "github.com/rwinkhart/libmutton/sync" ) const ansiShownPassword = "\033[38;5;10m" @@ -21,33 +21,33 @@ func EntryReader(decryptedEntry []string, hideSecrets, syncEnabled bool) { // if the first field (password) is not empty, print it if decryptedEntry[0] != "" { if !hideSecrets { - fmt.Print(ansiDirectoryHeader + "Password:" + backend.AnsiReset + "\n" + ansiShownPassword + decryptedEntry[0] + backend.AnsiReset + "\n\n") + fmt.Print(ansiDirectoryHeader + "Password:" + core.AnsiReset + "\n" + ansiShownPassword + decryptedEntry[0] + core.AnsiReset + "\n\n") } else { - fmt.Print(ansiDirectoryHeader + "Password:" + backend.AnsiReset + "\n" + ansiEmptyDirectoryWarning + "End command in \"show\" or \"-s\" to view" + backend.AnsiReset + "\n\n") + fmt.Print(ansiDirectoryHeader + "Password:" + core.AnsiReset + "\n" + ansiEmptyDirectoryWarning + "End command in \"show\" or \"-s\" to view" + core.AnsiReset + "\n\n") } } case 1: // if the second field (username) is not empty, print it if decryptedEntry[1] != "" { - fmt.Print(ansiDirectoryHeader + "Username:" + backend.AnsiReset + "\n" + decryptedEntry[1] + "\n\n") + fmt.Print(ansiDirectoryHeader + "Username:" + core.AnsiReset + "\n" + decryptedEntry[1] + "\n\n") } case 2: // if the third field (TOTP secret) is not empty, print it if decryptedEntry[2] != "" { if !hideSecrets { - fmt.Print(ansiDirectoryHeader + "TOTP Secret:" + backend.AnsiReset + "\n" + ansiShownPassword + decryptedEntry[2] + backend.AnsiReset + "\n\n") + fmt.Print(ansiDirectoryHeader + "TOTP Secret:" + core.AnsiReset + "\n" + ansiShownPassword + decryptedEntry[2] + core.AnsiReset + "\n\n") } else { - fmt.Print(ansiDirectoryHeader + "TOTP Secret:" + backend.AnsiReset + "\n" + ansiEmptyDirectoryWarning + "End command in \"show\" or \"-s\" to view" + backend.AnsiReset + "\n\n") + fmt.Print(ansiDirectoryHeader + "TOTP Secret:" + core.AnsiReset + "\n" + ansiEmptyDirectoryWarning + "End command in \"show\" or \"-s\" to view" + core.AnsiReset + "\n\n") } } case 3: // if the fourth field (url) is not empty, print it if decryptedEntry[3] != "" { - fmt.Print(ansiDirectoryHeader + "URL:" + backend.AnsiReset + "\n" + decryptedEntry[3] + "\n\n") + fmt.Print(ansiDirectoryHeader + "URL:" + core.AnsiReset + "\n" + decryptedEntry[3] + "\n\n") } case 4: // print the notes header - fmt.Println(ansiDirectoryHeader + "Notes:" + backend.AnsiReset) + fmt.Println(ansiDirectoryHeader + "Notes:" + core.AnsiReset) // combine remaining fields into a single string (to support Markdown rendering) var notesSlice []string @@ -73,8 +73,8 @@ func EntryReader(decryptedEntry []string, hideSecrets, syncEnabled bool) { // EntryReaderDecrypt is a wrapper for EntryReader that first decrypts a GPG-encrypted file before sending it to EntryReader func EntryReaderDecrypt(targetLocation string, hideSecrets bool) { - if isFile, _ := backend.TargetIsFile(targetLocation, true, 2); isFile { - EntryReader(backend.DecryptGPG(targetLocation), hideSecrets, false) // never sync if decrypting straight to EntryReader, as this means the entry could not have been modified + if isFile, _ := core.TargetIsFile(targetLocation, true, 2); isFile { + EntryReader(core.DecryptGPG(targetLocation), 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/init.go b/src/cli/init.go index 8f3a515..45761f7 100644 --- a/src/cli/init.go +++ b/src/cli/init.go @@ -6,8 +6,8 @@ import ( "os" "strconv" - "github.com/rwinkhart/MUTN/src/backend" - "github.com/rwinkhart/MUTN/src/sync" + "github.com/rwinkhart/libmutton/core" + "github.com/rwinkhart/libmutton/sync" ) // TempInitCli initializes the MUTN environment based on user input (will be replaced with a TUI menu) @@ -15,13 +15,13 @@ func TempInitCli() { // gpgID var gpgID string if inputBinary("Auto-generate GPG key?") { - gpgID = backend.GpgKeyGen() + gpgID = core.GpgKeyGen() } else { // select GPG key from menu - uidSlice := backend.GpgUIDListGen() + uidSlice := core.GpgUIDListGen() gpgIDInt := inputMenuGen("Select GPG key:", uidSlice) if gpgIDInt == 0 { - fmt.Println(backend.AnsiError + "No GPG keys found - please generate one" + backend.AnsiReset) + fmt.Println(core.AnsiError + "No GPG keys found - please generate one" + core.AnsiReset) os.Exit(1) } gpgID = uidSlice[gpgIDInt-1] @@ -34,7 +34,7 @@ func TempInitCli() { configSSH := inputBinary("Configure SSH settings (for synchronization)?") if configSSH { // necessary SSH info - fmt.Println(AnsiBold + "\nNote:" + backend.AnsiReset + " Only key-based authentication is supported (keys may optionally be passphrase-protected).\nThe remote server must already be in your ~" + backend.PathSeparator + ".ssh" + backend.PathSeparator + "known_hosts file.") + fmt.Println(AnsiBold + "\nNote:" + core.AnsiReset + " Only key-based authentication is supported (keys may optionally be passphrase-protected).\nThe remote server must already be in your ~" + core.PathSeparator + ".ssh" + core.PathSeparator + "known_hosts file.") sshUser := input("Remote SSH username:") sshPort := input("Remote SSH port:") sshIP := input("Remote SSH IP/domain:") @@ -43,32 +43,32 @@ func TempInitCli() { var sshKey string var sshKeyIsFile bool for !sshKeyIsFile { - fallbackSSHKey := backend.Home + backend.PathSeparator + ".ssh" + backend.PathSeparator + "id_ed25519" + fallbackSSHKey := core.Home + core.PathSeparator + ".ssh" + core.PathSeparator + "id_ed25519" sshKey = cmp.Or(expandPathWithHome(input("SSH private identity file path (falls back to \""+fallbackSSHKey+"\"):")), fallbackSSHKey) - sshKeyIsFile, _ = backend.TargetIsFile(sshKey, false, 0) + sshKeyIsFile, _ = core.TargetIsFile(sshKey, false, 0) if !sshKeyIsFile { - fmt.Println(backend.AnsiError + "SSH identity file not found: " + sshKey + backend.AnsiReset) + fmt.Println(core.AnsiError + "SSH identity file not found: " + sshKey + core.AnsiReset) } } sshKeyProtected := inputBinary("Is the identity file password-protected?") // initialize libmutton directories - backend.DirInit(false) + core.DirInit(false) // write config file (temporarily assigns sshEntryRoot and sshIsWindows to null to pass initial device ID registration) - backend.WriteConfig([][3]string{{"MUTN", "textEditor", textEditor}, {"LIBMUTTON", "gpgID", gpgID}, {"LIBMUTTON", "sshUser", sshUser}, {"LIBMUTTON", "sshIP", sshIP}, {"LIBMUTTON", "sshPort", sshPort}, {"LIBMUTTON", "sshKey", sshKey}, {"LIBMUTTON", "sshKeyProtected", strconv.FormatBool(sshKeyProtected)}, {"LIBMUTTON", "sshEntryRoot", "null"}, {"LIBMUTTON", "sshIsWindows", "null"}}, false) + core.WriteConfig([][3]string{{"MUTN", "textEditor", textEditor}, {"LIBMUTTON", "gpgID", gpgID}, {"LIBMUTTON", "sshUser", sshUser}, {"LIBMUTTON", "sshIP", sshIP}, {"LIBMUTTON", "sshPort", sshPort}, {"LIBMUTTON", "sshKey", sshKey}, {"LIBMUTTON", "sshKeyProtected", strconv.FormatBool(sshKeyProtected)}, {"LIBMUTTON", "sshEntryRoot", "null"}, {"LIBMUTTON", "sshIsWindows", "null"}}, false) // generate and register device ID sshEntryRoot, sshIsWindows := sync.DeviceIDGen() // update config file with sshEntryRoot and sshIsWindows - backend.WriteConfig([][3]string{{"LIBMUTTON", "sshEntryRoot", sshEntryRoot}, {"LIBMUTTON", "sshIsWindows", sshIsWindows}}, true) + core.WriteConfig([][3]string{{"LIBMUTTON", "sshEntryRoot", sshEntryRoot}, {"LIBMUTTON", "sshIsWindows", sshIsWindows}}, true) } else { // initialize libmutton directories - backend.DirInit(false) + core.DirInit(false) // write config file - backend.WriteConfig([][3]string{{"MUTN", "textEditor", textEditor}, {"LIBMUTTON", "gpgID", gpgID}}, false) + core.WriteConfig([][3]string{{"MUTN", "textEditor", textEditor}, {"LIBMUTTON", "gpgID", gpgID}}, false) } } diff --git a/src/cli/printInfo.go b/src/cli/printInfo.go index 1359bc2..ef1f1d2 100644 --- a/src/cli/printInfo.go +++ b/src/cli/printInfo.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/rwinkhart/MUTN/src/backend" + "github.com/rwinkhart/libmutton/core" ) // global constants used only in this file @@ -14,13 +14,13 @@ const ( ) func HelpMain() { - fmt.Print(AnsiBold + "\nMUTN | Copyright (c) 2024 Randall Winkhart\n" + backend.AnsiReset + ` + fmt.Print(AnsiBold + "\nMUTN | Copyright (c) 2024 Randall Winkhart\n" + core.AnsiReset + ` This software exists under the MIT license; you may redistribute it under certain conditions. This program comes with absolutely no warranty; type "mutn version" for details. -` + AnsiBold + "Usage:" + backend.AnsiReset + ` mutn [/ [argument] [option]] | [argument] +` + AnsiBold + "Usage:" + core.AnsiReset + ` mutn [/ [argument] [option]] | [argument] -` + AnsiBold + "Arguments:" + backend.AnsiReset + ` +` + AnsiBold + "Arguments:" + core.AnsiReset + ` help Bring up this menu version Display version and license information init Set up MUTN (generates libmutton.ini) @@ -31,7 +31,7 @@ This program comes with absolutely no warranty; type "mutn version" for details. shear Delete an existing entry sync Manually sync the entry directory -` + AnsiBold + "Options:" + backend.AnsiReset + ` +` + AnsiBold + "Options:" + core.AnsiReset + ` copy: password|-pw| Copy the password in an entry to your clipboard username|-u Copy the username in an entry to your clipboard @@ -52,17 +52,17 @@ This program comes with absolutely no warranty; type "mutn version" for details. note|-n Add a note entry folder|-f Add a new folder for entries -` + AnsiBold + "Tip 1:" + backend.AnsiReset + ` You can quickly read an entry with "mutn /" -` + AnsiBold + "Tip 2:" + backend.AnsiReset + ` Type "mutn" (no arguments/options) to view a list of saved entries -` + AnsiBold + "Tip 3:" + backend.AnsiReset + ` Provide "add", "edit", "copy", or "gen" as the only argument to receive more specific help -` + AnsiBold + "Tip 4:" + backend.AnsiReset + " Using \"add\", \"edit\", or \"copy\" without specifying an option (field) will default to \"password\"\n\n") +` + AnsiBold + "Tip 1:" + core.AnsiReset + ` You can quickly read an entry with "mutn /" +` + AnsiBold + "Tip 2:" + core.AnsiReset + ` Type "mutn" (no arguments/options) to view a list of saved entries +` + AnsiBold + "Tip 3:" + core.AnsiReset + ` Provide "add", "edit", "copy", or "gen" as the only argument to receive more specific help +` + AnsiBold + "Tip 4:" + core.AnsiReset + " Using \"add\", \"edit\", or \"copy\" without specifying an option (field) will default to \"password\"\n\n") os.Exit(0) } func HelpAdd() { - fmt.Print(AnsiBold + "\nUsage:" + backend.AnsiReset + ` mutn / add