package secure import ( "encoding/base64" "os" "path/filepath" "testing" ) func TestCipherRoundTripAndFingerprint(t *testing.T) { t.Parallel() dir := t.TempDir() key := make([]byte, 32) for index := range key { key[index] = byte(index + 1) } path := filepath.Join(dir, "master-key") if err := os.WriteFile(path, []byte(base64.RawStdEncoding.EncodeToString(key)), 0o600); err != nil { t.Fatal(err) } cipher, err := LoadCipher(path) if err != nil { t.Fatal(err) } ciphertext, nonce, err := cipher.Encrypt("hetzner-token-value") if err != nil { t.Fatal(err) } if string(ciphertext) == "hetzner-token-value" { t.Fatal("token was not encrypted") } plaintext, err := cipher.Decrypt(ciphertext, nonce) if err != nil { t.Fatal(err) } if plaintext != "hetzner-token-value" { t.Fatalf("got %q", plaintext) } if cipher.Fingerprint("same") != cipher.Fingerprint("same") || cipher.Fingerprint("same") == cipher.Fingerprint("different") { t.Fatal("fingerprint must be deterministic and token-specific") } } func TestLoadOrCreateCipherPersistsSecureKey(t *testing.T) { t.Parallel() path := filepath.Join(t.TempDir(), "secrets", "master_key") first, err := LoadOrCreateCipher(path) if err != nil { t.Fatal(err) } info, err := os.Stat(path) if err != nil { t.Fatal(err) } if permissions := info.Mode().Perm(); permissions != 0o600 { t.Fatalf("master key permissions = %o, want 600", permissions) } ciphertext, nonce, err := first.Encrypt("persistent token") if err != nil { t.Fatal(err) } second, err := LoadOrCreateCipher(path) if err != nil { t.Fatal(err) } plaintext, err := second.Decrypt(ciphertext, nonce) if err != nil || plaintext != "persistent token" { t.Fatalf("created key was not reused: plaintext=%q err=%v", plaintext, err) } } func TestPasswordHash(t *testing.T) { t.Parallel() hash, err := HashPassword("a secure password") if err != nil { t.Fatal(err) } if !VerifyPassword(hash, "a secure password") { t.Fatal("expected password verification to succeed") } if VerifyPassword(hash, "wrong password") { t.Fatal("wrong password verified") } if _, err := HashPassword("short"); err == nil { t.Fatal("short password was accepted") } }