package store import ( "database/sql" "log" "os" "path/filepath" "strings" "testing" ) func sealTestStore(t *testing.T) *Store { t.Helper() st, err := New(filepath.Join(t.TempDir(), "hub.db"), log.New(os.Stderr, "", 0)) if err != nil { t.Fatal(err) } t.Cleanup(func() { st.Close() }) return st } func rawValue(t *testing.T, st *Store, id string) string { t.Helper() var v string if err := st.db.QueryRow(`SELECT value FROM one_time_secrets WHERE customer_id = ?`, id).Scan(&v); err != nil { t.Fatal(err) } return v } // R-821: a copy of the database alone does not reveal the password — asserted on the raw column. func TestOffsiteSecret_RawRowHoldsNoPassword(t *testing.T) { st := sealTestStore(t) if err := st.SaveOneTimeSecret("c1", "Sup3rSecretPw%"); err != nil { t.Fatal(err) } raw := rawValue(t, st, "c1") if strings.Contains(raw, "Sup3rSecretPw") || !strings.HasPrefix(raw, sealPrefix) { t.Fatalf("raw row is not sealed: %q", raw) } if pw, err := st.OffsitePassword("c1"); err != nil || pw != "Sup3rSecretPw%" { t.Fatalf("OffsitePassword = %q, %v", pw, err) } if pw, err := st.ConsumeOneTimeSecret("c1"); err != nil || pw != "Sup3rSecretPw%" { t.Fatalf("Consume = %q, %v", pw, err) } } // A different key cannot open what was sealed (the key is the secret, not the format). func TestOffsiteSecret_WrongKeyCannotOpen(t *testing.T) { st := sealTestStore(t) if err := st.SaveOneTimeSecret("c1", "Sup3rSecretPw%"); err != nil { t.Fatal(err) } if err := st.SetOffsiteSecretKey([]byte("another-key-of-exactly-32-bytes!")); err != nil { t.Fatal(err) } if pw, err := st.OffsitePassword("c1"); err == nil || pw != "" { t.Fatalf("wrong key opened the secret: %q", pw) } } // Fail-closed: no key → nothing saved, nothing read, never plaintext. func TestOffsiteSecret_NoKeyRefusesToSave(t *testing.T) { st := sealTestStore(t) st.sealer = nil if err := st.SaveOneTimeSecret("c1", "Sup3rSecretPw%"); err != ErrNoSealKey { t.Fatalf("save without key = %v, want ErrNoSealKey", err) } var n int _ = st.db.QueryRow(`SELECT COUNT(*) FROM one_time_secrets`).Scan(&n) if n != 0 { t.Fatalf("%d row(s) written without a key", n) } } // Rows written by a pre-v0.127.0 hub are sealed in place at start-up; idempotent. func TestSealLegacyOffsiteSecrets_SealsPlaintextRows(t *testing.T) { st := sealTestStore(t) if _, err := st.db.Exec(`INSERT INTO one_time_secrets (customer_id, value) VALUES ('old', 'LegacyPlain1%')`); err != nil { t.Fatal(err) } if err := st.SaveOneTimeSecret("new", "AlreadySealed1%"); err != nil { t.Fatal(err) } sealedNew := rawValue(t, st, "new") n, err := st.SealLegacyOffsiteSecrets() if err != nil || n != 1 { t.Fatalf("sealed %d, %v; want 1", n, err) } if raw := rawValue(t, st, "old"); strings.Contains(raw, "LegacyPlain") { t.Fatalf("legacy row still plaintext: %q", raw) } if rawValue(t, st, "new") != sealedNew { t.Fatal("an already-sealed row was re-sealed") } if pw, err := st.OffsitePassword("old"); err != nil || pw != "LegacyPlain1%" { t.Fatalf("legacy row does not open: %q %v", pw, err) } if n, _ := st.SealLegacyOffsiteSecrets(); n != 0 { t.Fatalf("second run sealed %d", n) } if _, err := st.OffsitePassword("absent"); err != sql.ErrNoRows { t.Fatalf("absent = %v, want ErrNoRows", err) } }