mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-08-28 12:56:30 -04:00
Refactor for better modularity (share more code among edit functions, rename "offline" package to "backend"
This commit is contained in:
+2
-2
@@ -1,14 +1,14 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
termy "golang.org/x/crypto/ssh/terminal"
|
||||
"os"
|
||||
)
|
||||
|
||||
// global variables used across multiple files
|
||||
var (
|
||||
rootLength = len(offline.EntryRoot)
|
||||
rootLength = len(backend.EntryRoot)
|
||||
width, _, _ = termy.GetSize(int(os.Stdout.Fd()))
|
||||
)
|
||||
|
||||
|
||||
+5
-5
@@ -2,16 +2,16 @@ package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"os"
|
||||
)
|
||||
|
||||
// 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, hidePassword bool, entryType uint8) {
|
||||
_, isAccessible := offline.TargetIsFile(targetLocation, false, 0)
|
||||
_, isAccessible := backend.TargetIsFile(targetLocation, false, 0)
|
||||
if isAccessible {
|
||||
fmt.Println(offline.AnsiError + "Target location already exists" + offline.AnsiReset)
|
||||
fmt.Println(backend.AnsiError + "Target location already exists" + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ func AddEntry(targetLocation string, hidePassword bool, entryType uint8) {
|
||||
if entryType == 0 {
|
||||
password = inputHidden("Password:")
|
||||
} else {
|
||||
password = offline.StringGen(inputInt("Password length:", -1), inputBinary("Generate a complex (special characters) password?"), 0.2)
|
||||
password = backend.StringGen(inputInt("Password length:", -1), inputBinary("Generate a complex (special characters) password?"), 0.2)
|
||||
}
|
||||
|
||||
url := input("URL:")
|
||||
@@ -41,5 +41,5 @@ func AddEntry(targetLocation string, hidePassword bool, entryType uint8) {
|
||||
}
|
||||
|
||||
// write and preview the new entry
|
||||
writeEntryShortcut(targetLocation, unencryptedEntry, hidePassword)
|
||||
writeEntryCLI(targetLocation, unencryptedEntry, hidePassword)
|
||||
}
|
||||
|
||||
+23
-39
@@ -3,7 +3,7 @@ package cli
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
@@ -13,25 +13,19 @@ import (
|
||||
// RenameCli renames an entry at oldLocation to a new location (user input)
|
||||
func RenameCli(oldLocation string) {
|
||||
// ensure targetLocation exists
|
||||
offline.TargetIsFile(oldLocation, true, 0)
|
||||
backend.TargetIsFile(oldLocation, true, 0)
|
||||
|
||||
// prompt user for new location and rename
|
||||
newLocation := offline.EntryRoot + offline.PathSeparator + input("New location:")
|
||||
offline.Rename(oldLocation, newLocation)
|
||||
newLocation := backend.EntryRoot + backend.PathSeparator + input("New location:")
|
||||
backend.Rename(oldLocation, newLocation)
|
||||
|
||||
// exit is done from offline.Rename
|
||||
// exit is done from backend.Rename
|
||||
}
|
||||
|
||||
// EditEntry edits a field of an entry at targetLocation (user input), does not allow for editing notes
|
||||
func EditEntry(targetLocation string, hidePassword bool, field int) {
|
||||
// ensure targetLocation exists
|
||||
offline.TargetIsFile(targetLocation, true, 2)
|
||||
|
||||
// read old entry data
|
||||
unencryptedEntry := offline.DecryptGPG(targetLocation)
|
||||
|
||||
// ensure slice is long enough for field
|
||||
unencryptedEntry = offline.EnsureSliceLength(unencryptedEntry, field)
|
||||
// EditEntryField edits a field of an entry at targetLocation (user input), does not allow for editing notes
|
||||
func EditEntryField(targetLocation string, hidePassword bool, field int) {
|
||||
// fetch old entry data (with all required lines present)
|
||||
unencryptedEntry := backend.GetOldEntryData(targetLocation, field)
|
||||
|
||||
// edit the field
|
||||
switch field {
|
||||
@@ -44,20 +38,13 @@ func EditEntry(targetLocation string, hidePassword bool, field int) {
|
||||
}
|
||||
|
||||
// write and preview the modified entry
|
||||
writeEntryShortcut(targetLocation, unencryptedEntry, hidePassword)
|
||||
writeEntryCLI(targetLocation, unencryptedEntry, hidePassword)
|
||||
}
|
||||
|
||||
// EditEntryNote edits the note of an entry at targetLocation (user input)
|
||||
func EditEntryNote(targetLocation string, hidePassword bool) {
|
||||
// ensure targetLocation exists
|
||||
offline.TargetIsFile(targetLocation, true, 2)
|
||||
|
||||
// read old entry data
|
||||
unencryptedEntry := offline.DecryptGPG(targetLocation)
|
||||
|
||||
// ensure slice is long enough for note
|
||||
// avoids errors when storing non-note data
|
||||
unencryptedEntry = offline.EnsureSliceLength(unencryptedEntry, 2) // 2 is used because it is the index of URL, the last non-note field
|
||||
// fetch old entry data (with all required lines present)
|
||||
unencryptedEntry := backend.GetOldEntryData(targetLocation, 2)
|
||||
|
||||
// store non-note data separately
|
||||
nonNoteData := unencryptedEntry[:3]
|
||||
@@ -68,36 +55,33 @@ func EditEntryNote(targetLocation string, hidePassword bool) {
|
||||
// edit the note
|
||||
editedNote, noteEdited := editNote(noteData)
|
||||
if !noteEdited { // exit early if the note was not edited
|
||||
fmt.Println(offline.AnsiError + "Entry is unchanged" + offline.AnsiReset)
|
||||
fmt.Println(backend.AnsiError + "Entry is unchanged" + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
unencryptedEntry = append(nonNoteData, editedNote...)
|
||||
|
||||
// write and preview the modified entry
|
||||
writeEntryShortcut(targetLocation, unencryptedEntry, hidePassword)
|
||||
writeEntryCLI(targetLocation, unencryptedEntry, hidePassword)
|
||||
}
|
||||
|
||||
// GenUpdate generates a new password for an entry at targetLocation (user input)
|
||||
func GenUpdate(targetLocation string, hidePassword bool) {
|
||||
// ensure targetLocation exists
|
||||
offline.TargetIsFile(targetLocation, true, 2)
|
||||
|
||||
// read old entry data
|
||||
unencryptedEntry := offline.DecryptGPG(targetLocation)
|
||||
// fetch old entry data
|
||||
unencryptedEntry := backend.GetOldEntryData(targetLocation, 0)
|
||||
|
||||
// generate a new password
|
||||
unencryptedEntry[0] = offline.StringGen(inputInt("Password length:", -1), inputBinary("Generate a complex (special characters) password?"), 0.2)
|
||||
unencryptedEntry[0] = backend.StringGen(inputInt("Password length:", -1), inputBinary("Generate a complex (special characters) password?"), 0.2)
|
||||
|
||||
// write and preview the modified entry
|
||||
writeEntryShortcut(targetLocation, unencryptedEntry, hidePassword)
|
||||
writeEntryCLI(targetLocation, unencryptedEntry, hidePassword)
|
||||
}
|
||||
|
||||
// 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 := offline.CreateTempFile()
|
||||
tempFile := backend.CreateTempFile()
|
||||
defer os.Remove(tempFile.Name())
|
||||
editor := offline.ReadConfig([]string{"textEditor"})[0]
|
||||
editor := backend.ReadConfig([]string{"textEditor"})[0]
|
||||
|
||||
// write baseNote to tempFile (if it is not empty)
|
||||
if len(baseNote) > 0 {
|
||||
@@ -116,13 +100,13 @@ func editNote(baseNote []string) ([]string, bool) {
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
if err != nil {
|
||||
panic(offline.AnsiError + "Failed to write note with " + editor + offline.AnsiReset)
|
||||
panic(backend.AnsiError + "Failed to write note with " + editor + backend.AnsiReset)
|
||||
}
|
||||
|
||||
// open the tempFile for reading
|
||||
tempFile, err = os.Open(tempFile.Name())
|
||||
if err != nil {
|
||||
panic(offline.AnsiError + "Failed to write note with " + editor + offline.AnsiReset)
|
||||
panic(backend.AnsiError + "Failed to write note with " + editor + backend.AnsiReset)
|
||||
}
|
||||
|
||||
// read the edited note from the tempFile
|
||||
@@ -136,7 +120,7 @@ func editNote(baseNote []string) ([]string, bool) {
|
||||
tempFile.Close()
|
||||
|
||||
// remove trailing empty strings from the edited note
|
||||
note = offline.RemoveTrailingEmptyStrings(note)
|
||||
note = backend.RemoveTrailingEmptyStrings(note)
|
||||
|
||||
// trim trailing whitespace from each note line
|
||||
for i, line := range note {
|
||||
|
||||
+11
-11
@@ -2,7 +2,7 @@ package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
@@ -23,10 +23,10 @@ func determineIndentation(skippedDirList []bool, dirList []string, currentDirInd
|
||||
var trimmedDirectory = dirList[currentDirIndex]
|
||||
|
||||
// determine initial indentation multiplier based on PathSeparator occurrences
|
||||
indent := strings.Count(trimmedDirectory, offline.PathSeparator) - 1 // subtract 1 to avoid indenting root-level directories
|
||||
indent := strings.Count(trimmedDirectory, backend.PathSeparator) - 1 // subtract 1 to avoid indenting root-level directories
|
||||
|
||||
for i, skipped := range skippedDirList[:currentDirIndex] { // checks each skipped directory to determine if it is a parent to the current directory
|
||||
if strings.HasPrefix(trimmedDirectory, dirList[i]+offline.PathSeparator) { // if the current directory is the child of this iteration's directory...
|
||||
if strings.HasPrefix(trimmedDirectory, dirList[i]+backend.PathSeparator) { // if the current directory is the child of this iteration's directory...
|
||||
if skipped { // ...and this iteration's directory was skipped...
|
||||
subtractor++ // increment the subtractor to indicate that the visual indentation should be reduced
|
||||
} else {
|
||||
@@ -72,7 +72,7 @@ func printFileEntry(entry string, lastSlash int, charCounter int, colorAlternato
|
||||
}
|
||||
|
||||
// print fileEntryName to screen
|
||||
fmt.Printf("%s%s%s ", colorCode, fileEntryName, offline.AnsiReset)
|
||||
fmt.Printf("%s%s%s ", colorCode, fileEntryName, backend.AnsiReset)
|
||||
|
||||
return charCounter, colorAlternator
|
||||
}
|
||||
@@ -84,16 +84,16 @@ func EntryListGen() {
|
||||
var dirList []string
|
||||
|
||||
// walk entry directory
|
||||
_ = filepath.WalkDir(offline.EntryRoot,
|
||||
_ = filepath.WalkDir(backend.EntryRoot,
|
||||
func(fullPath string, entry fs.DirEntry, err error) error {
|
||||
|
||||
// check for errors encountered while walking directory
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
fmt.Println(offline.AnsiError + "\nThe entry directory does not exist - run \"mutn init\" to create it" + offline.AnsiReset)
|
||||
fmt.Println(backend.AnsiError + "\nThe entry directory does not exist - run \"mutn init\" to create it" + backend.AnsiReset)
|
||||
} else {
|
||||
// otherwise, print the source of the error
|
||||
fmt.Println(offline.AnsiError + "\nAn unexpected error occurred while generating the entry list: " + err.Error() + offline.AnsiReset)
|
||||
fmt.Println(backend.AnsiError + "\nAn unexpected error occurred while generating the entry list: " + err.Error() + backend.AnsiReset)
|
||||
}
|
||||
os.Exit(1)
|
||||
}
|
||||
@@ -112,7 +112,7 @@ func EntryListGen() {
|
||||
})
|
||||
|
||||
// print header bar w/total entry count
|
||||
fmt.Print("\n"+ansiBlackOnWhite, len(fileList), " libmutton entries:"+offline.AnsiReset)
|
||||
fmt.Print("\n"+ansiBlackOnWhite, len(fileList), " libmutton entries:"+backend.AnsiReset)
|
||||
|
||||
// dirList iteration
|
||||
dirListLength := len(dirList) // save length for multiple references below
|
||||
@@ -137,7 +137,7 @@ func EntryListGen() {
|
||||
|
||||
// check if next directory is within the current one
|
||||
if dirListLength > i+1 {
|
||||
if nextDir := dirList[i+1]; directory == nextDir[:strings.LastIndex(nextDir, offline.PathSeparator)] {
|
||||
if nextDir := dirList[i+1]; directory == nextDir[:strings.LastIndex(nextDir, backend.PathSeparator)] {
|
||||
containsSubdirectory = true
|
||||
} else {
|
||||
containsSubdirectory = false
|
||||
@@ -151,7 +151,7 @@ func EntryListGen() {
|
||||
for _, file := range fileList {
|
||||
|
||||
// print the current file if it belongs in the current directory - otherwise, break the loop and move on to the next directory
|
||||
if lastSlash := strings.LastIndex(file, offline.PathSeparator) + 1; file[:lastSlash-1] == directory {
|
||||
if lastSlash := strings.LastIndex(file, backend.PathSeparator) + 1; file[:lastSlash-1] == directory {
|
||||
|
||||
// print directory header if this is the first run of the loop
|
||||
if !containsFiles {
|
||||
@@ -171,7 +171,7 @@ func EntryListGen() {
|
||||
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
|
||||
printDirectoryHeader(vanityDirectory, indent)
|
||||
fmt.Print(strings.Repeat(" ", indent*2) + ansiEmptyDirectoryWarning + "-empty directory-" + offline.AnsiReset)
|
||||
fmt.Print(strings.Repeat(" ", indent*2) + ansiEmptyDirectoryWarning + "-empty directory-" + backend.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\".")
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func printDirectoryHeader(vanityDirectory string, indent int) {
|
||||
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+offline.AnsiReset+"\n", vanityDirectory)
|
||||
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+backend.AnsiReset+"\n", vanityDirectory)
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func printDirectoryHeader(vanityDirectory string, indent int) {
|
||||
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+offline.AnsiReset+"\n", strings.ReplaceAll(vanityDirectory, offline.PathSeparator, "/"))
|
||||
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+backend.AnsiReset+"\n", strings.ReplaceAll(vanityDirectory, backend.PathSeparator, "/"))
|
||||
}
|
||||
|
||||
+11
-11
@@ -5,7 +5,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
|
||||
"github.com/charmbracelet/glamour"
|
||||
)
|
||||
@@ -22,24 +22,24 @@ func EntryReader(decryptedEntry []string, hidePassword bool, sync bool) {
|
||||
// if the first field (password) is not empty, print it
|
||||
if decryptedEntry[0] != "" {
|
||||
if !hidePassword {
|
||||
fmt.Print(ansiDirectoryHeader + "Password:" + offline.AnsiReset + "\n" + ansiShownPassword + decryptedEntry[0] + offline.AnsiReset + "\n\n")
|
||||
fmt.Print(ansiDirectoryHeader + "Password:" + backend.AnsiReset + "\n" + ansiShownPassword + decryptedEntry[0] + backend.AnsiReset + "\n\n")
|
||||
} else {
|
||||
fmt.Print(ansiDirectoryHeader + "Password:" + offline.AnsiReset + "\n" + ansiEmptyDirectoryWarning + "End command in \"show\" or \"-s\" to view" + offline.AnsiReset + "\n\n")
|
||||
fmt.Print(ansiDirectoryHeader + "Password:" + backend.AnsiReset + "\n" + ansiEmptyDirectoryWarning + "End command in \"show\" or \"-s\" to view" + backend.AnsiReset + "\n\n")
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
// if the second field (username) is not empty, print it
|
||||
if decryptedEntry[1] != "" {
|
||||
fmt.Print(ansiDirectoryHeader + "Username:" + offline.AnsiReset + "\n" + decryptedEntry[1] + "\n\n")
|
||||
fmt.Print(ansiDirectoryHeader + "Username:" + backend.AnsiReset + "\n" + decryptedEntry[1] + "\n\n")
|
||||
}
|
||||
case 2:
|
||||
// if the third field (url) is not empty, print it
|
||||
if decryptedEntry[2] != "" {
|
||||
fmt.Print(ansiDirectoryHeader + "URL:" + offline.AnsiReset + "\n" + decryptedEntry[2] + "\n\n")
|
||||
fmt.Print(ansiDirectoryHeader + "URL:" + backend.AnsiReset + "\n" + decryptedEntry[2] + "\n\n")
|
||||
}
|
||||
case 3:
|
||||
// print the notes header
|
||||
fmt.Println(ansiDirectoryHeader + "Notes:" + offline.AnsiReset)
|
||||
fmt.Println(ansiDirectoryHeader + "Notes:" + backend.AnsiReset)
|
||||
|
||||
// combine remaining fields into a single string (for markdown rendering)
|
||||
var markdownNotes []string
|
||||
@@ -57,17 +57,17 @@ func EntryReader(decryptedEntry []string, hidePassword bool, sync bool) {
|
||||
}
|
||||
}
|
||||
|
||||
if sync && !offline.Windows {
|
||||
if sync && !backend.Windows {
|
||||
SshypSync() // TODO Remove after native sync is implemented
|
||||
}
|
||||
|
||||
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, sync bool) {
|
||||
if isFile, _ := offline.TargetIsFile(targetLocation, true, 2); isFile {
|
||||
EntryReader(offline.DecryptGPG(targetLocation), hidePassword, sync)
|
||||
// EntryReaderDecrypt is a wrapper for EntryReader that first decrypts a GPG-encrypted file before sending it to EntryReader
|
||||
func EntryReaderDecrypt(targetLocation string, hidePassword bool, sync bool) {
|
||||
if isFile, _ := backend.TargetIsFile(targetLocation, true, 2); isFile {
|
||||
EntryReader(backend.DecryptGPG(targetLocation), hidePassword, sync)
|
||||
}
|
||||
// do not exit, as this is the job of EntryReader
|
||||
}
|
||||
|
||||
+6
-6
@@ -2,7 +2,7 @@ package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"os"
|
||||
)
|
||||
|
||||
@@ -11,20 +11,20 @@ func TempInitCli() {
|
||||
// gpgID
|
||||
var gpgID string
|
||||
if inputBinary("Auto-generate GPG key?") {
|
||||
gpgID = offline.GpgKeyGen()
|
||||
gpgID = backend.GpgKeyGen()
|
||||
} else {
|
||||
// select GPG key from menu
|
||||
uidSlice := offline.GpgUIDListGen()
|
||||
uidSlice := backend.GpgUIDListGen()
|
||||
gpgIDInt := inputMenuGen("Select GPG key:", uidSlice)
|
||||
if gpgIDInt == 0 {
|
||||
fmt.Println(offline.AnsiError + "No GPG keys found - please generate one" + offline.AnsiReset)
|
||||
fmt.Println(backend.AnsiError + "No GPG keys found - please generate one" + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
gpgID = uidSlice[gpgIDInt-1]
|
||||
}
|
||||
|
||||
// textEditor
|
||||
textEditor := input("Text editor (leave blank for $EDITOR, falls back to \"" + offline.FallbackEditor + "\"):")
|
||||
textEditor := input("Text editor (leave blank for $EDITOR, falls back to \"" + backend.FallbackEditor + "\"):")
|
||||
|
||||
offline.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID})
|
||||
backend.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID})
|
||||
}
|
||||
|
||||
+30
-30
@@ -4,7 +4,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
)
|
||||
|
||||
// global constants used only in this file
|
||||
@@ -14,13 +14,13 @@ const (
|
||||
)
|
||||
|
||||
func HelpMain() {
|
||||
fmt.Print(ansiBold + "\nMUTN | Copyright (c) 2024 Randall Winkhart\n" + offline.AnsiReset + `
|
||||
fmt.Print(ansiBold + "\nMUTN | Copyright (c) 2024 Randall Winkhart\n" + backend.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:" + offline.AnsiReset + ` mutn [/<entry name> [argument] [option]] | [argument]
|
||||
` + ansiBold + "Usage:" + backend.AnsiReset + ` mutn [/<entry name> [argument] [option]] | [argument]
|
||||
|
||||
` + ansiBold + "Arguments:" + offline.AnsiReset + `
|
||||
` + ansiBold + "Arguments:" + backend.AnsiReset + `
|
||||
help|-h Bring up this menu
|
||||
version|-v Display version and license information
|
||||
init Set up MUTN (generates libmutton.ini)
|
||||
@@ -32,7 +32,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:" + offline.AnsiReset + `
|
||||
` + ansiBold + "Options:" + backend.AnsiReset + `
|
||||
copy:
|
||||
password|-pw|<blank> Copy the password of an entry to your clipboard
|
||||
username|-u Copy the username of 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:" + offline.AnsiReset + ` You can quickly read an entry with "mutn /<entry name>"
|
||||
` + ansiBold + "Tip 2:" + offline.AnsiReset + ` Type "mutn" (no arguments/options) to view a list of saved entries
|
||||
` + ansiBold + "Tip 3:" + offline.AnsiReset + ` Provide "add", "edit", "copy", or "gen" as the only argument to receive more specific help
|
||||
` + ansiBold + "Tip 4:" + offline.AnsiReset + " Using \"add\", \"edit\", or \"copy\" without specifying an option (field) will default to \"password\"\n\n")
|
||||
` + 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")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func HelpAdd() {
|
||||
fmt.Print(ansiBold + "\nUsage:" + offline.AnsiReset + ` mutn /<entry name> add <option>
|
||||
fmt.Print(ansiBold + "\nUsage:" + backend.AnsiReset + ` mutn /<entry name> add <option>
|
||||
|
||||
` + ansiBold + "Options:" + offline.AnsiReset + `
|
||||
` + ansiBold + "Options:" + backend.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:" + offline.AnsiReset + ` mutn /<entry name> edit <option>
|
||||
fmt.Print(ansiBold + "\nUsage:" + backend.AnsiReset + ` mutn /<entry name> edit <option>
|
||||
|
||||
` + ansiBold + "Options:" + offline.AnsiReset + `
|
||||
` + ansiBold + "Options:" + backend.AnsiReset + `
|
||||
edit:
|
||||
password|-pw|<blank> Change the password of an entry
|
||||
username|-u Change the username of an entry
|
||||
@@ -84,9 +84,9 @@ func HelpEdit() {
|
||||
}
|
||||
|
||||
func HelpCopy() {
|
||||
fmt.Print(ansiBold + "\nUsage:" + offline.AnsiReset + ` mutn /<entry name> copy <option>
|
||||
fmt.Print(ansiBold + "\nUsage:" + backend.AnsiReset + ` mutn /<entry name> copy <option>
|
||||
|
||||
` + ansiBold + "Options:" + offline.AnsiReset + `
|
||||
` + ansiBold + "Options:" + backend.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
|
||||
@@ -97,18 +97,18 @@ func HelpCopy() {
|
||||
}
|
||||
|
||||
func HelpGen() {
|
||||
fmt.Print(ansiBold + "\nUsage:" + offline.AnsiReset + ` mutn /<entry name> gen [option]
|
||||
fmt.Print(ansiBold + "\nUsage:" + backend.AnsiReset + ` mutn /<entry name> gen [option]
|
||||
|
||||
` + ansiBold + "Options:" + offline.AnsiReset + `
|
||||
` + ansiBold + "Options:" + backend.AnsiReset + `
|
||||
gen:
|
||||
update|-u Generate a password for an existing entry
|
||||
|
||||
` + ansiBold + "Tip:" + offline.AnsiReset + " If no options are provided, a new password entry is generated\n\n")
|
||||
` + ansiBold + "Tip:" + backend.AnsiReset + " If no options are provided, a new password entry is generated\n\n")
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
func Version() {
|
||||
fmt.Print(ansiBold + "\n MIT License" + offline.AnsiReset + `
|
||||
fmt.Print(ansiBold + "\n MIT License" + backend.AnsiReset + `
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
@@ -136,18 +136,18 @@ ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||
"\n\n---------------------------------------------------------" +
|
||||
"\n\n MUTN is a simple, self-hosted,\n SSH-synchronized password manager based on libmutton\n\n" +
|
||||
" .. ..\n" +
|
||||
" /()\\''.''. " + ansiVersionMeat + "♥♥♥♥" + offline.AnsiReset + " .''.''/()\\ _)\n" +
|
||||
" _. : * " + ansiVersionMeat + "♥♥♥♥♥♥ ♥♥♥♥♥♥♥♥" + offline.AnsiReset + " * : <[◎]|_|=\n" +
|
||||
" }-}-*] `..'..' " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥♥♥♥♥" + offline.AnsiReset + " `..'..' |\n" +
|
||||
" ◎-◎ // \\\\ " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥" + offline.AnsiReset + " // \\\\ /|\\\n" +
|
||||
" /()\\''.''. " + ansiVersionMeat + "♥♥♥♥" + backend.AnsiReset + " .''.''/()\\ _)\n" +
|
||||
" _. : * " + ansiVersionMeat + "♥♥♥♥♥♥ ♥♥♥♥♥♥♥♥" + backend.AnsiReset + " * : <[◎]|_|=\n" +
|
||||
" }-}-*] `..'..' " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥♥♥♥♥" + backend.AnsiReset + " `..'..' |\n" +
|
||||
" ◎-◎ // \\\\ " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥" + backend.AnsiReset + " // \\\\ /|\\\n" +
|
||||
ansiVersionOutline + "<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" +
|
||||
"\\" + ansiBlackOnWhite + " " + offline.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " MUTN Version 0.0.1 " + offline.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " The Butchered Update " + offline.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " " + offline.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " Copyright (c) 2024 Randall Winkhart " + offline.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " " + offline.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" + offline.AnsiReset +
|
||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " MUTN Version 0.0.1 " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
||||
"\\" + ansiBlackOnWhite + " The Butchered 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 +
|
||||
"\n For more information, see:\n\n" +
|
||||
" https://github.com/rwinkhart/MUTN\n" +
|
||||
" https://github.com/rwinkhart/libmutton\n\n")
|
||||
|
||||
@@ -3,7 +3,7 @@ package cli
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"github.com/rwinkhart/MUTN/src/offline"
|
||||
"github.com/rwinkhart/MUTN/src/backend"
|
||||
"golang.org/x/crypto/ssh/terminal"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -71,16 +71,16 @@ func inputMenuGen(prompt string, options []string) int {
|
||||
return inputInt(prompt, len(options))
|
||||
}
|
||||
|
||||
// writeEntryShortcut writes an entry to targetLocation and previews it (errors if no data is supplied)
|
||||
func writeEntryShortcut(targetLocation string, unencryptedEntry []string, hidePassword bool) {
|
||||
if offline.EntryIsNotEmpty(unencryptedEntry) {
|
||||
// writeEntryCLI writes an entry to targetLocation and previews it (errors if no data is supplied)
|
||||
func writeEntryCLI(targetLocation string, unencryptedEntry []string, hidePassword bool) {
|
||||
if backend.EntryIsNotEmpty(unencryptedEntry) {
|
||||
// write the entry to the target location
|
||||
offline.WriteEntry(targetLocation, unencryptedEntry)
|
||||
backend.WriteEntry(targetLocation, unencryptedEntry)
|
||||
// preview the entry
|
||||
fmt.Println(ansiBold + "\nEntry Preview:" + offline.AnsiReset)
|
||||
fmt.Println(ansiBold + "\nEntry Preview:" + backend.AnsiReset)
|
||||
EntryReader(unencryptedEntry, hidePassword, true)
|
||||
} else {
|
||||
fmt.Println(offline.AnsiError + "No data supplied for entry" + offline.AnsiReset)
|
||||
fmt.Println(backend.AnsiError + "No data supplied for entry" + backend.AnsiReset)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user