Make adjustments for easier CGO integration

This commit is contained in:
2026-01-21 18:35:26 -05:00
parent f82b35bc43
commit 48e084ac0f
7 changed files with 49 additions and 37 deletions
+3 -2
View File
@@ -31,7 +31,8 @@ func Entry(vanityPath string, timestamp int64) error {
// AllPasswordEntries adds age data for all un-aged entries containing passwords.
// Each entry is aged with a random timestamp from within the last year to prevent
// all entries having their passwords expire at the same time.
func AllPasswordEntries(forceReage bool) error {
// Leave rcwPassword nil to use RCW demonization.
func AllPasswordEntries(forceReage bool, rcwPassword []byte) error {
allVanityPaths, _, err := synccommon.WalkEntryDir()
if err != nil {
return errors.New("unable to walk entry directory: " + err.Error())
@@ -48,7 +49,7 @@ func AllPasswordEntries(forceReage bool) error {
}
}
decSlice, err := crypt.DecryptFileToSlice(global.EntryRoot + vanityPath)
decSlice, err := crypt.DecryptFileToSlice(global.EntryRoot+vanityPath, rcwPassword)
if err != nil {
return err
}
+3 -2
View File
@@ -13,7 +13,8 @@ import (
// CopyShortcut (given a path) decrypts an
// entry and copies a field to the clipboard.
func CopyShortcut(realPath string, field int) error {
// Leave rcwPassword nil to use RCW demonization.
func CopyShortcut(realPath string, field int, rcwPassword []byte) error {
// ensure realPath exists and is a file
_, err := back.TargetIsFile(realPath, true)
if err != nil {
@@ -21,7 +22,7 @@ func CopyShortcut(realPath string, field int) error {
}
// decrypt entry
decSlice, err := crypt.DecryptFileToSlice(realPath)
decSlice, err := crypt.DecryptFileToSlice(realPath, rcwPassword)
if err != nil {
return errors.New("unable to decrypt entry: " + err.Error())
}
+3 -2
View File
@@ -10,7 +10,8 @@ import (
// GetOldEntryData decrypts and returns old entry data (with all required lines present).
// This is a wrapper around the DecryptFileToSlice function that ensures all required lines are present in the returned slice.
// This makes it ideal for editing entries, as it guarantees at least a baseline slice length.
func GetOldEntryData(realPath string, field int) ([]string, error) {
// Leave rcwPassword nil to use RCW demonization.
func GetOldEntryData(realPath string, field int, rcwPassword []byte) ([]string, error) {
// ensure realPath exists and is a file
_, err := back.TargetIsFile(realPath, true)
if err != nil {
@@ -18,7 +19,7 @@ func GetOldEntryData(realPath string, field int) ([]string, error) {
}
// read old entry data
decryptedEntry, err := crypt.DecryptFileToSlice(realPath)
decryptedEntry, err := crypt.DecryptFileToSlice(realPath, rcwPassword)
if err != nil {
return nil, errors.New("unable to decrypt entry: " + err.Error())
}
+3 -2
View File
@@ -19,8 +19,9 @@ import (
// WriteEntry writes entryData to an encrypted file at realPath.
// If the entry contains an updated password, an age file is also created.
func WriteEntry(realPath string, decSlice []string, passwordIsNew bool) error {
err := os.WriteFile(realPath, crypt.EncryptBytes([]byte(strings.Join(decSlice, "\n"))), 0600)
// Leave rcwPassword nil to use RCW demonization.
func WriteEntry(realPath string, decSlice []string, passwordIsNew bool, rcwPassword []byte) error {
err := os.WriteFile(realPath, crypt.EncryptBytes([]byte(strings.Join(decSlice, "\n")), rcwPassword), 0600)
if err != nil {
return errors.New("unable to write to file: " + err.Error())
}
+29 -20
View File
@@ -13,7 +13,6 @@ import (
"github.com/rwinkhart/rcw/wrappers"
)
var Daemonize = true
var RetryPassword = true
// RCWDArgument reads the password from stdin and caches it via an RCW daemon.
@@ -25,23 +24,29 @@ func RCWDArgument() {
daemon.Start([]byte(password))
}
// DecryptFileToSlice decrypts an RCW wrapped file and returns the contents as a slice of (trimmed) strings.
func DecryptFileToSlice(realPath string) ([]string, error) {
// DecryptFileToSlice decrypts an RCW wrapped file
// and returns the contents as a slice of (trimmed) strings.
// Leave rcwPassword nil to use RCW demonization.
func DecryptFileToSlice(realPath string, rcwPassword []byte) ([]string, error) {
// read encrypted file
encBytes, err := os.ReadFile(realPath)
if err != nil {
return nil, errors.New("unable to open \"" + realPath + "\" for decryption: " + err.Error())
}
// decrypt data using RCW daemon
password := launchRCWDProcess()
if password == nil {
// if daemon is already running, use it to decrypt the data
// if no password was provided, assume daemon mode
if rcwPassword == nil {
rcwPassword = launchRCWDProcess()
// if rcwPassword is still nil, the daemon is already running;
// use it to encrypt the data
if rcwPassword == nil {
return strings.Split(string(daemon.GetDec(encBytes)), "\n"), nil
}
// if the daemon is not already running, use wrappers.Decrypt
// directly to avoid waiting for socket file creation
decBytes, err := wrappers.Decrypt(encBytes, password)
}
// if the daemon is not being used/was not already running,
// use wrappers.Decrypt directly to avoid waiting for socket file creation
decBytes, err := wrappers.Decrypt(encBytes, rcwPassword)
if err != nil {
return nil, errors.New("unable to decrypt \"" + realPath + "\": " + err.Error())
}
@@ -49,22 +54,28 @@ func DecryptFileToSlice(realPath string) ([]string, error) {
}
// EncryptBytes encrypts a byte slice using RCW and returns the encrypted data.
func EncryptBytes(decBytes []byte) []byte {
password := launchRCWDProcess()
if password == nil {
// if daemon is already running, use it to encrypt the data
// Leave rcwPassword nil to use RCW demonization.
func EncryptBytes(decBytes, rcwPassword []byte) []byte {
// if no rcwPassword was provided, assume daemon mode
if rcwPassword == nil {
rcwPassword = launchRCWDProcess()
// if rcwPassword is still nil, the daemon is already running;
// use it to encrypt the data
if rcwPassword == nil {
return daemon.GetEnc(decBytes)
}
// if the daemon is not already running, use wrappers.Encrypt
// directly to avoid waiting for socket file creation
return wrappers.Encrypt(decBytes, password)
}
// if the daemon is not being used/was not already running,
// use wrappers.Encrypt directly to avoid waiting for socket file creation
return wrappers.Encrypt(decBytes, rcwPassword)
}
// launchRCWDProcess launches an RCW daemon to cache a password.
// If the daemon is not already running OR if not running in daemonize mode,
// it collects and returns the password (otherwise returns nil).
func launchRCWDProcess() []byte {
if Daemonize && daemon.IsOpen() {
if daemon.IsOpen() {
return nil
}
var password []byte
@@ -81,12 +92,10 @@ func launchRCWDProcess() []byte {
password = global.GetPassword("RCW Password:")
}
if Daemonize {
cmd := exec.Command(os.Args[0], "startrcwd")
cmd.SysProcAttr = global.GetSysProcAttr()
_ = back.WriteToStdin(cmd, string(password))
_ = cmd.Start()
}
return password
}
+2 -2
View File
@@ -1,6 +1,6 @@
module github.com/rwinkhart/libmutton
go 1.25.5
go 1.25.6
require (
github.com/pkg/sftp v1.13.10
@@ -8,6 +8,7 @@ require (
github.com/rwinkhart/go-boilerplate v0.1.1
github.com/rwinkhart/rcw v0.2.4
golang.org/x/crypto v0.46.0
golang.org/x/sys v0.40.0
)
require (
@@ -15,7 +16,6 @@ require (
github.com/boombuler/barcode v1.1.0 // indirect
github.com/kr/fs v0.1.0 // indirect
github.com/rwinkhart/peercred-mini v0.1.2 // indirect
golang.org/x/sys v0.40.0 // indirect
)
replace golang.org/x/sys => github.com/rwinkhart/sys v0.40.0
-1
View File
@@ -13,7 +13,6 @@ These are as follows:
## Required Global Variable Manipulation
- `global.GetPassword` must be set to allow for different types of clients (CLI, GUI, TUI) to prompt for the password in the most appropriate way.
- `crypt.Daemonize`, true by default, determines whether to make use of the RCW daemon for password caching. This may be best to disable for interactive clients.
- `crypt.RetryPassword`, true by default, determines whether the crypt package should verify user-typed passwords and re-prompt if needed. Turn this off to handle this uniquely in the client.
## Required Arguments