The age commands: pub, priv, encrypt and decrypt (closes #3)
All checks were successful
check / check (push) Successful in 3m57s
All checks were successful
check / check (push) Successful in 3m57s
The application number is 657169, so the path is m/83696968'/657169'/<n>'. The 32 derived bytes are clamped the way X25519 requires and go through bech32 into an age identity, which is the only route age offers from raw bytes to a key; these are the steps sneak/secret takes in its agehd package. The derived recipient is always first in the recipient list, so the mnemonic that encrypted a file can always read it back. Decrypting recognises the text form by the line it starts with, so it needs no flag. A file named with -o is created readable only by its owner, since a decrypted one is as secret as what went into it. Model: opus-5
This commit is contained in:
84
internal/cli/age_test.go
Normal file
84
internal/cli/age_test.go
Normal file
@@ -0,0 +1,84 @@
|
||||
package cli_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.eeqj.de/sneak/keyfunc/internal/agekey"
|
||||
"git.eeqj.de/sneak/keyfunc/internal/mnemonic"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTheAgeCommandsPrintTheKey(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
recipient := strings.TrimSpace(run(t, "age", "pub"))
|
||||
require.True(t, strings.HasPrefix(recipient, "age1"))
|
||||
|
||||
identity := strings.TrimSpace(run(t, "age", "priv"))
|
||||
require.True(t, strings.HasPrefix(identity, "AGE-SECRET-KEY-1"))
|
||||
}
|
||||
|
||||
func TestAFileEncryptedByTheToolIsReadBackByIt(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
plain := written(t, "notes.txt", "the secret\n")
|
||||
sealed := filepath.Join(t.TempDir(), "notes.age")
|
||||
|
||||
run(t, "age", "encrypt", "-o", sealed, plain)
|
||||
require.Equal(t, "the secret\n", run(t, "age", "decrypt", sealed))
|
||||
}
|
||||
|
||||
func TestTheArmoredFormIsTextThatDecrypts(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
plain := written(t, "notes.txt", "the secret\n")
|
||||
|
||||
armored := run(t, "age", "encrypt", "--armor", plain)
|
||||
require.True(t, strings.HasPrefix(
|
||||
armored, "-----BEGIN AGE ENCRYPTED FILE-----",
|
||||
))
|
||||
|
||||
sealed := written(t, "notes.age", armored)
|
||||
require.Equal(t, "the secret\n", run(t, "age", "decrypt", sealed))
|
||||
}
|
||||
|
||||
func TestAnotherRecipientIsAddedAndTheDerivedOneStays(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
theirs := strings.TrimSpace(run(t, "age", "pub", "-n", "7"))
|
||||
plain := written(t, "notes.txt", "the secret\n")
|
||||
sealed := filepath.Join(t.TempDir(), "notes.age")
|
||||
|
||||
run(t, "age", "encrypt", "--to", theirs, "-o", sealed, plain)
|
||||
|
||||
require.Equal(t, "the secret\n", run(t, "age", "decrypt", sealed))
|
||||
require.Equal(t,
|
||||
"the secret\n", run(t, "age", "decrypt", "-n", "7", sealed),
|
||||
)
|
||||
}
|
||||
|
||||
func TestAFileForAnotherKeyIsRefused(t *testing.T) {
|
||||
t.Setenv(mnemonic.Variable, example())
|
||||
|
||||
plain := written(t, "notes.txt", "the secret\n")
|
||||
sealed := filepath.Join(t.TempDir(), "notes.age")
|
||||
|
||||
run(t, "age", "encrypt", "-n", "7", "-o", sealed, plain)
|
||||
|
||||
_, err := execute(t, "age", "decrypt", sealed)
|
||||
require.ErrorIs(t, err, agekey.ErrNotRecipient)
|
||||
}
|
||||
|
||||
// written puts the contents in a file of that name in a directory of
|
||||
// this test's own and returns the path to it.
|
||||
func written(t *testing.T, name, contents string) string {
|
||||
t.Helper()
|
||||
|
||||
path := filepath.Join(t.TempDir(), name)
|
||||
require.NoError(t, os.WriteFile(path, []byte(contents), 0o600))
|
||||
|
||||
return path
|
||||
}
|
||||
Reference in New Issue
Block a user