mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-09-05 16:47:20 -04:00
Move username to top of copy menu; send user to copy menu after creating/editing an entry; allow copying old password from copy menu
This commit is contained in:
@@ -5,7 +5,7 @@ go 1.25.4
|
|||||||
require (
|
require (
|
||||||
github.com/charmbracelet/glamour v0.7.0
|
github.com/charmbracelet/glamour v0.7.0
|
||||||
github.com/rwinkhart/go-boilerplate v0.1.1-0.20251110055016-10ee4f91fcb6
|
github.com/rwinkhart/go-boilerplate v0.1.1-0.20251110055016-10ee4f91fcb6
|
||||||
github.com/rwinkhart/libmutton v0.4.3-0.20251123083838-5dc3a5576d67
|
github.com/rwinkhart/libmutton v0.4.3-0.20251123183956-95a877d0b300
|
||||||
golang.org/x/term v0.37.0
|
golang.org/x/term v0.37.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ github.com/rwinkhart/go-highlite v0.1.1 h1:9TxbRhYVfD/3YaEgNk1BtEiZ0t8/5mxDUZqNM
|
|||||||
github.com/rwinkhart/go-highlite v0.1.1/go.mod h1:mWLMtCWcyV0BG4NeyPyAUGMjPvI0ds6vXmUq89QwBFA=
|
github.com/rwinkhart/go-highlite v0.1.1/go.mod h1:mWLMtCWcyV0BG4NeyPyAUGMjPvI0ds6vXmUq89QwBFA=
|
||||||
github.com/rwinkhart/go-winio v0.1.0 h1:b72agLW+dETGmhR3VbcbwnStfgKfc5AfgJOXBJDkaHg=
|
github.com/rwinkhart/go-winio v0.1.0 h1:b72agLW+dETGmhR3VbcbwnStfgKfc5AfgJOXBJDkaHg=
|
||||||
github.com/rwinkhart/go-winio v0.1.0/go.mod h1:ZWa7ssZJT30CCDGJ7fk/2SBTq9BIQrrVjrcss0UW2s0=
|
github.com/rwinkhart/go-winio v0.1.0/go.mod h1:ZWa7ssZJT30CCDGJ7fk/2SBTq9BIQrrVjrcss0UW2s0=
|
||||||
github.com/rwinkhart/libmutton v0.4.3-0.20251123083838-5dc3a5576d67 h1:lx+JG1J6vAMkYVaCjtDH79+CWYbGQWBuZwc52Umke0s=
|
github.com/rwinkhart/libmutton v0.4.3-0.20251123183956-95a877d0b300 h1:zeFKfGRyFaKgbfEsyu9rfSz2yG5OvaekGFran0wyT1M=
|
||||||
github.com/rwinkhart/libmutton v0.4.3-0.20251123083838-5dc3a5576d67/go.mod h1:QFyn9hvMbSfcfXnUl139Cr/ZxR7DARpsMtynOk3CziY=
|
github.com/rwinkhart/libmutton v0.4.3-0.20251123183956-95a877d0b300/go.mod h1:QFyn9hvMbSfcfXnUl139Cr/ZxR7DARpsMtynOk3CziY=
|
||||||
github.com/rwinkhart/peercred-mini v0.1.2 h1:4cGWDbv0whvLeVvbUdx84V/9p+2fS+DEXgrA1KxlRFo=
|
github.com/rwinkhart/peercred-mini v0.1.2 h1:4cGWDbv0whvLeVvbUdx84V/9p+2fS+DEXgrA1KxlRFo=
|
||||||
github.com/rwinkhart/peercred-mini v0.1.2/go.mod h1:LLHG7YshHEpbpJJP+Il9nx2dnGj5O3VGE32rWmflj0c=
|
github.com/rwinkhart/peercred-mini v0.1.2/go.mod h1:LLHG7YshHEpbpJJP+Il9nx2dnGj5O3VGE32rWmflj0c=
|
||||||
github.com/rwinkhart/rcw v0.2.3 h1:g1rVaspZnZM8nWupeSdVO827di4ORMZnczw6iXyo01Y=
|
github.com/rwinkhart/rcw v0.2.3 h1:g1rVaspZnZM8nWupeSdVO827di4ORMZnczw6iXyo01Y=
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ func main() {
|
|||||||
case "note", "-n":
|
case "note", "-n":
|
||||||
field = 4
|
field = 4
|
||||||
case "menu", "-m":
|
case "menu", "-m":
|
||||||
cli.CopyMenu(realPath)
|
cli.CopyMenu(realPath, nil, "")
|
||||||
default:
|
default:
|
||||||
cli.HelpCopy()
|
cli.HelpCopy()
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -44,9 +44,9 @@ func AddEntry(realPath string, hideSecrets bool, entryType uint8) {
|
|||||||
|
|
||||||
// write and preview the new entry
|
// write and preview the new entry
|
||||||
if password != "" {
|
if password != "" {
|
||||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true)
|
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true, "")
|
||||||
} else {
|
} else {
|
||||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, false)
|
writeEntryCLI(realPath, decryptedEntry, hideSecrets, false, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-17
@@ -16,25 +16,27 @@ import (
|
|||||||
|
|
||||||
// CopyMenu decrypts an entry and allows the user to
|
// CopyMenu decrypts an entry and allows the user to
|
||||||
// interactively copy fields without having to re-decrypt each time.
|
// interactively copy fields without having to re-decrypt each time.
|
||||||
func CopyMenu(realPath string) {
|
// Only one of realPath or decSlice should be provided.
|
||||||
// decrypt entry
|
func CopyMenu(realPath string, decSlice []string, oldPassword string) {
|
||||||
decSlice, err := crypt.DecryptFileToSlice(realPath)
|
var err error
|
||||||
if err != nil {
|
if decSlice == nil {
|
||||||
other.PrintError("Failed to decrypt entry: "+err.Error(), global.ErrorDecryption)
|
// decrypt entry
|
||||||
|
decSlice, err = crypt.DecryptFileToSlice(realPath)
|
||||||
|
if err != nil {
|
||||||
|
other.PrintError("Failed to decrypt entry: "+err.Error(), global.ErrorDecryption)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine populated fields in entry
|
// determine populated fields in entry
|
||||||
fieldIndexToString := map[int]string{
|
var fieldStrings = []string{"Username", "Password", "TOTP Code", "URL", "Note (first line)"}
|
||||||
0: "Password",
|
var indices = []int{1, 0, 2, 3, 4}
|
||||||
1: "Username",
|
|
||||||
2: "TOTP Code",
|
|
||||||
3: "URL",
|
|
||||||
4: "Note (first line)",
|
|
||||||
}
|
|
||||||
var fields []string
|
var fields []string
|
||||||
for i, _ := range decSlice[:min(5, len(decSlice))] {
|
for i := range indices {
|
||||||
if decSlice[i] != "" {
|
if len(decSlice) > indices[i] && decSlice[indices[i]] != "" {
|
||||||
fields = append(fields, fieldIndexToString[i])
|
fields = append(fields, fieldStrings[i])
|
||||||
|
if indices[i] == 0 && oldPassword != "" {
|
||||||
|
fields = append(fields, "Old Password")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,10 +54,16 @@ func CopyMenu(realPath string) {
|
|||||||
fmt.Println()
|
fmt.Println()
|
||||||
choice := front.InputMenuGen("Field to copy:", fields)
|
choice := front.InputMenuGen("Field to copy:", fields)
|
||||||
switch fields[choice-1] {
|
switch fields[choice-1] {
|
||||||
case "Password":
|
|
||||||
choice = 0
|
|
||||||
case "Username":
|
case "Username":
|
||||||
choice = 1
|
choice = 1
|
||||||
|
case "Password":
|
||||||
|
choice = 0
|
||||||
|
case "Old Password":
|
||||||
|
err := clip.CopyString(false, oldPassword)
|
||||||
|
if err != nil {
|
||||||
|
other.PrintError("Failed to copy old password to clipboard: "+err.Error(), global.ErrorClipboard)
|
||||||
|
}
|
||||||
|
continue
|
||||||
case "TOTP Code":
|
case "TOTP Code":
|
||||||
choice = 2
|
choice = 2
|
||||||
case "URL":
|
case "URL":
|
||||||
|
|||||||
+6
-3
@@ -35,8 +35,10 @@ func EditEntryField(realPath string, hideSecrets bool, field int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// edit the field
|
// edit the field
|
||||||
|
var oldPassword string
|
||||||
switch field {
|
switch field {
|
||||||
case 0:
|
case 0:
|
||||||
|
oldPassword = decryptedEntry[field]
|
||||||
decryptedEntry[field] = string(front.InputHidden("Password:"))
|
decryptedEntry[field] = string(front.InputHidden("Password:"))
|
||||||
case 1:
|
case 1:
|
||||||
decryptedEntry[field] = front.Input("Username:")
|
decryptedEntry[field] = front.Input("Username:")
|
||||||
@@ -59,9 +61,9 @@ func EditEntryField(realPath string, hideSecrets bool, field int) {
|
|||||||
|
|
||||||
// write and preview the modified entry
|
// write and preview the modified entry
|
||||||
if field == 0 {
|
if field == 0 {
|
||||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true)
|
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true, oldPassword)
|
||||||
} else {
|
} else {
|
||||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, false)
|
writeEntryCLI(realPath, decryptedEntry, hideSecrets, false, oldPassword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,10 +76,11 @@ func GenUpdate(realPath string, hideSecrets bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generate a new password
|
// generate a new password
|
||||||
|
oldPassword := decryptedEntry[0]
|
||||||
decryptedEntry[0] = inputPasswordGen()
|
decryptedEntry[0] = inputPasswordGen()
|
||||||
|
|
||||||
// write and preview the modified entry
|
// write and preview the modified entry
|
||||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true)
|
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true, oldPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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).
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/charmbracelet/glamour"
|
"github.com/charmbracelet/glamour"
|
||||||
@@ -78,8 +77,6 @@ fieldLoop:
|
|||||||
other.PrintError("Failed to sync entries: "+err.Error(), global.ErrorSyncProcess)
|
other.PrintError("Failed to sync entries: "+err.Error(), global.ErrorSyncProcess)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EntryReaderDecrypt is a wrapper for EntryReader that first decrypts an RCW-wrapped file before sending it to EntryReader.
|
// EntryReaderDecrypt is a wrapper for EntryReader that first decrypts an RCW-wrapped file before sending it to EntryReader.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/rwinkhart/go-boilerplate/back"
|
"github.com/rwinkhart/go-boilerplate/back"
|
||||||
"github.com/rwinkhart/go-boilerplate/front"
|
"github.com/rwinkhart/go-boilerplate/front"
|
||||||
@@ -28,7 +29,7 @@ func inputPasswordGen() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// writeEntryCLI writes an entry to realPath and previews it (errors if no data is supplied).
|
// writeEntryCLI writes an entry to realPath and previews it (errors if no data is supplied).
|
||||||
func writeEntryCLI(realPath string, decSlice []string, hideSecrets bool, passwordIsNew bool) {
|
func writeEntryCLI(realPath string, decSlice []string, hideSecrets bool, passwordIsNew bool, oldPassword string) {
|
||||||
if core.EntryIsNotEmpty(decSlice) {
|
if core.EntryIsNotEmpty(decSlice) {
|
||||||
err := core.WriteEntry(realPath, decSlice, passwordIsNew)
|
err := core.WriteEntry(realPath, decSlice, passwordIsNew)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -37,6 +38,8 @@ func writeEntryCLI(realPath string, decSlice []string, hideSecrets bool, passwor
|
|||||||
// preview the entry
|
// preview the entry
|
||||||
fmt.Println(back.AnsiBold + "\nEntry Preview:" + back.AnsiReset)
|
fmt.Println(back.AnsiBold + "\nEntry Preview:" + back.AnsiReset)
|
||||||
EntryReader(decSlice, hideSecrets, true)
|
EntryReader(decSlice, hideSecrets, true)
|
||||||
|
CopyMenu("", decSlice, oldPassword)
|
||||||
|
os.Exit(0)
|
||||||
} else {
|
} else {
|
||||||
other.PrintError("No data supplied for entry", back.ErrorTargetNotFound)
|
other.PrintError("No data supplied for entry", back.ErrorTargetNotFound)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user