Pages are sealed with AES-256-GCM. Each person's key is derived (HKDF) from a master key in the settings file plus their Authentik issuer and subject. Plain files from earlier versions are read and re-saved encrypted. Mako refuses to open a notebook it cannot decrypt rather than overwrite it. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
72 lines
2.0 KiB
Go
72 lines
2.0 KiB
Go
package vault
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
const master = "0123456789abcdef0123456789abcdef"
|
|
|
|
func must(t *testing.T, m, iss, sub string) *Cipher {
|
|
t.Helper()
|
|
c, err := New(m, iss, sub)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return c
|
|
}
|
|
|
|
func TestRoundTrip(t *testing.T) {
|
|
c := must(t, master, "https://a/", "alice")
|
|
plain := []byte("---\ntitle: \"Secret\"\n---\n\ndear diary")
|
|
sealed := c.Seal(plain, "page-1")
|
|
if !IsSealed(sealed) || bytes.Contains(sealed, []byte("diary")) || bytes.Contains(sealed, []byte("Secret")) {
|
|
t.Fatalf("not encrypted: %q", sealed)
|
|
}
|
|
got, err := c.Open(sealed, "page-1")
|
|
if err != nil || !bytes.Equal(got, plain) {
|
|
t.Fatalf("open: %q %v", got, err)
|
|
}
|
|
if bytes.Equal(sealed, c.Seal(plain, "page-1")) {
|
|
t.Fatal("two seals of the same text must differ")
|
|
}
|
|
}
|
|
|
|
func TestWrongKeyNameOrDamage(t *testing.T) {
|
|
c := must(t, master, "https://a/", "alice")
|
|
sealed := c.Seal([]byte("hello"), "p1")
|
|
|
|
cases := map[string]*Cipher{
|
|
"another person": must(t, master, "https://a/", "bob"),
|
|
"another issuer": must(t, master, "https://b/", "alice"),
|
|
"another master key": must(t, strings.Repeat("z", 40), "https://a/", "alice"),
|
|
}
|
|
for name, other := range cases {
|
|
if _, err := other.Open(sealed, "p1"); !errors.Is(err, ErrWrongKey) {
|
|
t.Errorf("%s: want ErrWrongKey, got %v", name, err)
|
|
}
|
|
}
|
|
if _, err := c.Open(sealed, "p2"); !errors.Is(err, ErrWrongKey) {
|
|
t.Errorf("a file moved to another page name opened: %v", err)
|
|
}
|
|
bad := append([]byte{}, sealed...)
|
|
bad[len(bad)-1] ^= 1
|
|
if _, err := c.Open(bad, "p1"); !errors.Is(err, ErrWrongKey) {
|
|
t.Errorf("a damaged file opened: %v", err)
|
|
}
|
|
if _, err := c.Open([]byte("plain text"), "p1"); !errors.Is(err, ErrWrongKey) {
|
|
t.Errorf("plain text opened: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestNewChecks(t *testing.T) {
|
|
if _, err := New("short", "i", "s"); err == nil {
|
|
t.Error("a short key was accepted")
|
|
}
|
|
if _, err := New(master, "i", ""); err == nil {
|
|
t.Error("an empty user was accepted")
|
|
}
|
|
}
|