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:
@@ -4,12 +4,8 @@ go 1.22.6
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/charmbracelet/glamour v0.7.0
|
github.com/charmbracelet/glamour v0.7.0
|
||||||
github.com/fortis/go-steam-totp v0.0.0-20171114202746-18e928674727
|
github.com/rwinkhart/libmutton v0.0.0-20240808205713-d82188f56655
|
||||||
github.com/pkg/sftp v1.13.6
|
|
||||||
github.com/pquerna/otp v1.4.1-0.20231130234153-3357de7c0481
|
|
||||||
golang.org/x/crypto v0.26.0
|
|
||||||
golang.org/x/term v0.23.0
|
golang.org/x/term v0.23.0
|
||||||
gopkg.in/ini.v1 v1.67.0
|
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@@ -18,6 +14,7 @@ require (
|
|||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
github.com/aymerick/douceur v0.2.0 // indirect
|
||||||
github.com/boombuler/barcode v1.0.2 // indirect
|
github.com/boombuler/barcode v1.0.2 // indirect
|
||||||
github.com/dlclark/regexp2 v1.11.4 // 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/gorilla/css v1.0.1 // indirect
|
||||||
github.com/kr/fs v0.1.0 // indirect
|
github.com/kr/fs v0.1.0 // indirect
|
||||||
github.com/lucasb-eyer/go-colorful v1.2.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/reflow v0.3.0 // indirect
|
||||||
github.com/muesli/termenv v0.15.2 // indirect
|
github.com/muesli/termenv v0.15.2 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.5 // 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/rivo/uniseg v0.4.7 // indirect
|
||||||
github.com/stretchr/testify v1.8.4 // indirect
|
github.com/stretchr/testify v1.8.4 // indirect
|
||||||
github.com/yuin/goldmark v1.7.4 // indirect
|
github.com/yuin/goldmark v1.7.4 // indirect
|
||||||
github.com/yuin/goldmark-emoji v1.0.3 // 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/net v0.28.0 // indirect
|
||||||
golang.org/x/sys v0.23.0 // indirect
|
golang.org/x/sys v0.23.0 // indirect
|
||||||
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -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.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
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.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
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=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
|||||||
+10
-10
@@ -7,9 +7,9 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
|
||||||
"github.com/rwinkhart/MUTN/src/cli"
|
"github.com/rwinkhart/MUTN/src/cli"
|
||||||
"github.com/rwinkhart/MUTN/src/sync"
|
"github.com/rwinkhart/libmutton/core"
|
||||||
|
"github.com/rwinkhart/libmutton/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -55,13 +55,13 @@ func main() {
|
|||||||
case "register":
|
case "register":
|
||||||
// register a new device ID
|
// register a new device ID
|
||||||
// stdin[0] is expected to be the 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
|
// 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":
|
case "init":
|
||||||
// create the necessary directories for libmuttonserver to function
|
// create the necessary directories for libmuttonserver to function
|
||||||
backend.DirInit(false)
|
core.DirInit(false)
|
||||||
_ = os.MkdirAll(backend.ConfigDir+backend.PathSeparator+"deletions", 0700) // error ignored; failure would have occurred by this point in backend.DirInit
|
_ = 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")
|
fmt.Println("libmuttonserver directories initialized")
|
||||||
case "version":
|
case "version":
|
||||||
versionServer()
|
versionServer()
|
||||||
@@ -71,13 +71,13 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func helpServer() {
|
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 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.
|
This program comes with absolutely no warranty; type "libmuttonserver version" for details.
|
||||||
|
|
||||||
` + cli.AnsiBold + "Usage:" + backend.AnsiReset + ` libmuttonserver <argument>
|
` + cli.AnsiBold + "Usage:" + core.AnsiReset + ` libmuttonserver <argument>
|
||||||
|
|
||||||
` + cli.AnsiBold + "Arguments (user):" + backend.AnsiReset + `
|
` + cli.AnsiBold + "Arguments (user):" + core.AnsiReset + `
|
||||||
help Bring up this menu
|
help Bring up this menu
|
||||||
version Display version and license information
|
version Display version and license information
|
||||||
init Create the necessary directories for libmuttonserver to function` + "\n\n")
|
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() {
|
func versionServer() {
|
||||||
cli.MITLicense()
|
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")
|
Copyright (c) 2024 Randall Winkhart` + "\n\n")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
|
||||||
"github.com/rwinkhart/MUTN/src/cli"
|
"github.com/rwinkhart/MUTN/src/cli"
|
||||||
"github.com/rwinkhart/MUTN/src/sync"
|
"github.com/rwinkhart/libmutton/core"
|
||||||
|
"github.com/rwinkhart/libmutton/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -25,7 +25,7 @@ func main() {
|
|||||||
if strings.HasPrefix(args[1], "/") {
|
if strings.HasPrefix(args[1], "/") {
|
||||||
|
|
||||||
// store location of target entry
|
// store location of target entry
|
||||||
targetLocation := backend.TargetLocationFormat(args[1])
|
targetLocation := core.TargetLocationFormat(args[1])
|
||||||
|
|
||||||
// entry reader shortcut (if no other arguments are supplied)
|
// entry reader shortcut (if no other arguments are supplied)
|
||||||
if argsCount == 2 {
|
if argsCount == 2 {
|
||||||
@@ -38,7 +38,7 @@ func main() {
|
|||||||
case "show", "-s":
|
case "show", "-s":
|
||||||
cli.EntryReaderDecrypt(targetLocation, false)
|
cli.EntryReaderDecrypt(targetLocation, false)
|
||||||
case "copy":
|
case "copy":
|
||||||
backend.CopyArgument(args[0], targetLocation, 0)
|
core.CopyArgument(args[0], targetLocation, 0)
|
||||||
case "edit":
|
case "edit":
|
||||||
cli.EditEntryField(targetLocation, true, 0)
|
cli.EditEntryField(targetLocation, true, 0)
|
||||||
case "gen":
|
case "gen":
|
||||||
@@ -82,7 +82,7 @@ func main() {
|
|||||||
default:
|
default:
|
||||||
cli.HelpCopy()
|
cli.HelpCopy()
|
||||||
}
|
}
|
||||||
backend.CopyArgument(args[0], targetLocation, field)
|
core.CopyArgument(args[0], targetLocation, field)
|
||||||
case "edit":
|
case "edit":
|
||||||
var field int // indicates which (numbered) field to edit
|
var field int // indicates which (numbered) field to edit
|
||||||
switch args[3] {
|
switch args[3] {
|
||||||
@@ -97,7 +97,7 @@ func main() {
|
|||||||
case "note", "-n":
|
case "note", "-n":
|
||||||
field = 4
|
field = 4
|
||||||
case "rename", "-r":
|
case "rename", "-r":
|
||||||
backend.TargetIsFile(targetLocation, true, 0) // ensure location exists before prompting for new location
|
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
|
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:
|
default:
|
||||||
cli.HelpEdit()
|
cli.HelpEdit()
|
||||||
@@ -158,13 +158,13 @@ func main() {
|
|||||||
} else {
|
} else {
|
||||||
switch args[1] {
|
switch args[1] {
|
||||||
case "clipclear":
|
case "clipclear":
|
||||||
backend.ClipClearArgument()
|
core.ClipClearArgument()
|
||||||
case "sync":
|
case "sync":
|
||||||
sync.RunJob(true)
|
sync.RunJob(true)
|
||||||
case "init":
|
case "init":
|
||||||
cli.TempInitCli()
|
cli.TempInitCli()
|
||||||
case "tweak":
|
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)
|
os.Exit(0)
|
||||||
case "copy":
|
case "copy":
|
||||||
cli.HelpCopy()
|
cli.HelpCopy()
|
||||||
|
|||||||
+5
-5
@@ -5,21 +5,21 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"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
|
// AddEntry creates a new entry at targetLocation by taking user input via CLI prompts
|
||||||
// entryType: 0 = standard (password), 1 = auto-generated password, 2 = note
|
// entryType: 0 = standard (password), 1 = auto-generated password, 2 = note
|
||||||
func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) {
|
func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) {
|
||||||
// ensure target location does not already exist
|
// ensure target location does not already exist
|
||||||
_, isAccessible := backend.TargetIsFile(targetLocation, false, 0)
|
_, isAccessible := core.TargetIsFile(targetLocation, false, 0)
|
||||||
if isAccessible {
|
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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure target containing directory exists and is a directory (not a file)
|
// 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
|
var unencryptedEntry []string
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) {
|
|||||||
if entryType == 0 {
|
if entryType == 0 {
|
||||||
password = inputHidden("Password:")
|
password = inputHidden("Password:")
|
||||||
} else {
|
} 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:")
|
totp := inputHidden("TOTP secret:")
|
||||||
|
|||||||
+11
-11
@@ -8,8 +8,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/libmutton/core"
|
||||||
"github.com/rwinkhart/MUTN/src/sync"
|
"github.com/rwinkhart/libmutton/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RenameCli renames an entry at oldLocationIncomplete to a new location (user input) on both the client and the server
|
// 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)
|
// EditEntryField edits a field of an entry at targetLocation (user input)
|
||||||
func EditEntryField(targetLocation string, hideSecrets bool, field int) {
|
func EditEntryField(targetLocation string, hideSecrets bool, field int) {
|
||||||
// fetch old entry data (with all required lines present)
|
// fetch old entry data (with all required lines present)
|
||||||
unencryptedEntry := backend.GetOldEntryData(targetLocation, field)
|
unencryptedEntry := core.GetOldEntryData(targetLocation, field)
|
||||||
|
|
||||||
// edit the field
|
// edit the field
|
||||||
switch field {
|
switch field {
|
||||||
@@ -44,7 +44,7 @@ func EditEntryField(targetLocation string, hideSecrets bool, field int) {
|
|||||||
// edit the note
|
// edit the note
|
||||||
editedNote, noteEdited := editNote(noteData)
|
editedNote, noteEdited := editNote(noteData)
|
||||||
if !noteEdited { // exit early if the note was not edited
|
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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
unencryptedEntry = append(nonNoteData, editedNote...)
|
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)
|
// GenUpdate generates a new password for an entry at targetLocation (user input)
|
||||||
func GenUpdate(targetLocation string, hideSecrets bool) {
|
func GenUpdate(targetLocation string, hideSecrets bool) {
|
||||||
// fetch old entry data
|
// fetch old entry data
|
||||||
unencryptedEntry := backend.GetOldEntryData(targetLocation, 0)
|
unencryptedEntry := core.GetOldEntryData(targetLocation, 0)
|
||||||
|
|
||||||
// generate a new password
|
// 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
|
// write and preview the modified entry
|
||||||
writeEntryCLI(targetLocation, unencryptedEntry, hideSecrets, false)
|
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)
|
// 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
|
// returns the edited note and a boolean indicating whether the note was edited
|
||||||
func editNote(baseNote []string) ([]string, bool) {
|
func editNote(baseNote []string) ([]string, bool) {
|
||||||
tempFile := backend.CreateTempFile()
|
tempFile := core.CreateTempFile()
|
||||||
defer func(name string) {
|
defer func(name string) {
|
||||||
_ = os.Remove(name) // error ignored; if the file could be created, it can probably be removed
|
_ = os.Remove(name) // error ignored; if the file could be created, it can probably be removed
|
||||||
}(tempFile.Name())
|
}(tempFile.Name())
|
||||||
|
|
||||||
// fetch the user's text editor
|
// 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)
|
// write baseNote to tempFile (if it is not empty)
|
||||||
if len(baseNote) > 0 {
|
if len(baseNote) > 0 {
|
||||||
@@ -94,13 +94,13 @@ func editNote(baseNote []string) ([]string, bool) {
|
|||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
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
|
// open the tempFile for reading
|
||||||
tempFile, err = os.Open(tempFile.Name())
|
tempFile, err = os.Open(tempFile.Name())
|
||||||
if err != nil {
|
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
|
// 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
|
_ = tempFile.Close() // error ignored; if the file could be opened, it can probably be closed
|
||||||
|
|
||||||
// remove trailing empty strings from the edited note
|
// remove trailing empty strings from the edited note
|
||||||
note = backend.RemoveTrailingEmptyStrings(note)
|
note = core.RemoveTrailingEmptyStrings(note)
|
||||||
|
|
||||||
// trim trailing whitespace from each note line
|
// trim trailing whitespace from each note line
|
||||||
for i, line := range note {
|
for i, line := range note {
|
||||||
|
|||||||
@@ -2,10 +2,11 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
|
||||||
"github.com/rwinkhart/MUTN/src/sync"
|
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/rwinkhart/libmutton/core"
|
||||||
|
"github.com/rwinkhart/libmutton/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// global constants used only in this file
|
// global constants used only in this file
|
||||||
@@ -71,7 +72,7 @@ func printFileEntry(entry string, lastSlash, charCounter, indent int, colorAlter
|
|||||||
}
|
}
|
||||||
|
|
||||||
// print fileEntryName to screen
|
// 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
|
return charCounter, colorAlternator
|
||||||
}
|
}
|
||||||
@@ -81,7 +82,7 @@ func EntryListGen() {
|
|||||||
fileList, dirList := sync.WalkEntryDir()
|
fileList, dirList := sync.WalkEntryDir()
|
||||||
|
|
||||||
// print header bar w/total entry count
|
// 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
|
// dirList iteration
|
||||||
dirListLength := len(dirList) // save length for multiple references below
|
dirListLength := len(dirList) // save length for multiple references below
|
||||||
@@ -127,7 +128,7 @@ func EntryListGen() {
|
|||||||
containsFiles = true
|
containsFiles = true
|
||||||
skippedDirList[i] = false // the directory header is being printed, indicate that it is not being skipped
|
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
|
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)
|
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
|
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
|
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
|
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)
|
||||||
fmt.Print(strings.Repeat(" ", indent*2) + ansiEmptyDirectoryWarning + "-empty directory-" + backend.AnsiReset)
|
fmt.Print(strings.Repeat(" ", indent*2) + ansiEmptyDirectoryWarning + "-empty directory-" + core.AnsiReset)
|
||||||
} else { // warn if the only thing that exists is the root-level directory
|
} 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\".")
|
fmt.Print("\n\nNothing's here! For help creating your first entry, run \"mutn help\".")
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -5,8 +5,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/libmutton/core"
|
||||||
"github.com/rwinkhart/MUTN/src/sync"
|
"github.com/rwinkhart/libmutton/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
const ansiShownPassword = "\033[38;5;10m"
|
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 the first field (password) is not empty, print it
|
||||||
if decryptedEntry[0] != "" {
|
if decryptedEntry[0] != "" {
|
||||||
if !hideSecrets {
|
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 {
|
} 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:
|
case 1:
|
||||||
// if the second field (username) is not empty, print it
|
// if the second field (username) is not empty, print it
|
||||||
if decryptedEntry[1] != "" {
|
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:
|
case 2:
|
||||||
// if the third field (TOTP secret) is not empty, print it
|
// if the third field (TOTP secret) is not empty, print it
|
||||||
if decryptedEntry[2] != "" {
|
if decryptedEntry[2] != "" {
|
||||||
if !hideSecrets {
|
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 {
|
} 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:
|
case 3:
|
||||||
// if the fourth field (url) is not empty, print it
|
// if the fourth field (url) is not empty, print it
|
||||||
if decryptedEntry[3] != "" {
|
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:
|
case 4:
|
||||||
// print the notes header
|
// 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)
|
// combine remaining fields into a single string (to support Markdown rendering)
|
||||||
var notesSlice []string
|
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
|
// EntryReaderDecrypt is a wrapper for EntryReader that first decrypts a GPG-encrypted file before sending it to EntryReader
|
||||||
func EntryReaderDecrypt(targetLocation string, hideSecrets bool) {
|
func EntryReaderDecrypt(targetLocation string, hideSecrets bool) {
|
||||||
if isFile, _ := backend.TargetIsFile(targetLocation, true, 2); isFile {
|
if isFile, _ := core.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
|
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
|
// do not exit, as this is the job of EntryReader
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-14
@@ -6,8 +6,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/libmutton/core"
|
||||||
"github.com/rwinkhart/MUTN/src/sync"
|
"github.com/rwinkhart/libmutton/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TempInitCli initializes the MUTN environment based on user input (will be replaced with a TUI menu)
|
// TempInitCli initializes the MUTN environment based on user input (will be replaced with a TUI menu)
|
||||||
@@ -15,13 +15,13 @@ func TempInitCli() {
|
|||||||
// gpgID
|
// gpgID
|
||||||
var gpgID string
|
var gpgID string
|
||||||
if inputBinary("Auto-generate GPG key?") {
|
if inputBinary("Auto-generate GPG key?") {
|
||||||
gpgID = backend.GpgKeyGen()
|
gpgID = core.GpgKeyGen()
|
||||||
} else {
|
} else {
|
||||||
// select GPG key from menu
|
// select GPG key from menu
|
||||||
uidSlice := backend.GpgUIDListGen()
|
uidSlice := core.GpgUIDListGen()
|
||||||
gpgIDInt := inputMenuGen("Select GPG key:", uidSlice)
|
gpgIDInt := inputMenuGen("Select GPG key:", uidSlice)
|
||||||
if gpgIDInt == 0 {
|
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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
gpgID = uidSlice[gpgIDInt-1]
|
gpgID = uidSlice[gpgIDInt-1]
|
||||||
@@ -34,7 +34,7 @@ func TempInitCli() {
|
|||||||
configSSH := inputBinary("Configure SSH settings (for synchronization)?")
|
configSSH := inputBinary("Configure SSH settings (for synchronization)?")
|
||||||
if configSSH {
|
if configSSH {
|
||||||
// necessary SSH info
|
// 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:")
|
sshUser := input("Remote SSH username:")
|
||||||
sshPort := input("Remote SSH port:")
|
sshPort := input("Remote SSH port:")
|
||||||
sshIP := input("Remote SSH IP/domain:")
|
sshIP := input("Remote SSH IP/domain:")
|
||||||
@@ -43,32 +43,32 @@ func TempInitCli() {
|
|||||||
var sshKey string
|
var sshKey string
|
||||||
var sshKeyIsFile bool
|
var sshKeyIsFile bool
|
||||||
for !sshKeyIsFile {
|
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)
|
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 {
|
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?")
|
sshKeyProtected := inputBinary("Is the identity file password-protected?")
|
||||||
|
|
||||||
// initialize libmutton directories
|
// 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)
|
// 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
|
// generate and register device ID
|
||||||
sshEntryRoot, sshIsWindows := sync.DeviceIDGen()
|
sshEntryRoot, sshIsWindows := sync.DeviceIDGen()
|
||||||
|
|
||||||
// update config file with sshEntryRoot and sshIsWindows
|
// 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 {
|
} else {
|
||||||
// initialize libmutton directories
|
// initialize libmutton directories
|
||||||
backend.DirInit(false)
|
core.DirInit(false)
|
||||||
|
|
||||||
// write config file
|
// 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"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/libmutton/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
// global constants used only in this file
|
// global constants used only in this file
|
||||||
@@ -14,13 +14,13 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func HelpMain() {
|
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 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.
|
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
|
help Bring up this menu
|
||||||
version Display version and license information
|
version Display version and license information
|
||||||
init Set up MUTN (generates libmutton.ini)
|
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
|
shear Delete an existing entry
|
||||||
sync Manually sync the entry directory
|
sync Manually sync the entry directory
|
||||||
|
|
||||||
` + AnsiBold + "Options:" + backend.AnsiReset + `
|
` + AnsiBold + "Options:" + core.AnsiReset + `
|
||||||
copy:
|
copy:
|
||||||
password|-pw|<blank> Copy the password in an entry to your clipboard
|
password|-pw|<blank> Copy the password in an entry to your clipboard
|
||||||
username|-u Copy the username 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
|
note|-n Add a note entry
|
||||||
folder|-f Add a new folder for entries
|
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 1:" + core.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 2:" + core.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 3:" + core.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 4:" + core.AnsiReset + " Using \"add\", \"edit\", or \"copy\" without specifying an option (field) will default to \"password\"\n\n")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HelpAdd() {
|
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:
|
add:
|
||||||
password|-pw|<blank> Add a password entry
|
password|-pw|<blank> Add a password entry
|
||||||
note|-n Add a note entry
|
note|-n Add a note entry
|
||||||
@@ -71,9 +71,9 @@ func HelpAdd() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HelpEdit() {
|
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:
|
edit:
|
||||||
password|-pw|<blank> Change the password in an entry
|
password|-pw|<blank> Change the password in an entry
|
||||||
username|-u Change the username in an entry
|
username|-u Change the username in an entry
|
||||||
@@ -85,9 +85,9 @@ func HelpEdit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func HelpCopy() {
|
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:
|
copy:
|
||||||
password|-pw|<blank> Copy the password in an entry to your clipboard
|
password|-pw|<blank> Copy the password in an entry to your clipboard
|
||||||
username|-u Copy the username 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() {
|
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:
|
gen:
|
||||||
update|-u Generate a password for an existing entry
|
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)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MITLicense() {
|
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
|
Permission is hereby granted, free of charge, to any
|
||||||
person obtaining a copy of this software and associated
|
person obtaining a copy of this software and associated
|
||||||
@@ -141,18 +141,18 @@ func Version() {
|
|||||||
MITLicense()
|
MITLicense()
|
||||||
fmt.Print("\n\n MUTN is a simple, self-hosted,\n SSH-synchronized password manager based on libmutton\n\n" +
|
fmt.Print("\n\n MUTN is a simple, self-hosted,\n SSH-synchronized password manager based on libmutton\n\n" +
|
||||||
" .. ..\n" +
|
" .. ..\n" +
|
||||||
" /()\\''.''. " + ansiVersionMeat + "♥♥♥♥" + backend.AnsiReset + " .''.''/()\\ _)\n" +
|
" /()\\''.''. " + ansiVersionMeat + "♥♥♥♥" + core.AnsiReset + " .''.''/()\\ _)\n" +
|
||||||
" _. : * " + ansiVersionMeat + "♥♥♥♥♥♥ ♥♥♥♥♥♥♥♥" + backend.AnsiReset + " * : <[◎]|_|=\n" +
|
" _. : * " + ansiVersionMeat + "♥♥♥♥♥♥ ♥♥♥♥♥♥♥♥" + core.AnsiReset + " * : <[◎]|_|=\n" +
|
||||||
" }-}-*] `..'..' " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥♥♥♥♥" + backend.AnsiReset + " `..'..' |\n" +
|
" }-}-*] `..'..' " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥♥♥♥♥" + core.AnsiReset + " `..'..' |\n" +
|
||||||
" ◎-◎ // \\\\ " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥" + backend.AnsiReset + " // \\\\ /|\\\n" +
|
" ◎-◎ // \\\\ " + ansiVersionMeat + "♥♥♥♥♥♥♥♥♥" + core.AnsiReset + " // \\\\ /|\\\n" +
|
||||||
ansiVersionOutline + "<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" +
|
ansiVersionOutline + "<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" +
|
||||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " MUTN Version " + backend.LibmuttonVersion + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " MUTN Version " + core.LibmuttonVersion + " " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " The Tripe Transmission Update " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " The Tripe Transmission Update " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " Copyright (c) 2024 Randall Winkhart " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " Copyright (c) 2024 Randall Winkhart " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"\\" + ansiBlackOnWhite + " " + backend.AnsiReset + ansiVersionOutline + "/\n" +
|
"\\" + ansiBlackOnWhite + " " + core.AnsiReset + ansiVersionOutline + "/\n" +
|
||||||
"<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" + backend.AnsiReset +
|
"<><><><><><><><><><><><><><>-<><><><><><><><><><><><><><>\n" + core.AnsiReset +
|
||||||
"\n For more information, see:\n\n" +
|
"\n For more information, see:\n\n" +
|
||||||
" https://github.com/rwinkhart/MUTN\n" +
|
" https://github.com/rwinkhart/MUTN\n" +
|
||||||
" https://github.com/rwinkhart/libmutton\n\n")
|
" https://github.com/rwinkhart/libmutton\n\n")
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/rwinkhart/MUTN/src/backend"
|
"github.com/rwinkhart/libmutton/core"
|
||||||
"golang.org/x/crypto/ssh/terminal"
|
"golang.org/x/term"
|
||||||
)
|
)
|
||||||
|
|
||||||
// input prompts the user for input and returns the input as a string
|
// 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
|
// inputHidden prompts the user for input and returns the input as a string, hiding the input from the terminal
|
||||||
func inputHidden(prompt string) string {
|
func inputHidden(prompt string) string {
|
||||||
fmt.Print("\n" + prompt + " ")
|
fmt.Print("\n" + prompt + " ")
|
||||||
byteInput, _ := terminal.ReadPassword(int(os.Stdin.Fd()))
|
byteInput, _ := term.ReadPassword(int(os.Stdin.Fd()))
|
||||||
password := string(byteInput)
|
password := string(byteInput)
|
||||||
fmt.Println()
|
fmt.Println()
|
||||||
return password
|
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)
|
// writeEntryCLI writes an entry to targetLocation and previews it (errors if no data is supplied)
|
||||||
func writeEntryCLI(targetLocation string, unencryptedEntry []string, hideSecrets, verifyEntryDoesNotExist bool) {
|
func writeEntryCLI(targetLocation string, unencryptedEntry []string, hideSecrets, verifyEntryDoesNotExist bool) {
|
||||||
if backend.EntryIsNotEmpty(unencryptedEntry) {
|
if core.EntryIsNotEmpty(unencryptedEntry) {
|
||||||
// write the entry to the target location
|
// write the entry to the target location
|
||||||
backend.WriteEntry(targetLocation, unencryptedEntry, verifyEntryDoesNotExist)
|
core.WriteEntry(targetLocation, unencryptedEntry, verifyEntryDoesNotExist)
|
||||||
// preview the entry
|
// preview the entry
|
||||||
fmt.Println(AnsiBold + "\nEntry Preview:" + backend.AnsiReset)
|
fmt.Println(AnsiBold + "\nEntry Preview:" + core.AnsiReset)
|
||||||
EntryReader(unencryptedEntry, hideSecrets, true)
|
EntryReader(unencryptedEntry, hideSecrets, true)
|
||||||
} else {
|
} 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)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// expandPathWithHome, given a path (as a string) containing "~", returns the path with "~" expanded to the user's home directory
|
// expandPathWithHome, given a path (as a string) containing "~", returns the path with "~" expanded to the user's home directory
|
||||||
func expandPathWithHome(path string) string {
|
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