mirror of
https://github.com/rwinkhart/MUTN.git
synced 2026-08-28 04:46:41 -04:00
Simplify error codes
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
.TH MUTN 1 "21 April 2025" "v0.2.6" "MUTN man page"
|
||||
.TH MUTN 1 "01 June 2025" "v0.D.0" "MUTN man page"
|
||||
|
||||
.SH NAME
|
||||
\fBmutn\fR - Simple, self-hosted, SSH-synchronized password and note management based on libmutton. It is the successor to sshyp.
|
||||
@@ -152,23 +152,15 @@ Once this has been done, you may proceed with the client setup:
|
||||
|
||||
102: write error
|
||||
|
||||
103: sync process error
|
||||
103: target not found
|
||||
|
||||
104: server connection error
|
||||
104: sync process error
|
||||
|
||||
105: target not found
|
||||
105: decryption error
|
||||
|
||||
106: target already exists
|
||||
106: encryption error
|
||||
|
||||
107: target wrong type (file/directory)
|
||||
|
||||
108: decryption error
|
||||
|
||||
109: encryption error
|
||||
|
||||
110: clipboard error
|
||||
|
||||
111: other error
|
||||
107: clipboard error
|
||||
|
||||
.SH AUTHOR
|
||||
Randall Winkhart (https://github.com/rwinkhart)
|
||||
|
||||
@@ -5,8 +5,8 @@ go 1.24.3
|
||||
require (
|
||||
github.com/Trojan2021/BEAN v0.0.0-20241210230804-8f294833b514
|
||||
github.com/charmbracelet/glamour v0.7.0
|
||||
github.com/rwinkhart/go-boilerplate v0.0.0-20250529185306-e2e64d7fa43b
|
||||
github.com/rwinkhart/libmutton v0.3.2-0.20250601004130-4dab9f2c93e5
|
||||
github.com/rwinkhart/go-boilerplate v0.0.0-20250601181619-e38a47784de0
|
||||
github.com/rwinkhart/libmutton v0.3.2-0.20250601181751-5f8789a0f018
|
||||
golang.org/x/term v0.32.0
|
||||
)
|
||||
|
||||
|
||||
@@ -57,12 +57,12 @@ github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rwinkhart/convertroman v0.2.0 h1:otUm939eXT77q/Lr31mJtMwVWEw0RjEUB71gO65h9OM=
|
||||
github.com/rwinkhart/convertroman v0.2.0/go.mod h1:Af6HqvX0EIM4Y3HcnNXbbRey1dLasGB7WU0+3Cowgmw=
|
||||
github.com/rwinkhart/go-boilerplate v0.0.0-20250529185306-e2e64d7fa43b h1:ENgsUlCmYktd1eauEkjW6Fu8rgZzyGOS/m/6jc968xI=
|
||||
github.com/rwinkhart/go-boilerplate v0.0.0-20250529185306-e2e64d7fa43b/go.mod h1:cnzIF45I0FCOvE4YIB+26pLCUx2kWyY2llKYZruNaRY=
|
||||
github.com/rwinkhart/go-boilerplate v0.0.0-20250601181619-e38a47784de0 h1:Zuwn0er30tMYrBXD1n4nM3mkGhrLFAdn3sZyMHkxx2I=
|
||||
github.com/rwinkhart/go-boilerplate v0.0.0-20250601181619-e38a47784de0/go.mod h1:cnzIF45I0FCOvE4YIB+26pLCUx2kWyY2llKYZruNaRY=
|
||||
github.com/rwinkhart/go-winio-easy-pipe-handles v0.0.0-20250407031321-96994a0e8410 h1:NhHwFM3Pgm6zRUfFKvi0p5ndjfFbVWsRwmmhyFlG4PE=
|
||||
github.com/rwinkhart/go-winio-easy-pipe-handles v0.0.0-20250407031321-96994a0e8410/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
|
||||
github.com/rwinkhart/libmutton v0.3.2-0.20250601004130-4dab9f2c93e5 h1:ofZcQ4Pns5PsJY4ksejkt92ldDyDZ+FPhXMoRHehw4I=
|
||||
github.com/rwinkhart/libmutton v0.3.2-0.20250601004130-4dab9f2c93e5/go.mod h1:uIz4AJcXW7ZHvvoPlLNWQofTBIbFa1UJ2JI6O+FSQ60=
|
||||
github.com/rwinkhart/libmutton v0.3.2-0.20250601181751-5f8789a0f018 h1:SpVerjfORaFmFep1s22YxqxDdJDd+VhGotsNbcOnX40=
|
||||
github.com/rwinkhart/libmutton v0.3.2-0.20250601181751-5f8789a0f018/go.mod h1:KsTWIJIHZdtDsFNAxJ0Xjpfy0mEVks5EWatswZWgdn0=
|
||||
github.com/rwinkhart/peercred-mini v0.1.0 h1:TiS6u8cEWzW55S9X4iVpU72Iuy/NG6rMUJMtUEVEFLw=
|
||||
github.com/rwinkhart/peercred-mini v0.1.0/go.mod h1:+x4Mxc2veE+YePSOpcUasjimh7n799c1KraLuQwHR20=
|
||||
github.com/rwinkhart/rcw v0.2.0 h1:/rFgJ+20OSThipKAX5KPwW2xbPpgh1zl49THmEkkPis=
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/rwinkhart/MUTN/src/cli"
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/front"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/core"
|
||||
"github.com/rwinkhart/libmutton/crypt"
|
||||
"github.com/rwinkhart/libmutton/global"
|
||||
@@ -47,7 +48,7 @@ func main() {
|
||||
case "copy":
|
||||
err := core.CopyArgument(targetLocation, 0)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to copy passphrase to clipboard: "+err.Error(), global.ErrorClipboard, true)
|
||||
other.PrintError("Failed to copy passphrase to clipboard: "+err.Error(), global.ErrorClipboard, true)
|
||||
}
|
||||
case "edit":
|
||||
cli.EditEntryField(targetLocation, true, 0)
|
||||
@@ -58,7 +59,7 @@ func main() {
|
||||
case "shear":
|
||||
err := syncclient.ShearRemoteFromClient(args[1]) // pass the incomplete path as the server and all clients (reading from the deletions directory) will have a different home directory
|
||||
if err != nil {
|
||||
back.PrintError("Failed to shear target: "+err.Error(), back.ErrorWrite, true)
|
||||
other.PrintError("Failed to shear target: "+err.Error(), back.ErrorWrite, true)
|
||||
}
|
||||
default:
|
||||
cli.HelpMain()
|
||||
@@ -97,7 +98,7 @@ func main() {
|
||||
}
|
||||
err := core.CopyArgument(targetLocation, field)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to copy field to clipboard: "+err.Error(), global.ErrorClipboard, true)
|
||||
other.PrintError("Failed to copy field to clipboard: "+err.Error(), global.ErrorClipboard, true)
|
||||
}
|
||||
case "edit":
|
||||
var field int // indicates which (numbered) field to edit
|
||||
@@ -163,7 +164,7 @@ func main() {
|
||||
case "folder", "-f":
|
||||
err := syncclient.AddFolderRemoteFromClient(args[1]) // pass the incomplete path as the server will have a different home directory
|
||||
if err != nil {
|
||||
back.PrintError("Failed to add folder: "+err.Error(), back.ErrorWrite, true)
|
||||
other.PrintError("Failed to add folder: "+err.Error(), back.ErrorWrite, true)
|
||||
}
|
||||
default:
|
||||
cli.HelpAdd()
|
||||
@@ -179,21 +180,21 @@ func main() {
|
||||
case "clipclear":
|
||||
err := core.ClipClearArgument()
|
||||
if err != nil {
|
||||
back.PrintError("Failure occurred in clipboard clearing process: "+err.Error(), global.ErrorClipboard, true)
|
||||
other.PrintError("Failure occurred in clipboard clearing process: "+err.Error(), global.ErrorClipboard, true)
|
||||
}
|
||||
case "startrcwd":
|
||||
crypt.RCWDArgument()
|
||||
case "sync":
|
||||
_, err := syncclient.RunJob(true)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to sync entries: "+err.Error(), global.ErrorSyncProcess, true)
|
||||
other.PrintError("Failed to sync entries: "+err.Error(), global.ErrorSyncProcess, true)
|
||||
}
|
||||
case "init":
|
||||
err := core.LibmuttonInit(front.Input,
|
||||
[][3]string{{"MUTN", "textEditor", cmp.Or(front.Input("Text editor (leave blank for $EDITOR, falls back to \""+cli.FallbackEditor+"\"):"), os.Getenv("EDITOR"), cli.FallbackEditor)}},
|
||||
confirmRCWPassphrase("new"), false)
|
||||
if err != nil {
|
||||
back.PrintError("Initialization failed: "+err.Error(), 0, true)
|
||||
other.PrintError("Initialization failed: "+err.Error(), 0, true)
|
||||
}
|
||||
case "tweak":
|
||||
choice := front.InputMenuGen("Action:", []string{"Change device ID", "Change master passphrase/Optimize entries"})
|
||||
@@ -201,11 +202,11 @@ func main() {
|
||||
case 1:
|
||||
oldDeviceID, err := global.GetCurrentDeviceID()
|
||||
if err != nil {
|
||||
back.PrintError("Failed to get current device ID: "+err.Error(), back.ErrorRead, true)
|
||||
other.PrintError("Failed to get current device ID: "+err.Error(), back.ErrorRead, true)
|
||||
}
|
||||
_, _, err = synccycles.DeviceIDGen(oldDeviceID)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to change device ID: "+err.Error(), global.ErrorSyncProcess, true)
|
||||
other.PrintError("Failed to change device ID: "+err.Error(), global.ErrorSyncProcess, true)
|
||||
}
|
||||
fmt.Println("\nDevice ID changed successfully.")
|
||||
case 2:
|
||||
@@ -214,7 +215,7 @@ func main() {
|
||||
fmt.Print("\nRe-encrypting entries. Please wait; do not force close this process.\n")
|
||||
err := core.EntryRefresh(oldPassphrase, newPassphrase, false)
|
||||
if err != nil {
|
||||
back.PrintError("Re-encryption failed: "+err.Error(), global.ErrorEncryption, true)
|
||||
other.PrintError("Re-encryption failed: "+err.Error(), global.ErrorEncryption, true)
|
||||
}
|
||||
fmt.Println("\nRe-encryption complete.")
|
||||
}
|
||||
|
||||
+2
-1
@@ -3,6 +3,7 @@ package cli
|
||||
import (
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/front"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/core"
|
||||
)
|
||||
|
||||
@@ -12,7 +13,7 @@ func AddEntry(targetLocation string, hideSecrets bool, entryType uint8) {
|
||||
// ensure targetLocation is valid
|
||||
_, err := core.EntryAddPrecheck(targetLocation)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to add entry: "+err.Error(), back.ErrorWrite, true)
|
||||
other.PrintError("Failed to add entry: "+err.Error(), back.ErrorWrite, true)
|
||||
}
|
||||
|
||||
var decryptedEntry []string
|
||||
|
||||
+10
-6
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/front"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/cfg"
|
||||
"github.com/rwinkhart/libmutton/core"
|
||||
"github.com/rwinkhart/libmutton/syncclient"
|
||||
@@ -19,7 +20,7 @@ func RenameCli(oldLocationIncomplete string) {
|
||||
newLocationIncomplete := front.Input("New location:")
|
||||
err := syncclient.RenameRemoteFromClient(oldLocationIncomplete, newLocationIncomplete)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to rename entry: "+err.Error(), back.ErrorWrite, true)
|
||||
other.PrintError("Failed to rename entry: "+err.Error(), back.ErrorWrite, true)
|
||||
}
|
||||
|
||||
// exit is done from sync.RenameRemoteFromClient
|
||||
@@ -30,7 +31,7 @@ func EditEntryField(targetLocation string, hideSecrets bool, field int) {
|
||||
// fetch old entry data (with all required lines present)
|
||||
decryptedEntry, err := core.GetOldEntryData(targetLocation, field)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to fetch entry data: "+err.Error(), back.ErrorRead, true)
|
||||
other.PrintError("Failed to fetch entry data: "+err.Error(), back.ErrorRead, true)
|
||||
}
|
||||
|
||||
// edit the field
|
||||
@@ -51,7 +52,7 @@ func EditEntryField(targetLocation string, hideSecrets bool, field int) {
|
||||
// edit the note
|
||||
editedNote, noteEdited := editNote(fieldsNote)
|
||||
if !noteEdited { // exit early if the note was not edited
|
||||
back.PrintError("Entry is unchanged", 0, true)
|
||||
other.PrintError("Entry is unchanged", 0, true)
|
||||
}
|
||||
decryptedEntry = append(fieldsMain, editedNote...)
|
||||
}
|
||||
@@ -65,7 +66,7 @@ func GenUpdate(targetLocation string, hideSecrets bool) {
|
||||
// fetch old entry data
|
||||
decryptedEntry, err := core.GetOldEntryData(targetLocation, 0)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to fetch entry data: "+err.Error(), back.ErrorRead, true)
|
||||
other.PrintError("Failed to fetch entry data: "+err.Error(), back.ErrorRead, true)
|
||||
}
|
||||
|
||||
// generate a new password
|
||||
@@ -78,7 +79,10 @@ 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).
|
||||
// Returns the edited note and a boolean indicating whether the note was edited.
|
||||
func editNote(baseNote []string) ([]string, bool) {
|
||||
tempFile := back.CreateTempFile()
|
||||
tempFile, err := back.CreateTempFile()
|
||||
if err != nil {
|
||||
other.PrintError("Failed to create temporary note file: "+err.Error(), back.ErrorWrite, true)
|
||||
}
|
||||
defer func(name string) {
|
||||
_ = os.Remove(name) // error ignored; if the file could be created, it can probably be removed
|
||||
}(tempFile.Name())
|
||||
@@ -112,7 +116,7 @@ func editNote(baseNote []string) ([]string, bool) {
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stdin = os.Stdin
|
||||
cmd.Stderr = os.Stderr
|
||||
err := cmd.Run()
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
panic(back.AnsiError + "Failed to write note with " + editor + back.AnsiReset) // panic is used to ensure the tempFile is removed, as per the defer statement
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/synccommon"
|
||||
)
|
||||
|
||||
@@ -81,7 +82,7 @@ func printFileEntry(entry string, lastSlash, charCounter, indent int, colorAlter
|
||||
func EntryListGen() {
|
||||
fileList, dirList, err := synccommon.WalkEntryDir()
|
||||
if err != nil {
|
||||
back.PrintError("Failed to generate entry list: "+err.Error(), back.ErrorRead, true)
|
||||
other.PrintError("Failed to generate entry list: "+err.Error(), back.ErrorRead, true)
|
||||
}
|
||||
|
||||
// print header bar w/total entry count
|
||||
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/crypt"
|
||||
"github.com/rwinkhart/libmutton/global"
|
||||
"github.com/rwinkhart/libmutton/syncclient"
|
||||
@@ -68,7 +69,7 @@ fieldLoop:
|
||||
if syncEnabled {
|
||||
_, err := syncclient.RunJob(false)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to sync entries: "+err.Error(), global.ErrorSyncProcess, true)
|
||||
other.PrintError("Failed to sync entries: "+err.Error(), global.ErrorSyncProcess, true)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,10 +78,14 @@ 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) {
|
||||
if isFile, _ := back.TargetIsFile(targetLocation, true, 2); isFile {
|
||||
isFile, _, err := back.TargetIsFile(targetLocation, true, 2)
|
||||
if err != nil {
|
||||
other.PrintError("Failed to verify target location: "+err.Error(), back.ErrorTargetNotFound, true)
|
||||
}
|
||||
if isFile {
|
||||
decBytes, err := crypt.DecryptFileToSlice(targetLocation)
|
||||
if err != nil {
|
||||
back.PrintError("Failed to decrypt entry: "+err.Error(), global.ErrorDecryption, true)
|
||||
other.PrintError("Failed to decrypt entry: "+err.Error(), global.ErrorDecryption, true)
|
||||
}
|
||||
EntryReader(decBytes, hideSecrets, false) // never sync if decrypting straight to EntryReader, as this means the entry could not have been modified
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/rwinkhart/go-boilerplate/back"
|
||||
"github.com/rwinkhart/go-boilerplate/front"
|
||||
"github.com/rwinkhart/go-boilerplate/other"
|
||||
"github.com/rwinkhart/libmutton/core"
|
||||
"github.com/rwinkhart/libmutton/synccycles"
|
||||
)
|
||||
@@ -33,12 +34,12 @@ func writeEntryCLI(targetLocation string, decryptedEntry []string, hideSecrets b
|
||||
// write the entry to the target location
|
||||
err := core.WriteEntry(targetLocation, []byte(strings.Join(decryptedEntry, "\n")))
|
||||
if err != nil {
|
||||
back.PrintError("Failed to write entry: "+err.Error(), back.ErrorWrite, true)
|
||||
other.PrintError("Failed to write entry: "+err.Error(), back.ErrorWrite, true)
|
||||
}
|
||||
// preview the entry
|
||||
fmt.Println(back.AnsiBold + "\nEntry Preview:" + back.AnsiReset)
|
||||
EntryReader(decryptedEntry, hideSecrets, true)
|
||||
} else {
|
||||
back.PrintError("No data supplied for entry", back.ErrorTargetNotFound, true)
|
||||
other.PrintError("No data supplied for entry", back.ErrorTargetNotFound, true)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user