eleven / messenger Public

Clone
git clone https://amadan.net/eleven/messenger

Plain git — no account needed to clone.

Download

Download this file

1package client
2
3import (
4 "os"
5 "strings"
6 "testing"
7
8 "lchat/internal/e2ee"
9)
10
11// The cross-implementation vector: a JS-sealed envelope (fixed DEK) from
12// home/test/gen-home-vector.mjs — the same generator the Swift HomeCrypto
13// tests pin against. Opening it byte-for-byte proves the AES-GCM layout,
14// padding, and EHB1 framing match the browser's.
15func TestOpenHomeBlobJSVector(t *testing.T) {
16 raw, err := os.ReadFile("testdata/home-vector.txt")
17 if err != nil {
18 t.Fatal(err)
19 }
20 envelope, err := e2ee.B64uDecode(strings.TrimSpace(string(raw)))
21 if err != nil {
22 t.Fatal(err)
23 }
24 dek, err := e2ee.B64uDecode("AAcOFRwjKjE4P0ZNVFtiaXB3foWMk5qhqK-2vcTL0tk") // gen-home-vector.mjs's fixed DEK
25 if err != nil {
26 t.Fatal(err)
27 }
28 v, err := OpenHomeBlob(envelope, dek)
29 if err != nil {
30 t.Fatalf("OpenHomeBlob: %v", err)
31 }
32 if v.V != 1 || len(v.Servers) != 1 || v.Servers[0].URL != "https://test.example.com" || v.Servers[0].Name != "Test" {
33 t.Fatalf("vector contents: %+v", v)
34 }
35}
36
37func TestSealOpenHomeBlobRoundTrip(t *testing.T) {
38 dek, err := e2ee.GenerateKey()
39 if err != nil {
40 t.Fatal(err)
41 }
42 in := &Vault{V: 1, Servers: []VaultServer{
43 {URL: "https://a.11ch.at", Name: "Alpha", Starred: true,
44 Credentials: &VaultCredentials{Token: "tokA", UserPub: "pubA", UserPriv: "privA", Name: "Paul"}},
45 {URL: "https://b.11ch.at", Name: "Bare save"}, // credential-less entry
46 {URL: "https://c.11ch.at", Archived: true,
47 Credentials: &VaultCredentials{Token: "tokC", UserPub: "pubC", UserPriv: "privC"}},
48 }}
49 envelope, err := SealHomeBlob(in, dek, map[string]string{"cred-1": "wrapped-opaque"})
50 if err != nil {
51 t.Fatal(err)
52 }
53 out, err := OpenHomeBlob(envelope, dek)
54 if err != nil {
55 t.Fatal(err)
56 }
57 if len(out.Servers) != 3 || out.Servers[0].Credentials.Token != "tokA" ||
58 !out.Servers[0].Starred || !out.Servers[2].Archived || out.Servers[1].Credentials != nil {
59 t.Fatalf("round trip: %+v", out)
60 }
61
62 // Session projection: credentials become a live space session; the vault
63 // name backfills when credentials carry none; bare entries yield nil.
64 s := out.Servers[0].Session()
65 if s == nil || s.Base != "https://a.11ch.at" || s.Token != "tokA" || s.Name != "Paul" || !s.LabelPublished {
66 t.Fatalf("session projection: %+v", s)
67 }
68 if got := out.Servers[2].Session(); got == nil || got.Name != "" {
69 t.Fatalf("nameless credentials: %+v", got)
70 }
71 if out.Servers[1].Session() != nil {
72 t.Fatal("bare entry must project no session")
73 }
74
75 // Wrong key must not open.
76 other, _ := e2ee.GenerateKey()
77 if _, err := OpenHomeBlob(envelope, other); err == nil {
78 t.Fatal("opened with the wrong DEK")
79 }
80}
81
82// OpenHandoff is the CLI's end of restore.js's cli branch: the page seals the
83// home session to the ephemeral pubkey; only the matching private key +
84// matching nonce open it.
85func TestOpenHandoff(t *testing.T) {
86 kp, err := e2ee.GenerateUserKeypair()
87 if err != nil {
88 t.Fatal(err)
89 }
90 sealed, err := e2ee.SealForPub(kp.PublicKey, HomeSession{V: 1, Token: "hometok", CredID: "cred-1", DEK: "dEk"})
91 if err != nil {
92 t.Fatal(err)
93 }
94 back := e2ee.B64uEncode([]byte(`{"nonce":"n-123","wrapped":"` + sealed + `"}`))
95
96 hs, err := OpenHandoff(back, "n-123", kp.PrivateKey)
97 if err != nil {
98 t.Fatalf("OpenHandoff: %v", err)
99 }
100 if hs.Token != "hometok" || hs.CredID != "cred-1" || hs.DEK != "dEk" {
101 t.Fatalf("session: %+v", hs)
102 }
103
104 if _, err := OpenHandoff(back, "other-nonce", kp.PrivateKey); err == nil {
105 t.Fatal("nonce mismatch accepted")
106 }
107 otherKP, _ := e2ee.GenerateUserKeypair()
108 if _, err := OpenHandoff(back, "n-123", otherKP.PrivateKey); err == nil {
109 t.Fatal("wrong ephemeral key accepted")
110 }
111 if _, err := OpenHandoff("not base64 json", "n", kp.PrivateKey); err == nil {
112 t.Fatal("garbage accepted")
113 }
114}
115