mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-08-28 04:46:41 -04:00
Switch to dependence on github.com/rwinkhart/libmutton
This commit is contained in:
+5
-5
@@ -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:")
|
||||
|
||||
+11
-11
@@ -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 {
|
||||
|
||||
@@ -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\".")
|
||||
}
|
||||
|
||||
+11
-11
@@ -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
|
||||
}
|
||||
|
||||
+14
-14
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+30
-30
@@ -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 [/<entry name> [argument] [option]] | [argument]
|
||||
` + AnsiBold + "Usage:" + core.AnsiReset + ` mutn [/<entry name> [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|<blank> 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 /<entry name>"
|
||||
` + 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 /<entry name>"
|
||||
` + 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 /<entry name> add <option>
|
||||
fmt.Print(AnsiBold + "\nUsage:" + core.AnsiReset + ` mutn /<entry name> add <option>
|
||||
|
||||
` + AnsiBold + "Options:" + backend.AnsiReset + `
|
||||
` + AnsiBold + "Options:" + core.AnsiReset + `
|
||||
add:
|
||||
password|-pw|<blank> Add a password entry
|
||||
note|-n Add a note entry
|
||||
@@ -71,9 +71,9 @@ func HelpAdd() {
|
||||
}
|
||||
|
||||
func HelpEdit() {
|
||||
fmt.Print(AnsiBold + "\nUsage:" + backend.AnsiReset + ` mutn /<entry name> edit <option>
|
||||
fmt.Print(AnsiBold + "\nUsage:" + core.AnsiReset + ` mutn /<entry name> edit <option>
|
||||
|
||||
` + AnsiBold + "Options:" + backend.AnsiReset + `
|
||||
` + AnsiBold + "Options:" + core.AnsiReset + `
|
||||
edit:
|
||||
password|-pw|<blank> Change the password in an entry
|
||||
username|-u Change the username in an entry
|
||||
@@ -85,9 +85,9 @@ func HelpEdit() {
|
||||
}
|
||||
|
||||
func HelpCopy() {
|
||||
fmt.Print(AnsiBold + "\nUsage:" + backend.AnsiReset + ` mutn /<entry name> copy <option>
|
||||
fmt.Print(AnsiBold + "\nUsage:" + core.AnsiReset + ` mutn /<entry name> copy <option>
|
||||
|
||||
` + AnsiBold + "Options:" + backend.AnsiReset + `
|
||||
` + AnsiBold + "Options:" + core.AnsiReset + `
|
||||
copy:
|
||||
password|-pw|<blank> Copy the password in an entry to your clipboard
|
||||
username|-u Copy the username in an entry to your clipboard
|
||||
@@ -98,18 +98,18 @@ func HelpCopy() {
|
||||
}
|
||||
|
||||
func HelpGen() {
|
||||
fmt.Print(AnsiBold + "\nUsage:" + backend.AnsiReset + ` mutn /<entry name> gen [option]
|
||||
fmt.Print(AnsiBold + "\nUsage:" + core.AnsiReset + ` mutn /<entry name> gen [option]
|
||||
|
||||
` + AnsiBold + "Options:" + backend.AnsiReset + `
|
||||
` + AnsiBold + "Options:" + core.AnsiReset + `
|
||||
gen:
|
||||
update|-u Generate a password for an existing entry
|
||||
|
||||
` + AnsiBold + "Tip:" + backend.AnsiReset + " If no options are provided, a new password entry is generated\n\n")
|
||||
` + AnsiBold + "Tip:" + core.AnsiReset + " If no options are provided, a new password entry is generated\n\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func MITLicense() {
|
||||
fmt.Print(AnsiBold + "\n MIT License" + backend.AnsiReset + `
|
||||
fmt.Print(AnsiBold + "\n MIT License" + core.AnsiReset + `
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
@@ -141,18 +141,18 @@ func Version() {
|
||||
MITLicense()
|
||||
fmt.Print("\n\n MUTN is a simple, self-hosted,\n SSH-synchronized password manager based on libmutton\n\n" +
|
||||
" .. ..\n" +
|
||||
" /()\\''.''. " + ansiVersionMeat + "♥♥♥♥" + backend.AnsiReset + " .''.''/()\\ _)\n" +
|
||||
" _. : * " + ansiVersionMeat + "♥♥♥♥♥♥ ♥♥♥♥♥♥♥♥" + backend.AnsiReset + " * : <[◎]|_|=\n" +
|
||||
" }-}-*] `..'..' " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥♥♥♥♥" + backend.AnsiReset + " `..'..' |\n" +
|
||||
" ◎-◎ // \\\\ " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥" + backend.AnsiReset + " // \\\\ /|\\\n" +
|
||||
" /()\\''.''. " + ansiVersionMeat + "♥♥♥♥" + core.AnsiReset + " .''.''/()\\ _)\n" +
|
||||
" _. : * " + ansiVersionMeat + "♥♥♥♥♥♥ ♥♥♥♥♥♥♥♥" + core.AnsiReset + " * : <[◎]|_|=\n" +
|
||||
" }-}-*] `..'..' " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥♥♥♥♥" + core.AnsiReset + " `..'..' |\n" +
|
||||
" ◎-◎ // \\\\ " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥" + core.AnsiReset + " // \\\\ /|\\\n" +
|
||||
ansiVersionOutline + "<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" +
|
||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " MUTN Version " + backend.LibmuttonVersion + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " The Tripe Transmission Update " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " Copyright (c) 2024 Randall Winkhart " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" + backend.AnsiReset +
|
||||
"\\" + ansiBlackOnWhite + " " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " MUTN Version " + core.LibmuttonVersion + " " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " The Tripe Transmission Update " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " Copyright (c) 2024 Randall Winkhart " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" + core.AnsiReset +
|
||||
"\n For more information, see:\n\n" +
|
||||
" https://github.com/rwinkhart/MUTN\n" +
|
||||
" https://github.com/rwinkhart/libmutton\n\n")
|
||||
|
||||
@@ -6,8 +6,8 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"github.com/rwinkhart/libmutton/core"
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
// input prompts the user for input and returns the input as a string
|
||||
@@ -21,7 +21,7 @@ func input(prompt string) string {
|
||||
// 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()))
|
||||
byteInput, _ := term.ReadPassword(int(os.Stdin.Fd()))
|
||||
password := string(byteInput)
|
||||
fmt.Println()
|
||||
return password
|
||||
@@ -66,19 +66,19 @@ func inputMenuGen(prompt string, options []string) int {
|
||||
|
||||
// writeEntryCLI writes an entry to targetLocation and previews it (errors if no data is supplied)
|
||||
func writeEntryCLI(targetLocation string, unencryptedEntry []string, hideSecrets, verifyEntryDoesNotExist bool) {
|
||||
if backend.EntryIsNotEmpty(unencryptedEntry) {
|
||||
if core.EntryIsNotEmpty(unencryptedEntry) {
|
||||
// write the entry to the target location
|
||||
backend.WriteEntry(targetLocation, unencryptedEntry, verifyEntryDoesNotExist)
|
||||
core.WriteEntry(targetLocation, unencryptedEntry, verifyEntryDoesNotExist)
|
||||
// preview the entry
|
||||
fmt.Println(AnsiBold + "\nEntry Preview:" + backend.AnsiReset)
|
||||
fmt.Println(AnsiBold + "\nEntry Preview:" + core.AnsiReset)
|
||||
EntryReader(unencryptedEntry, hideSecrets, true)
|
||||
} else {
|
||||
fmt.Println(backend.AnsiError + "No data supplied for entry" + backend.AnsiReset)
|
||||
fmt.Println(core.AnsiError + "No data supplied for entry" + core.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
// expandPathWithHome, given a path (as a string) containing "~", returns the path with "~" expanded to the user's home directory
|
||||
func expandPathWithHome(path string) string {
|
||||
return strings.Replace(path, "~", backend.Home, 1)
|
||||
return strings.Replace(path, "~", core.Home, 1)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user