mirror of
https://github.com/ivuorinen/a.git
synced 2026-01-26 11:34:07 +00:00
Initial commit
This commit is contained in:
122
cmd/decrypt.go
Normal file
122
cmd/decrypt.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// tryDecrypt attempts to decrypt using the given key and output/input files.
|
||||
func tryDecrypt(keyPath, output, input string) error {
|
||||
ageBin := "age"
|
||||
if ageBin != "age" {
|
||||
return fmt.Errorf("invalid binary for decryption: %s", ageBin)
|
||||
}
|
||||
ageArgs := []string{"-d", "-i", keyPath, "-o", output, input}
|
||||
expectedFlags := map[string]bool{"-d": true, "-i": true, "-o": true}
|
||||
for i, arg := range ageArgs {
|
||||
if i == 0 || i == 2 || i == 4 {
|
||||
if !expectedFlags[arg] && i != 0 {
|
||||
return fmt.Errorf("unexpected flag in age arguments: %s", arg)
|
||||
}
|
||||
} else if arg == "" {
|
||||
return fmt.Errorf("invalid argument for decryption: empty string")
|
||||
}
|
||||
}
|
||||
if !strings.HasSuffix(keyPath, "id_rsa") && !strings.HasSuffix(keyPath, "id_ed25519") {
|
||||
return fmt.Errorf("invalid key file for decryption: %s", keyPath)
|
||||
}
|
||||
if !strings.HasSuffix(output, ".txt") && !strings.HasSuffix(output, ".out") {
|
||||
return fmt.Errorf("invalid output file for decryption: %s", output)
|
||||
}
|
||||
// #nosec G204 -- ageBin and ageArgs are validated above
|
||||
return exec.Command(ageBin, ageArgs...).Run()
|
||||
}
|
||||
|
||||
// selectSSHKey determines which SSH key to use based on flags and config.
|
||||
func selectSSHKey(sshKeyFlag string, cfg *Config) string {
|
||||
if sshKeyFlag != "" {
|
||||
return sshKeyFlag
|
||||
}
|
||||
return cfg.SSHKeyPath
|
||||
}
|
||||
|
||||
// tryAllKeys attempts decryption with all provided keys, returns true on success.
|
||||
func tryAllKeys(keys []string, input, output string, log *logrus.Logger, triedKeys *[]string) bool {
|
||||
for _, keyPath := range keys {
|
||||
*triedKeys = append(*triedKeys, keyPath)
|
||||
log.WithFields(logrus.Fields{
|
||||
"input": input,
|
||||
"output": output,
|
||||
"sshKey": keyPath,
|
||||
}).Info("Trying decryption with SSH key")
|
||||
err := tryDecrypt(keyPath, output, input)
|
||||
if err == nil {
|
||||
log.Info("Decryption successful")
|
||||
return true
|
||||
}
|
||||
log.WithError(err).Warnf("Decryption failed with key %s", keyPath)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Decrypt returns a cobra.Command that decrypts files using age, scanning local SSH keys if needed.
|
||||
func Decrypt(cfg *Config, log *logrus.Logger) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "decrypt",
|
||||
Short: "Decrypt a file",
|
||||
RunE: func(cmd *cobra.Command, _ []string) error {
|
||||
input, _ := cmd.Flags().GetString("input")
|
||||
output, _ := cmd.Flags().GetString("output")
|
||||
sshKeyFlag, _ := cmd.Flags().GetString("ssh-key")
|
||||
|
||||
if input == "" {
|
||||
return fmt.Errorf("input file is required")
|
||||
}
|
||||
if output == "" {
|
||||
return fmt.Errorf("output file is required")
|
||||
}
|
||||
if _, err := os.Stat(input); err != nil {
|
||||
return fmt.Errorf("input file does not exist: %w", err)
|
||||
}
|
||||
|
||||
sshKey := selectSSHKey(sshKeyFlag, cfg)
|
||||
var triedKeys []string
|
||||
var success bool
|
||||
|
||||
if sshKey != "" {
|
||||
triedKeys = append(triedKeys, sshKey)
|
||||
log.WithFields(logrus.Fields{
|
||||
"input": input,
|
||||
"output": output,
|
||||
"sshKey": sshKey,
|
||||
}).Info("Trying decryption with provided SSH key")
|
||||
if err := tryDecrypt(sshKey, output, input); err == nil {
|
||||
log.Info("Decryption successful")
|
||||
success = true
|
||||
} else {
|
||||
log.WithError(err).Warn("Decryption failed with provided SSH key")
|
||||
}
|
||||
} else {
|
||||
keys, err := ScanSSHPrivateKeys()
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not scan ~/.ssh for private keys: %w", err)
|
||||
}
|
||||
success = tryAllKeys(keys, input, output, log, &triedKeys)
|
||||
}
|
||||
|
||||
if !success {
|
||||
return fmt.Errorf("decryption failed: none of the tried SSH keys matched\nTried keys: %v", triedKeys)
|
||||
}
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().StringP("input", "i", "", "Input file to decrypt")
|
||||
cmd.Flags().StringP("output", "o", "", "Output file for decrypted data")
|
||||
cmd.Flags().String("ssh-key", "", "SSH private key to use for decryption")
|
||||
return cmd
|
||||
}
|
||||
Reference in New Issue
Block a user