Cybersecurity-Projects/PROJECTS/beginner/steganography-multi-tool/internal/cli/passphrase.go

83 lines
1.8 KiB
Go

/*
©AngelaMos | 2026
passphrase.go
Passphrase acquisition from flag, environment, or a no-echo terminal prompt
*/
package cli
import (
"bytes"
"errors"
"fmt"
"os"
"golang.org/x/term"
)
const (
promptEnterPassphrase = "Passphrase: "
promptConfirmPassphrase = "Confirm passphrase: "
promptRetryPassphrase = "Wrong passphrase, try again: "
maxPassphraseAttempts = 3
)
var (
errPassphraseNonInteractive = errors.New("encryption requested but no passphrase provided; pass -k or set " + envPassphrase)
errPassphraseMismatch = errors.New("passphrases did not match")
)
var (
interactive = func() bool { return term.IsTerminal(int(os.Stdin.Fd())) }
readSecret = func() ([]byte, error) { return term.ReadPassword(int(os.Stdin.Fd())) }
)
func passphraseFromFlagOrEnv(flagValue string) []byte {
if flagValue != "" {
return []byte(flagValue)
}
if env := os.Getenv(envPassphrase); env != "" {
return []byte(env)
}
return nil
}
func resolveHidePassphrase(flagValue string, encryptWanted bool) ([]byte, error) {
if p := passphraseFromFlagOrEnv(flagValue); p != nil {
return p, nil
}
if !encryptWanted {
return nil, nil
}
if !interactive() {
return nil, errPassphraseNonInteractive
}
return promptPassphraseConfirmed()
}
func promptPassphraseConfirmed() ([]byte, error) {
first, err := promptPassphrase(promptEnterPassphrase)
if err != nil {
return nil, err
}
second, err := promptPassphrase(promptConfirmPassphrase)
if err != nil {
return nil, err
}
if !bytes.Equal(first, second) {
return nil, errPassphraseMismatch
}
return first, nil
}
func promptPassphrase(prompt string) ([]byte, error) {
fmt.Fprint(os.Stderr, prompt)
pass, err := readSecret()
fmt.Fprintln(os.Stderr)
if err != nil {
return nil, err
}
return pass, nil
}