cli/cmd/crypt/cmd_encrypt.go
Charon 7280168922
Some checks are pending
Security Scan / Go Vulnerability Check (push) Waiting to run
Security Scan / Secret Detection (push) Waiting to run
Security Scan / Dependency & Config Scan (push) Waiting to run
refactor: flatten commands, extract php/ci to own repos (#2)
## Summary
- Extract PHP/Laravel commands to `core/php` repo (42 files, standalone module)
- Extract CI/release + SDK commands to `core/ci` repo (10 files)
- Remove `internal/variants/` build tag system entirely
- Move all 30 remaining command packages from `internal/cmd/` to top-level `cmd/`
- Rewrite `main.go` with direct imports — no more variant selection
- PHP and CI are now optional via commented import lines in main.go

Co-authored-by: Claude <developers@lethean.io>
Reviewed-on: #2
Co-authored-by: Charon <charon@lthn.ai>
Co-committed-by: Charon <charon@lthn.ai>
2026-02-16 14:45:06 +00:00

115 lines
2.8 KiB
Go

package crypt
import (
"fmt"
"os"
"strings"
"forge.lthn.ai/core/go/pkg/cli"
"forge.lthn.ai/core/go/pkg/crypt"
)
// Encrypt command flags
var (
encryptPassphrase string
encryptAES bool
)
func addEncryptCommand(parent *cli.Command) {
encryptCmd := cli.NewCommand("encrypt", "Encrypt a file", "", func(cmd *cli.Command, args []string) error {
return runEncrypt(args[0])
})
encryptCmd.Args = cli.ExactArgs(1)
cli.StringFlag(encryptCmd, &encryptPassphrase, "passphrase", "p", "", "Passphrase (prompted if not given)")
cli.BoolFlag(encryptCmd, &encryptAES, "aes", "", false, "Use AES-256-GCM instead of ChaCha20-Poly1305")
parent.AddCommand(encryptCmd)
decryptCmd := cli.NewCommand("decrypt", "Decrypt an encrypted file", "", func(cmd *cli.Command, args []string) error {
return runDecrypt(args[0])
})
decryptCmd.Args = cli.ExactArgs(1)
cli.StringFlag(decryptCmd, &encryptPassphrase, "passphrase", "p", "", "Passphrase (prompted if not given)")
cli.BoolFlag(decryptCmd, &encryptAES, "aes", "", false, "Use AES-256-GCM instead of ChaCha20-Poly1305")
parent.AddCommand(decryptCmd)
}
func getPassphrase() (string, error) {
if encryptPassphrase != "" {
return encryptPassphrase, nil
}
return cli.Prompt("Passphrase", "")
}
func runEncrypt(path string) error {
passphrase, err := getPassphrase()
if err != nil {
return cli.Wrap(err, "failed to read passphrase")
}
if passphrase == "" {
return cli.Err("passphrase cannot be empty")
}
data, err := os.ReadFile(path)
if err != nil {
return cli.Wrap(err, "failed to read file")
}
var encrypted []byte
if encryptAES {
encrypted, err = crypt.EncryptAES(data, []byte(passphrase))
} else {
encrypted, err = crypt.Encrypt(data, []byte(passphrase))
}
if err != nil {
return cli.Wrap(err, "failed to encrypt")
}
outPath := path + ".enc"
if err := os.WriteFile(outPath, encrypted, 0o600); err != nil {
return cli.Wrap(err, "failed to write encrypted file")
}
cli.Success(fmt.Sprintf("Encrypted %s -> %s", path, outPath))
return nil
}
func runDecrypt(path string) error {
passphrase, err := getPassphrase()
if err != nil {
return cli.Wrap(err, "failed to read passphrase")
}
if passphrase == "" {
return cli.Err("passphrase cannot be empty")
}
data, err := os.ReadFile(path)
if err != nil {
return cli.Wrap(err, "failed to read file")
}
var decrypted []byte
if encryptAES {
decrypted, err = crypt.DecryptAES(data, []byte(passphrase))
} else {
decrypted, err = crypt.Decrypt(data, []byte(passphrase))
}
if err != nil {
return cli.Wrap(err, "failed to decrypt")
}
outPath := strings.TrimSuffix(path, ".enc")
if outPath == path {
outPath = path + ".dec"
}
if err := os.WriteFile(outPath, decrypted, 0o600); err != nil {
return cli.Wrap(err, "failed to write decrypted file")
}
cli.Success(fmt.Sprintf("Decrypted %s -> %s", path, outPath))
return nil
}