mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-09-03 23:57:23 -04:00
Move TOTP secrets to a dedicated entry field (breaks sshyp entry format compatibility)
This commit is contained in:
@@ -31,7 +31,7 @@ _mutnCompletions() {
|
|||||||
while read -r; do COMPREPLY+=( "$REPLY" ); done < <( compgen -W "password username totp url note" -- "$cur" )
|
while read -r; do COMPREPLY+=( "$REPLY" ); done < <( compgen -W "password username totp url note" -- "$cur" )
|
||||||
;;
|
;;
|
||||||
edit )
|
edit )
|
||||||
while read -r; do COMPREPLY+=( "$REPLY" ); done < <( compgen -W "password username url note rename" -- "$cur" )
|
while read -r; do COMPREPLY+=( "$REPLY" ); done < <( compgen -W "password username totp url note rename" -- "$cur" )
|
||||||
;;
|
;;
|
||||||
gen )
|
gen )
|
||||||
while read -r; do COMPREPLY+=( "$REPLY" ); done < <( compgen -W "update" -- "$cur" )
|
while read -r; do COMPREPLY+=( "$REPLY" ); done < <( compgen -W "update" -- "$cur" )
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ function cliMUTNEntryCompleter {
|
|||||||
(Get-ChildItem -Path $mutnPath -Recurse -File).FullName.Substring($mutnPath.Length) -replace '\\', '/' -replace ' ', '` '
|
(Get-ChildItem -Path $mutnPath -Recurse -File).FullName.Substring($mutnPath.Length) -replace '\\', '/' -replace ' ', '` '
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
$trimmedPaths = $null # If any errors occur (especially, "You cannot call a method on a null-valued expression", set $trimmedPaths to $null
|
$trimmedPaths = $null # if any errors occur (especially, "You cannot call a method on a null-valued expression", set $trimmedPaths to $null
|
||||||
}
|
}
|
||||||
if ($null -eq $trimmedPaths) { # If no entries are found, add 'help' to $trimmedPaths
|
if ($null -eq $trimmedPaths) { # if no entries are found, add 'help' to $trimmedPaths
|
||||||
$trimmedPaths = 'help'
|
$trimmedPaths = 'help'
|
||||||
}
|
}
|
||||||
$trimmedPaths | Where-Object { $_ -like "$wordToComplete*" }
|
$trimmedPaths | Where-Object { $_ -like "$wordToComplete*" }
|
||||||
@@ -21,7 +21,7 @@ function cliMUTNOptionCompleter {
|
|||||||
$possibleValues = @{
|
$possibleValues = @{
|
||||||
add = @('password', 'note', 'folder')
|
add = @('password', 'note', 'folder')
|
||||||
copy = @('password', 'username', 'totp', 'url', 'note')
|
copy = @('password', 'username', 'totp', 'url', 'note')
|
||||||
edit = @('password', 'username', 'url', 'note', 'rename')
|
edit = @('password', 'username', 'totp', 'url', 'note', 'rename')
|
||||||
gen = @('update')
|
gen = @('update')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ case ${words[-2]} in
|
|||||||
compadd {password,username,totp,url,note}
|
compadd {password,username,totp,url,note}
|
||||||
;;
|
;;
|
||||||
edit )
|
edit )
|
||||||
compadd {password,username,url,note,rename}
|
compadd {password,username,totp,url,note,rename}
|
||||||
;;
|
;;
|
||||||
gen )
|
gen )
|
||||||
compadd update
|
compadd update
|
||||||
|
|||||||
@@ -72,13 +72,13 @@ func main() {
|
|||||||
field = 0
|
field = 0
|
||||||
case "username", "-u":
|
case "username", "-u":
|
||||||
field = 1
|
field = 1
|
||||||
case "url", "-l":
|
|
||||||
field = 2
|
|
||||||
case "note", "-n":
|
|
||||||
field = 3
|
|
||||||
case "totp", "-t":
|
case "totp", "-t":
|
||||||
fmt.Println("TOTP code will be copied to clipboard - your clipboard will be kept up to date with the current TOTP code until this process is closed")
|
fmt.Println("TOTP code will be copied to clipboard - your clipboard will be kept up to date with the current TOTP code until this process is closed")
|
||||||
field = 5 // TODO Update field after removed from notes (breaking sshyp entry compatibility)
|
field = 2
|
||||||
|
case "url", "-l":
|
||||||
|
field = 3
|
||||||
|
case "note", "-n":
|
||||||
|
field = 4
|
||||||
default:
|
default:
|
||||||
cli.HelpCopy()
|
cli.HelpCopy()
|
||||||
}
|
}
|
||||||
@@ -90,10 +90,12 @@ func main() {
|
|||||||
field = 0
|
field = 0
|
||||||
case "username", "-u":
|
case "username", "-u":
|
||||||
field = 1
|
field = 1
|
||||||
case "url", "-l":
|
case "totp", "-t":
|
||||||
field = 2
|
field = 2
|
||||||
case "note", "-n":
|
case "url", "-l":
|
||||||
field = 3
|
field = 3
|
||||||
|
case "note", "-n":
|
||||||
|
field = 4
|
||||||
case "rename", "-r":
|
case "rename", "-r":
|
||||||
cli.RenameCli(targetLocation)
|
cli.RenameCli(targetLocation)
|
||||||
default:
|
default:
|
||||||
|
|||||||
+4
-4
@@ -26,17 +26,17 @@ func CopyArgument(targetLocation string, field int, executableName string) {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if field != 5 { // TODO Update field after removed from notes (breaking sshyp entry compatibility)
|
if field != 2 {
|
||||||
copySubject = decryptedEntry[field]
|
copySubject = decryptedEntry[field]
|
||||||
} else { // TOTP mode
|
} else { // TOTP mode
|
||||||
var secret string // stores secret for TOTP generation
|
var secret string // stores secret for TOTP generation
|
||||||
var forSteam bool // indicates whether to generate TOTP in Steam format
|
var forSteam bool // indicates whether to generate TOTP in Steam format
|
||||||
|
|
||||||
if strings.HasPrefix(decryptedEntry[5], "steam@") {
|
if strings.HasPrefix(decryptedEntry[2], "steam@") {
|
||||||
secret = decryptedEntry[5][6:]
|
secret = decryptedEntry[2][6:]
|
||||||
forSteam = true
|
forSteam = true
|
||||||
} else {
|
} else {
|
||||||
secret = decryptedEntry[5]
|
secret = decryptedEntry[2]
|
||||||
}
|
}
|
||||||
|
|
||||||
for { // keep field copied to clipboard, refresh on 30-second intervals
|
for { // keep field copied to clipboard, refresh on 30-second intervals
|
||||||
|
|||||||
+1
-1
@@ -36,7 +36,7 @@ func Rename(oldLocation string, newLocation string) {
|
|||||||
fmt.Println(AnsiError + "Failed to rename - does the target containing directory exists?" + AnsiReset)
|
fmt.Println(AnsiError + "Failed to rename - does the target containing directory exists?" + AnsiReset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO If in online mode, rename oldLocation to newLocation on the server
|
// TODO implement synced renaming
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// TODO GPG support is a temporary feature - it will be replaced with a different encryption scheme in the future
|
// TODO GPG support is a temporary feature - it will be replaced with a different encryption scheme in the future
|
||||||
// TODO These functions may continue to exist after that point, but consider them deprecated
|
// These functions may continue to exist after that point, but consider them deprecated
|
||||||
|
|
||||||
// DecryptGPG decrypts a GPG-encrypted file and returns the contents as a slice of (trimmed) strings
|
// DecryptGPG decrypts a GPG-encrypted file and returns the contents as a slice of (trimmed) strings
|
||||||
func DecryptGPG(targetLocation string) []string {
|
func DecryptGPG(targetLocation string) []string {
|
||||||
|
|||||||
+4
-3
@@ -28,16 +28,17 @@ func AddEntry(targetLocation string, hidePassword bool, entryType uint8) {
|
|||||||
password = backend.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
totp := inputHidden("TOTP secret:")
|
||||||
url := input("URL:")
|
url := input("URL:")
|
||||||
if inputBinary("Add a note to this entry?") {
|
if inputBinary("Add a note to this entry?") {
|
||||||
note, _ := editNote([]string{})
|
note, _ := editNote([]string{})
|
||||||
unencryptedEntry = append([]string{password, username, url}, note...)
|
unencryptedEntry = append([]string{password, username, totp, url}, note...)
|
||||||
} else {
|
} else {
|
||||||
unencryptedEntry = []string{password, username, url}
|
unencryptedEntry = []string{password, username, totp, url}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
note, _ := editNote([]string{})
|
note, _ := editNote([]string{})
|
||||||
unencryptedEntry = append([]string{"", "", ""}, note...)
|
unencryptedEntry = append([]string{"", "", "", ""}, note...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// write and preview the new entry
|
// write and preview the new entry
|
||||||
|
|||||||
+5
-3
@@ -34,11 +34,13 @@ func EditEntryField(targetLocation string, hidePassword bool, field int) {
|
|||||||
case 1:
|
case 1:
|
||||||
unencryptedEntry[field] = input("Username:")
|
unencryptedEntry[field] = input("Username:")
|
||||||
case 2:
|
case 2:
|
||||||
|
unencryptedEntry[field] = inputHidden("TOTP secret:")
|
||||||
|
case 3:
|
||||||
unencryptedEntry[field] = input("URL:")
|
unencryptedEntry[field] = input("URL:")
|
||||||
case 3: // edit notes fields
|
case 4: // edit notes fields
|
||||||
// store note and non-note data separately
|
// store note and non-note data separately
|
||||||
nonNoteData := unencryptedEntry[:3]
|
nonNoteData := unencryptedEntry[:4]
|
||||||
noteData := unencryptedEntry[3:]
|
noteData := unencryptedEntry[4:]
|
||||||
|
|
||||||
// edit the note
|
// edit the note
|
||||||
editedNote, noteEdited := editNote(noteData)
|
editedNote, noteEdited := editNote(noteData)
|
||||||
|
|||||||
+12
-3
@@ -34,17 +34,26 @@ func EntryReader(decryptedEntry []string, hidePassword bool, syncEnabled bool) {
|
|||||||
fmt.Print(ansiDirectoryHeader + "Username:" + backend.AnsiReset + "\n" + decryptedEntry[1] + "\n\n")
|
fmt.Print(ansiDirectoryHeader + "Username:" + backend.AnsiReset + "\n" + decryptedEntry[1] + "\n\n")
|
||||||
}
|
}
|
||||||
case 2:
|
case 2:
|
||||||
// if the third field (url) is not empty, print it
|
// if the third field (TOTP secret) is not empty, print it
|
||||||
if decryptedEntry[2] != "" {
|
if decryptedEntry[2] != "" {
|
||||||
fmt.Print(ansiDirectoryHeader + "URL:" + backend.AnsiReset + "\n" + decryptedEntry[2] + "\n\n")
|
if !hidePassword {
|
||||||
|
fmt.Print(ansiDirectoryHeader + "TOTP Secret:" + backend.AnsiReset + "\n" + ansiShownPassword + decryptedEntry[2] + backend.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")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case 3:
|
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")
|
||||||
|
}
|
||||||
|
case 4:
|
||||||
// print the notes header
|
// print the notes header
|
||||||
fmt.Println(ansiDirectoryHeader + "Notes:" + backend.AnsiReset)
|
fmt.Println(ansiDirectoryHeader + "Notes:" + backend.AnsiReset)
|
||||||
|
|
||||||
// combine remaining fields into a single string (for markdown rendering)
|
// combine remaining fields into a single string (for markdown rendering)
|
||||||
var markdownNotes []string
|
var markdownNotes []string
|
||||||
for field := 3; field < len(decryptedEntry); field++ {
|
for field := 4; field < len(decryptedEntry); field++ {
|
||||||
markdownNotes = append(markdownNotes, decryptedEntry[field])
|
markdownNotes = append(markdownNotes, decryptedEntry[field])
|
||||||
}
|
}
|
||||||
r, _ := glamour.NewTermRenderer(glamour.WithStylesFromJSONBytes(glamourStyle()), glamour.WithPreservedNewLines(), glamour.WithWordWrap(width))
|
r, _ := glamour.NewTermRenderer(glamour.WithStylesFromJSONBytes(glamourStyle()), glamour.WithPreservedNewLines(), glamour.WithWordWrap(width))
|
||||||
|
|||||||
@@ -37,12 +37,13 @@ This program comes with absolutely no warranty; type "mutn version" for details.
|
|||||||
password|-pw|<blank> Copy the password of an entry to your clipboard
|
password|-pw|<blank> Copy the password of an entry to your clipboard
|
||||||
username|-u Copy the username of an entry to your clipboard
|
username|-u Copy the username of an entry to your clipboard
|
||||||
totp|-t Copy the TOTP code of an entry to your clipboard
|
totp|-t Copy the TOTP code of an entry to your clipboard
|
||||||
url|-l Copy the url of an entry to your clipboard
|
url|-l Copy the URL of an entry to your clipboard
|
||||||
note|-n Copy the note of an entry to your clipboard
|
note|-n Copy the note of an entry to your clipboard
|
||||||
edit:
|
edit:
|
||||||
password|-pw|<blank> Change the password of an entry
|
password|-pw|<blank> Change the password of an entry
|
||||||
username|-u Change the username of an entry
|
username|-u Change the username of an entry
|
||||||
url|-l Change the url attached to an entry
|
totp|-t Change the TOTP secret of an entry
|
||||||
|
url|-l Change the URL attached to an entry
|
||||||
note|-n Change the note attached to an entry
|
note|-n Change the note attached to an entry
|
||||||
rename|-r Rename or relocate an entry
|
rename|-r Rename or relocate an entry
|
||||||
gen:
|
gen:
|
||||||
@@ -77,7 +78,8 @@ func HelpEdit() {
|
|||||||
edit:
|
edit:
|
||||||
password|-pw|<blank> Change the password of an entry
|
password|-pw|<blank> Change the password of an entry
|
||||||
username|-u Change the username of an entry
|
username|-u Change the username of an entry
|
||||||
url|-l Change the url attached to an entry
|
totp|-t Change the TOTP secret of an entry
|
||||||
|
url|-l Change the URL attached to an entry
|
||||||
note|-n Change the note attached to an entry
|
note|-n Change the note attached to an entry
|
||||||
rename|-r Rename or relocate an entry` + "\n\n")
|
rename|-r Rename or relocate an entry` + "\n\n")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
@@ -91,7 +93,7 @@ func HelpCopy() {
|
|||||||
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
|
||||||
totp|-t Copy the TOTP code of an entry to your clipboard
|
totp|-t Copy the TOTP code of an entry to your clipboard
|
||||||
url|-l Copy the url in an entry to your clipboard
|
url|-l Copy the URL in an entry to your clipboard
|
||||||
note|-n Copy the first note line in an entry to your clipboard` + "\n\n")
|
note|-n Copy the first note line in an entry to your clipboard` + "\n\n")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user