Drop support for non-continuous TOTP copy

This commit is contained in:
2025-11-13 22:18:02 -05:00
parent 8d1dd48035
commit c63dff4092
4 changed files with 23 additions and 40 deletions
+15 -25
View File
@@ -1,3 +1,5 @@
//go:build (!android && !ios) || termux
package clip package clip
import ( import (
@@ -9,37 +11,28 @@ import (
"github.com/rwinkhart/libmutton/crypt" "github.com/rwinkhart/libmutton/crypt"
) )
// CopyArgument copies a field from an entry to the clipboard. // CopyShortcut, given a path, decrypts an
// If field is -1, it will one-time copy the TOTP code // entry and copies a field to the clipboard.
// (instead of keeping the clipboard up-to-date). func CopyShortcut(targetLocation string, field int) error {
func CopyArgument(targetLocation string, field int) error {
// ensure targetLocation exists and is a file // ensure targetLocation exists and is a file
_, err := back.TargetIsFile(targetLocation, true) _, err := back.TargetIsFile(targetLocation, true)
if err != nil { if err != nil {
return err return err
} }
// decrypt entry
decSlice, err := crypt.DecryptFileToSlice(targetLocation) decSlice, err := crypt.DecryptFileToSlice(targetLocation)
if err != nil { if err != nil {
return errors.New("unable to decrypt entry: " + err.Error()) return errors.New("unable to decrypt entry: " + err.Error())
} }
// handle non-persistent TOTP copy
var copySubject string
var realField int
if field == -1 {
realField = 2
} else {
realField = field
}
// if field exists in entry... // if field exists in entry...
if len(decSlice) > realField { if len(decSlice) > field {
if decSlice[realField] == "" { if decSlice[field] == "" {
return errors.New("field is empty") return errors.New("field is empty")
} }
if realField == 2 { // TOTP mode if field == 2 { // TOTP mode
fmt.Println(back.AnsiWarning + "[Starting]" + back.AnsiReset + " TOTP clipboard refresher") fmt.Println(back.AnsiWarning + "[Starting]" + back.AnsiReset + " TOTP clipboard refresher")
errorChan := make(chan error) errorChan := make(chan error)
go TOTPCopier(decSlice[2], field, errorChan, nil) // "done" is not needed because the process runs until the program is killed go TOTPCopier(decSlice[2], field, errorChan, nil) // "done" is not needed because the process runs until the program is killed
@@ -52,19 +45,16 @@ func CopyArgument(targetLocation string, field int) error {
} }
select {} // block indefinitely select {} // block indefinitely
} else { // other } else { // other
copySubject = decSlice[realField] // copy field to clipboard; launch clipboard clearing process
err = CopyString(true, decSlice[field])
if err != nil {
return err
}
return nil
} }
} else { } else {
return errors.New("field does not exist in entry") return errors.New("field does not exist in entry")
} }
// copy field to clipboard; launch clipboard clearing process
err = CopyString(false, copySubject)
if err != nil {
return err
}
return nil
} }
// ClipClearArgument reads the assigned clipboard contents from stdin and passes them to clipClearProcess. // ClipClearArgument reads the assigned clipboard contents from stdin and passes them to clipClearProcess.
+7 -14
View File
@@ -1,3 +1,5 @@
//go:build (!android && !ios) || termux
package clip package clip
import ( import (
@@ -29,16 +31,7 @@ func GenTOTP(secret string, time time.Time, forSteam bool) (string, error) {
// TOTPCopier is meant to be run as a goroutine to keep // TOTPCopier is meant to be run as a goroutine to keep
// the clipboard up-to-date with the latest TOTP token. // the clipboard up-to-date with the latest TOTP token.
// Set oneTime to -1 for a one-time (non-continuous) TOTP copy.
// For oneTime mode, this function can be used normally (not as a goroutine).
func TOTPCopier(secret string, oneTime int, errorChan chan<- error, done <-chan bool) error { func TOTPCopier(secret string, oneTime int, errorChan chan<- error, done <-chan bool) error {
var writeErrorChan func(err error)
if errorChan != nil {
writeErrorChan = func(err error) { errorChan <- err }
} else {
writeErrorChan = func(err error) {}
}
var forSteam bool var forSteam bool
if strings.HasPrefix(secret, "steam@") { if strings.HasPrefix(secret, "steam@") {
secret = secret[6:] secret = secret[6:]
@@ -49,16 +42,16 @@ func TOTPCopier(secret string, oneTime int, errorChan chan<- error, done <-chan
currentTime := time.Now() currentTime := time.Now()
token, err := GenTOTP(secret, currentTime, forSteam) token, err := GenTOTP(secret, currentTime, forSteam)
if err != nil { if err != nil {
writeErrorChan(err) errorChan <- err
return err // return for when not used as goroutine; should exit on error regardless return err // return for when not used as goroutine; should exit on error regardless
} }
err = CopyString(true, token) err = CopyString(false, token)
if err != nil { if err != nil {
writeErrorChan(err) errorChan <- err
return err // return for when not used as goroutine; should exit on error regardless return err // return for when not used as goroutine; should exit on error regardless
} }
if oneTime != -1 { if oneTime != -1 {
writeErrorChan(err) errorChan <- err
time.Sleep(time.Duration(30-(currentTime.Second()%30)) * time.Second) time.Sleep(time.Duration(30-(currentTime.Second()%30)) * time.Second)
} else { } else {
return nil return nil
@@ -67,7 +60,7 @@ func TOTPCopier(secret string, oneTime int, errorChan chan<- error, done <-chan
// exit after sleep if indicated (will not update clipboard again) // exit after sleep if indicated (will not update clipboard again)
select { select {
case <-done: case <-done:
writeErrorChan(nil) errorChan <- err
return nil return nil
default: default:
} }
+1 -1
View File
@@ -21,7 +21,7 @@ These are as follows:
- `startrcwd`: Should be accepted by all libmutton implementations making use of the RCW daemon to cache passwords. Please accept a `startrcwd` argument that calls `crypt.RCWDArgument()`. - `startrcwd`: Should be accepted by all libmutton implementations making use of the RCW daemon to cache passwords. Please accept a `startrcwd` argument that calls `crypt.RCWDArgument()`.
## Mobile Clipboard Management ## Mobile Clipboard Management
In an effort to reduce dependencies not needed in most environments, libmutton no longer provides clipboard management for mobile platforms. This should be handled by your GUI toolkit/framework. In an effort to reduce dependencies not needed in most environments, libmutton no longer provides clipboard management for mobile platforms (except for Termux). This should be handled by your GUI toolkit/framework.
## Configuration ## Configuration
libmutton-based password manager clients should all share the same INI configuration file. libmutton-based password manager clients should all share the same INI configuration file.