mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-08-28 04:46:41 -04:00
Enable entry password aging (sync with latest libmutton development version)
This commit is contained in:
+1
-1
@@ -13,7 +13,7 @@ var (
|
||||
)
|
||||
|
||||
const (
|
||||
MUTNVersion = "0.3.A" // untagged releases feature a letter suffix corresponding to the eventual release version, e.g "0.B.0" -> "0.2.0", "0.2.A" -> "0.2.1"
|
||||
MUTNVersion = "0.D.0" // untagged releases feature a letter suffix corresponding to the eventual release version, e.g "0.B.0" -> "0.2.0", "0.2.A" -> "0.2.1"
|
||||
|
||||
ansiBlackOnWhite = "\033[38;5;0;48;5;15m"
|
||||
)
|
||||
|
||||
+11
-6
@@ -7,22 +7,22 @@ import (
|
||||
"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 realPath by taking user input via CLI prompts.
|
||||
// Requires: entryType (0 = standard password entry, 1 = auto-generated password entry, 2 = note-only entry).
|
||||
func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) {
|
||||
// ensure targetLocation is valid
|
||||
_, err := core.EntryAddPrecheck(targetLocation)
|
||||
func AddEntry(realPath string, hideSecrets bool, entryType uint8) {
|
||||
// ensure realPath is valid
|
||||
_, err := core.EntryAddPrecheck(realPath)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to add entry: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
|
||||
var decryptedEntry []string
|
||||
|
||||
var password string
|
||||
if entryType < 2 {
|
||||
username := front.Input("Username:")
|
||||
|
||||
// determine whether to generate the password
|
||||
var password string
|
||||
if entryType == 0 {
|
||||
password = string(front.InputHidden("Password:"))
|
||||
} else {
|
||||
@@ -43,5 +43,10 @@ func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) {
|
||||
}
|
||||
|
||||
// write and preview the new entry
|
||||
writeEntryCLI(targetLocation, decryptedEntry, hideSecrets)
|
||||
if password != "" {
|
||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true)
|
||||
} else {
|
||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -16,9 +16,9 @@ import (
|
||||
|
||||
// CopyMenu decrypts an entry and allows the user to
|
||||
// interactively copy fields without having to re-decrypt each time.
|
||||
func CopyMenu(targetLocation string) {
|
||||
func CopyMenu(realPath string) {
|
||||
// decrypt entry
|
||||
decSlice, err := crypt.DecryptFileToSlice(targetLocation)
|
||||
decSlice, err := crypt.DecryptFileToSlice(realPath)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to decrypt entry: "+err.Error(), global.ErrorDecryption)
|
||||
}
|
||||
|
||||
+15
-11
@@ -15,10 +15,10 @@ import (
|
||||
)
|
||||
|
||||
// RenameCli renames an entry at oldLocationIncomplete to a new location (user input) on both the client and the server.
|
||||
func RenameCli(oldLocationIncomplete string) {
|
||||
func RenameCli(oldVanityPath string) {
|
||||
// prompt user for new location and rename
|
||||
newLocationIncomplete := front.Input("New location:")
|
||||
err := syncclient.RenameRemoteFromClient(oldLocationIncomplete, newLocationIncomplete)
|
||||
newVanityPath := front.Input("New location:")
|
||||
err := syncclient.RenameRemoteFromClient(oldVanityPath, newVanityPath)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to rename entry: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
@@ -26,10 +26,10 @@ func RenameCli(oldLocationIncomplete string) {
|
||||
// exit is done from sync.RenameRemoteFromClient
|
||||
}
|
||||
|
||||
// EditEntryField edits a field of an entry at targetLocation (user input).
|
||||
func EditEntryField(targetLocation string, hideSecrets bool, field int) {
|
||||
// EditEntryField edits a field of an entry at realPath (user input).
|
||||
func EditEntryField(realPath string, hideSecrets bool, field int) {
|
||||
// fetch old entry data (with all required lines present)
|
||||
decryptedEntry, err := core.GetOldEntryData(targetLocation, field)
|
||||
decryptedEntry, err := core.GetOldEntryData(realPath, field)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to fetch entry data: "+err.Error(), back.ErrorRead)
|
||||
}
|
||||
@@ -58,13 +58,17 @@ func EditEntryField(targetLocation string, hideSecrets bool, field int) {
|
||||
}
|
||||
|
||||
// write and preview the modified entry
|
||||
writeEntryCLI(targetLocation, decryptedEntry, hideSecrets)
|
||||
if field == 0 {
|
||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true)
|
||||
} else {
|
||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, false)
|
||||
}
|
||||
}
|
||||
|
||||
// GenUpdate generates a new password for an entry at targetLocation (user input).
|
||||
func GenUpdate(targetLocation string, hideSecrets bool) {
|
||||
// GenUpdate generates a new password for an entry at realPath (user input).
|
||||
func GenUpdate(realPath string, hideSecrets bool) {
|
||||
// fetch old entry data
|
||||
decryptedEntry, err := core.GetOldEntryData(targetLocation, 0)
|
||||
decryptedEntry, err := core.GetOldEntryData(realPath, 0)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to fetch entry data: "+err.Error(), back.ErrorRead)
|
||||
}
|
||||
@@ -73,7 +77,7 @@ func GenUpdate(targetLocation string, hideSecrets bool) {
|
||||
decryptedEntry[0] = inputPasswordGen()
|
||||
|
||||
// write and preview the modified entry
|
||||
writeEntryCLI(targetLocation, decryptedEntry, hideSecrets)
|
||||
writeEntryCLI(realPath, decryptedEntry, hideSecrets, true)
|
||||
}
|
||||
|
||||
// editNote uses the user-specified text editor to edit an existing note (or create a new one if baseNote is empty).
|
||||
|
||||
+20
-3
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/age"
|
||||
"github.com/rwinkhart/libmutton/synccommon"
|
||||
)
|
||||
|
||||
@@ -47,7 +48,7 @@ func determineIndentation(skippedDirList []bool, dirList []string, currentDirInd
|
||||
}
|
||||
|
||||
// printFileEntry handles processing for printing file entries (determines color, wraps lines, and prints).
|
||||
func printFileEntry(entry string, lastSlash, charCounter, indent int, colorAlternator int8) (int, int8) {
|
||||
func printFileEntry(entry string, lastSlash, charCounter, indent int, colorAlternator int8, agingTimestamp int64) (int, int8) {
|
||||
// determine color to print fileEntryName (alternate each time function is run)
|
||||
var colorCode string
|
||||
if colorAlternator > 0 {
|
||||
@@ -57,6 +58,17 @@ func printFileEntry(entry string, lastSlash, charCounter, indent int, colorAlter
|
||||
}
|
||||
colorAlternator = -colorAlternator
|
||||
|
||||
// determine password aging dot
|
||||
var agingDot string
|
||||
switch age.TranslateAgeTimestamp(agingTimestamp) {
|
||||
case 1:
|
||||
agingDot = back.AnsiGreen + "⁍" + back.AnsiReset
|
||||
case 2:
|
||||
agingDot = back.AnsiWarning + "⁍" + back.AnsiReset
|
||||
case 3:
|
||||
agingDot = back.AnsiError + "⁍" + back.AnsiReset
|
||||
}
|
||||
|
||||
// trim the containing directory from the entry to determine fileEntryName
|
||||
fileEntryName := entry[lastSlash:]
|
||||
|
||||
@@ -72,7 +84,7 @@ func printFileEntry(entry string, lastSlash, charCounter, indent int, colorAlter
|
||||
}
|
||||
|
||||
// print fileEntryName to screen
|
||||
fmt.Printf("%s%s%s ", colorCode, fileEntryName, back.AnsiReset)
|
||||
fmt.Printf("%s%s%s%s ", agingDot, colorCode, fileEntryName, back.AnsiReset)
|
||||
|
||||
return charCounter, colorAlternator
|
||||
}
|
||||
@@ -83,6 +95,11 @@ func EntryListGen() {
|
||||
if err != nil {
|
||||
other.PrintError("Failed to generate entry list: "+err.Error(), back.ErrorRead)
|
||||
}
|
||||
var vanityPathsToTimestamps map[string]int64
|
||||
vanityPathsToTimestamps, err = synccommon.GetEntryAges()
|
||||
if err != nil {
|
||||
other.PrintError("Failed to retrieve entry aging data: "+err.Error(), back.ErrorRead)
|
||||
}
|
||||
|
||||
// print header bar w/total entry count
|
||||
fmt.Print("\n"+ansiBlackOnWhite, len(fileList), " libmutton entries:"+back.AnsiReset)
|
||||
@@ -134,7 +151,7 @@ func EntryListGen() {
|
||||
fmt.Printf("\n\n"+strings.Repeat(" ", indent*2)+ansiDirectoryHeader+"%s/"+back.AnsiReset+"\n", vanityDirectory)
|
||||
}
|
||||
|
||||
charCounter, colorAlternator = printFileEntry(file, lastSlash, charCounter, indent, colorAlternator)
|
||||
charCounter, colorAlternator = printFileEntry(file, lastSlash, charCounter, indent, colorAlternator, vanityPathsToTimestamps[file])
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -83,12 +83,12 @@ fieldLoop:
|
||||
}
|
||||
|
||||
// EntryReaderDecrypt is a wrapper for EntryReader that first decrypts an RCW-wrapped file before sending it to EntryReader.
|
||||
func EntryReaderDecrypt(targetLocation string, hideSecrets bool) {
|
||||
_, err := back.TargetIsFile(targetLocation, true)
|
||||
func EntryReaderDecrypt(realPath string, hideSecrets bool) {
|
||||
_, err := back.TargetIsFile(realPath, true)
|
||||
if err != nil { // if the location does not exist or is a directory...
|
||||
other.PrintError("Failed to verify target location: "+err.Error(), back.ErrorTargetNotFound)
|
||||
}
|
||||
decSlice, err := crypt.DecryptFileToSlice(targetLocation)
|
||||
decSlice, err := crypt.DecryptFileToSlice(realPath)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to decrypt entry: "+err.Error(), global.ErrorDecryption)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/front"
|
||||
@@ -28,17 +27,16 @@ func inputPasswordGen() string {
|
||||
return synccycles.StringGen(passLength, complexity, passCharset)
|
||||
}
|
||||
|
||||
// writeEntryCLI writes an entry to targetLocation and previews it (errors if no data is supplied).
|
||||
func writeEntryCLI(targetLocation string, decryptedEntry []string, hideSecrets bool) {
|
||||
if core.EntryIsNotEmpty(decryptedEntry) {
|
||||
// write the entry to the target location
|
||||
err := core.WriteEntry(targetLocation, []byte(strings.Join(decryptedEntry, "\n")))
|
||||
// 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) {
|
||||
if core.EntryIsNotEmpty(decSlice) {
|
||||
err := core.WriteEntry(realPath, decSlice, passwordIsNew)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to write entry: "+err.Error(), back.ErrorWrite)
|
||||
}
|
||||
// preview the entry
|
||||
fmt.Println(back.AnsiBold + "\nEntry Preview:" + back.AnsiReset)
|
||||
EntryReader(decryptedEntry, hideSecrets, true)
|
||||
EntryReader(decSlice, hideSecrets, true)
|
||||
} else {
|
||||
other.PrintError("No data supplied for entry", back.ErrorTargetNotFound)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user