nostr-contact-card 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENCE +21 -0
- package/README.md +115 -0
- package/dist/card.d.ts +128 -0
- package/dist/card.d.ts.map +1 -0
- package/dist/card.js +293 -0
- package/dist/card.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/link-card.d.ts +68 -0
- package/dist/link-card.d.ts.map +1 -0
- package/dist/link-card.js +197 -0
- package/dist/link-card.js.map +1 -0
- package/package.json +66 -0
- package/vectors/contact-card.json +1099 -0
package/LICENCE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT Licence
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ForgeSworn
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# nostr-contact-card
|
|
2
|
+
|
|
3
|
+
[](https://github.com/forgesworn/nostr-contact-card/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/nostr-contact-card)
|
|
5
|
+
[](./LICENCE)
|
|
6
|
+
[](https://github.com/sponsors/TheCryptoDonkey)
|
|
7
|
+
|
|
8
|
+
**One QR or link that makes a stranger a contact, names their box, and starts a bond.**
|
|
9
|
+
|
|
10
|
+
A contact card is a small signed JSON object carried after `#` in a link or
|
|
11
|
+
as the whole of a QR code. It holds a person's key and name, their public
|
|
12
|
+
relays, their box (a Link address card, carried opaquely, that the person's
|
|
13
|
+
signature endorses), a rendezvous key and a fresh ephemeral for deriving
|
|
14
|
+
private rendezvous material, an optional attestation pointer, and a bond
|
|
15
|
+
handshake so an in-person ceremony can start from the card.
|
|
16
|
+
|
|
17
|
+
Reading a card needs nothing from the network: five checks, in order, and
|
|
18
|
+
the result names the step that failed so the client can say why. What comes
|
|
19
|
+
back is rebuilt from the fields the draft names, each checked; an extra key
|
|
20
|
+
on the wire never reaches the caller under a verified signature. Dialling
|
|
21
|
+
the box afterwards is on the person's own word; a later fresh address from
|
|
22
|
+
the box is accepted only under the node id they endorsed, which the client
|
|
23
|
+
pins from the first read (the Link card inside a contact card lasts seven
|
|
24
|
+
days, the card itself thirty, so a client keeps the node id it read).
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { buildCard, cardLink, readCard, refreshBox } from 'nostr-contact-card'
|
|
28
|
+
|
|
29
|
+
const card = buildCard({ identityPrivateKey, rz, ephemeralPrivateKey, name: 'Ada', relays, boxes: [box], bond })
|
|
30
|
+
const link = cardLink('https://your.app/join', card) // the server never sees the fragment
|
|
31
|
+
|
|
32
|
+
const r = readCard(scannedText, now())
|
|
33
|
+
if (!r.ok) show(r.step, r.reason)
|
|
34
|
+
else { addContact(r.card.p, r.card.name); for (const b of r.boxes) dial(b.link, b.box.p) }
|
|
35
|
+
|
|
36
|
+
const fresh = refreshBox(pinnedNodeId, freshLinkCardBytes, now(), highestSerialSeen)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Vectors in `vectors/contact-card.json` are the draft's known-answer file:
|
|
40
|
+
cards failing at each step, extra-key, format-character, surrogate,
|
|
41
|
+
byte-order-mark, empty-field and expiry-window cases, and refresh cases
|
|
42
|
+
including a small-order node id and a nonce point carrying torsion. A
|
|
43
|
+
second implementation, written from the draft alone, must agree on every
|
|
44
|
+
one; the vectors carry the expected `ok` and step, and a verifier that
|
|
45
|
+
disagrees on either is wrong.
|
|
46
|
+
|
|
47
|
+
## What a card carries
|
|
48
|
+
|
|
49
|
+
More than two keys: the person's key `p`, their rendezvous key `rz`, a
|
|
50
|
+
fresh ephemeral, each box's key and Link node id (and so its onion
|
|
51
|
+
address), a display name, and a bond nonce that is a bearer secret for the
|
|
52
|
+
card's life: whoever holds the link can start the ceremony. The fragment
|
|
53
|
+
never reaches the server, but it does sit in browser history, clipboards,
|
|
54
|
+
chat logs and photographs of QR codes. Hand a card to the person it is
|
|
55
|
+
for.
|
|
56
|
+
|
|
57
|
+
Whoever holds it cannot derive rendezvous material from it, because the
|
|
58
|
+
derivation (in nostr-deaddrop) needs the reader's own secret or the
|
|
59
|
+
ephemeral's private half, and a card carries neither. It is never
|
|
60
|
+
identity: the box still decides admission, and a bond still needs the
|
|
61
|
+
ceremony.
|
|
62
|
+
|
|
63
|
+
## Security notes
|
|
64
|
+
|
|
65
|
+
- `readCard` returns only the named fields, every hex field lower-cased
|
|
66
|
+
(bond and persona keys included), bond canonicalised. Names, display
|
|
67
|
+
names and persona labels pass `isGoodName`: 1 to 100 code points, at
|
|
68
|
+
least one visible, no control, surrogate, unassigned or private-use
|
|
69
|
+
character, no separator but an ordinary space and none at the ends, no
|
|
70
|
+
invisible or direction-changing format character, no run of five
|
|
71
|
+
combining marks; the joiners and tag characters emoji need are allowed
|
|
72
|
+
only beside a pictographic character. Empty strings are refused, because
|
|
73
|
+
an empty name or attest would hash the same as none.
|
|
74
|
+
- The wire is decoded as strict UTF-8: a byte sequence that is not UTF-8,
|
|
75
|
+
or a leading byte-order mark, is not a card. Nothing decodes to U+FFFD.
|
|
76
|
+
- Link cards are verified as libsodium and ed25519-dalek's `verify_strict`
|
|
77
|
+
do: canonical encodings only (no ZIP-215), a node id or nonce point of
|
|
78
|
+
small order refused, `S` below the group order, and the cofactorless
|
|
79
|
+
equation `[S]B = R + [k]A`. noble's own `verify` multiplies by the
|
|
80
|
+
cofactor and would accept a node id or nonce carrying torsion that a
|
|
81
|
+
strict verifier refuses, so the check is done by hand (`verifyStrict`).
|
|
82
|
+
- Relay hints and card relays pass `isRelayUrl`: `wss://`, a URL with a
|
|
83
|
+
DNS name or IP literal as host, no credentials, no fragment, no comma, no
|
|
84
|
+
unprintable character, no byte-order mark. Onion hints are a 56-character
|
|
85
|
+
base32 host with a non-zero port. An ephemeral hint (kind 0x04) has a
|
|
86
|
+
compressed-point prefix. Kind 0x02 and unknown kinds come back in `hints`
|
|
87
|
+
exactly as the box wrote them; only `relays` and `onions` are checked
|
|
88
|
+
views. A serial above 2^53 is refused under rule 3, before the signature.
|
|
89
|
+
- `now` must be a finite number of seconds and `highestSerial` an integer
|
|
90
|
+
or absent. Anything else fails closed; it never switches a check off.
|
|
91
|
+
- Hex case is normalised and base64url padding tolerated, so one card has
|
|
92
|
+
several wire forms; so does any JSON re-serialisation. Anything that
|
|
93
|
+
caches or deduplicates on the encoded string must key on the card's
|
|
94
|
+
fields, not its bytes.
|
|
95
|
+
- The size cap applies to the card, not the link it rides on. A contact
|
|
96
|
+
card's `issued` may be up to 300 seconds ahead of `now`, and `expires`
|
|
97
|
+
must be after `issued`.
|
|
98
|
+
- Replay protection for a box's fresh Link cards is rule 8, and rule 8
|
|
99
|
+
needs the highest serial this client accepted for that node id. The
|
|
100
|
+
library pins nothing: persist `link.serial` per node id and pass it to
|
|
101
|
+
`refreshBox`; without it any unexpired old card of the same node is
|
|
102
|
+
accepted.
|
|
103
|
+
|
|
104
|
+
## What remains
|
|
105
|
+
|
|
106
|
+
In the profile's own words, from its table of what remains: a card is
|
|
107
|
+
trusted on first use. An impostor who hands you a card is an impostor
|
|
108
|
+
you have a contact for; what narrows that is not in this library but in
|
|
109
|
+
how many independent channels confirm the key, shown as a count and never
|
|
110
|
+
as a score, and a bond ceremony spoken live. Whoever holds a card holds
|
|
111
|
+
its bond nonce, a bearer secret for the card's life.
|
|
112
|
+
|
|
113
|
+
## Licence
|
|
114
|
+
|
|
115
|
+
MIT. ForgeSworn.
|
package/dist/card.d.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { type LinkCard } from './link-card.js';
|
|
2
|
+
export declare const CARD_DOMAIN = "nostr-contact-card:v1";
|
|
3
|
+
export declare const MAX_CARD_BYTES: number;
|
|
4
|
+
export declare const MAX_AGE_SECONDS: number;
|
|
5
|
+
export declare const MAX_RELAYS = 8;
|
|
6
|
+
export declare const MAX_BOXES = 4;
|
|
7
|
+
/** Longest name, display name or persona label, in code points. */
|
|
8
|
+
export declare const MAX_NAME = 100;
|
|
9
|
+
export declare const MAX_PERSONAS = 16;
|
|
10
|
+
export interface BondHandshake {
|
|
11
|
+
v?: 1;
|
|
12
|
+
pubkey: string;
|
|
13
|
+
displayName?: string;
|
|
14
|
+
nonce: string;
|
|
15
|
+
personas?: {
|
|
16
|
+
pubkey: string;
|
|
17
|
+
label?: string;
|
|
18
|
+
}[];
|
|
19
|
+
}
|
|
20
|
+
export interface Box {
|
|
21
|
+
/** The box's own key, x-only hex. */
|
|
22
|
+
p: string;
|
|
23
|
+
/** The box's binding event id, where the box publishes one. */
|
|
24
|
+
claim: string;
|
|
25
|
+
/** FSL-CARD-1, base64url without padding, carried opaquely. */
|
|
26
|
+
card: string;
|
|
27
|
+
carriers?: string[];
|
|
28
|
+
}
|
|
29
|
+
export interface UnsignedCard {
|
|
30
|
+
v: 1;
|
|
31
|
+
p: string;
|
|
32
|
+
rz: string;
|
|
33
|
+
name?: string;
|
|
34
|
+
issued: number;
|
|
35
|
+
expires: number;
|
|
36
|
+
relays: string[];
|
|
37
|
+
boxes: Box[];
|
|
38
|
+
eph: string;
|
|
39
|
+
attest?: string;
|
|
40
|
+
bond?: BondHandshake;
|
|
41
|
+
}
|
|
42
|
+
export interface Card extends UnsignedCard {
|
|
43
|
+
sig: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A name, display name or persona label a person will see: 1 to 100 code
|
|
47
|
+
* points, at least one visible one, no control, surrogate, unassigned or
|
|
48
|
+
* private-use character, no separator other than an ordinary space and none
|
|
49
|
+
* of those at the ends, no invisible or direction-changing format character,
|
|
50
|
+
* no run of five combining marks. The format characters emoji sequences use
|
|
51
|
+
* (the zero-width joiner and the tag characters) are allowed only beside a
|
|
52
|
+
* pictographic character, so a family or a flag reads and a hidden joiner
|
|
53
|
+
* does not.
|
|
54
|
+
*/
|
|
55
|
+
export declare function isGoodName(s: unknown): s is string;
|
|
56
|
+
/**
|
|
57
|
+
* A bond handshake with only the fields the draft names, each checked, in
|
|
58
|
+
* canonical key order. Throws with a `handshake:` message on anything else.
|
|
59
|
+
*/
|
|
60
|
+
export declare function cleanBond(p: unknown): BondHandshake;
|
|
61
|
+
/** The canonical bytes of a bond handshake: fixed key order, no whitespace, absent keys omitted. */
|
|
62
|
+
export declare function handshakeBytes(p: BondHandshake): Uint8Array;
|
|
63
|
+
/**
|
|
64
|
+
* §2 of the draft: the digest the card's signature covers. Fields are
|
|
65
|
+
* colon-joined; every field that could carry a separator is constrained by
|
|
66
|
+
* `readCard` step 2 (relays no comma, box cards base64url, carriers a
|
|
67
|
+
* short token alphabet and never an empty list, attest no colon, and no
|
|
68
|
+
* empty name or attest, which would hash the same as absence) so no two
|
|
69
|
+
* well-formed cards share a digest.
|
|
70
|
+
*/
|
|
71
|
+
export declare function cardDigest(c: UnsignedCard): Uint8Array;
|
|
72
|
+
export interface BuildOptions {
|
|
73
|
+
identityPrivateKey: Uint8Array;
|
|
74
|
+
/** The rendezvous public key, a child of the root, x-only hex. */
|
|
75
|
+
rz: string;
|
|
76
|
+
/** A fresh ephemeral secret for this card; its public half goes on the card. */
|
|
77
|
+
ephemeralPrivateKey: Uint8Array;
|
|
78
|
+
name?: string;
|
|
79
|
+
relays?: string[];
|
|
80
|
+
boxes?: Box[];
|
|
81
|
+
attest?: string;
|
|
82
|
+
bond?: Omit<BondHandshake, 'v'>;
|
|
83
|
+
/** Card lifetime in seconds, at most 30 days. */
|
|
84
|
+
ttlSeconds?: number;
|
|
85
|
+
now?: () => number;
|
|
86
|
+
}
|
|
87
|
+
/** Build and sign a card. Throws when it would not fit or would not verify. */
|
|
88
|
+
export declare function buildCard(o: BuildOptions): Card;
|
|
89
|
+
export declare function encodeCard(card: Card): string;
|
|
90
|
+
/** A link a person can send: the card rides after `#`, so no server sees it. */
|
|
91
|
+
export declare function cardLink(base: string, card: Card): string;
|
|
92
|
+
export interface ReadOk {
|
|
93
|
+
ok: true;
|
|
94
|
+
/** Only the fields the draft names, each checked; nothing else from the wire survives. */
|
|
95
|
+
card: Card;
|
|
96
|
+
/** Each box with its verified Link card; the node id is the one `p` endorsed. */
|
|
97
|
+
boxes: {
|
|
98
|
+
box: Box;
|
|
99
|
+
link: LinkCard;
|
|
100
|
+
}[];
|
|
101
|
+
}
|
|
102
|
+
export type ReadResult = ReadOk | {
|
|
103
|
+
ok: false;
|
|
104
|
+
step: 1 | 2 | 3 | 4 | 5;
|
|
105
|
+
reason: string;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* §3 steps 1 to 5. The result names the step that failed, for the words a
|
|
109
|
+
* client shows. The card returned is rebuilt from the fields the draft
|
|
110
|
+
* names: an extra key on the wire, `__proto__` included, never reaches the
|
|
111
|
+
* caller under a verified signature.
|
|
112
|
+
*/
|
|
113
|
+
export declare function readCard(encoded: string, now: number): ReadResult;
|
|
114
|
+
/**
|
|
115
|
+
* §3 step 6: accept a fresh Link card from a box only under the node id the
|
|
116
|
+
* person endorsed. Pass the highest serial previously accepted for that node
|
|
117
|
+
* id, persisted by the caller; without it any unexpired old card of the same
|
|
118
|
+
* node replays, which is rule 8's job to stop and this function cannot do
|
|
119
|
+
* alone.
|
|
120
|
+
*/
|
|
121
|
+
export declare function refreshBox(pinnedNodeId: string | Uint8Array, freshCard: Uint8Array, now: number, highestSerial?: number): {
|
|
122
|
+
ok: true;
|
|
123
|
+
link: LinkCard;
|
|
124
|
+
} | {
|
|
125
|
+
ok: false;
|
|
126
|
+
reason: string;
|
|
127
|
+
};
|
|
128
|
+
//# sourceMappingURL=card.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.d.ts","sourceRoot":"","sources":["../src/card.ts"],"names":[],"mappings":"AAIA,OAAO,EAA8B,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAE1E,eAAO,MAAM,WAAW,0BAA0B,CAAA;AAClD,eAAO,MAAM,cAAc,QAAY,CAAA;AACvC,eAAO,MAAM,eAAe,QAAiB,CAAA;AAC7C,eAAO,MAAM,UAAU,IAAI,CAAA;AAC3B,eAAO,MAAM,SAAS,IAAI,CAAA;AAC1B,mEAAmE;AACnE,eAAO,MAAM,QAAQ,MAAM,CAAA;AAC3B,eAAO,MAAM,YAAY,KAAK,CAAA;AAE9B,MAAM,WAAW,aAAa;IAC5B,CAAC,CAAC,EAAE,CAAC,CAAA;IACL,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CAChD;AAED,MAAM,WAAW,GAAG;IAClB,qCAAqC;IACrC,CAAC,EAAE,MAAM,CAAA;IACT,+DAA+D;IAC/D,KAAK,EAAE,MAAM,CAAA;IACb,+DAA+D;IAC/D,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,EAAE,CAAC,CAAA;IACJ,CAAC,EAAE,MAAM,CAAA;IACT,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,GAAG,EAAE,CAAA;IACZ,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,aAAa,CAAA;CACrB;AACD,MAAM,WAAW,IAAK,SAAQ,YAAY;IAAG,GAAG,EAAE,MAAM,CAAA;CAAE;AAqB1D;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,MAAM,CAkBlD;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,aAAa,CAqBnD;AAED,oGAAoG;AACpG,wBAAgB,cAAc,CAAC,CAAC,EAAE,aAAa,GAAG,UAAU,CAO3D;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,YAAY,GAAG,UAAU,CAMtD;AAED,MAAM,WAAW,YAAY;IAC3B,kBAAkB,EAAE,UAAU,CAAA;IAC9B,kEAAkE;IAClE,EAAE,EAAE,MAAM,CAAA;IACV,gFAAgF;IAChF,mBAAmB,EAAE,UAAU,CAAA;IAC/B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,EAAE,CAAA;IACjB,KAAK,CAAC,EAAE,GAAG,EAAE,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,GAAG,CAAC,CAAA;IAC/B,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAA;CACnB;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,CAAC,EAAE,YAAY,GAAG,IAAI,CAuB/C;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,CAE7C;AAED,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,MAAM,CAEzD;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,IAAI,CAAA;IACR,0FAA0F;IAC1F,IAAI,EAAE,IAAI,CAAA;IACV,iFAAiF;IACjF,KAAK,EAAE;QAAE,GAAG,EAAE,GAAG,CAAC;QAAC,IAAI,EAAE,QAAQ,CAAA;KAAE,EAAE,CAAA;CACtC;AACD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAExF;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,UAAU,CAiEjE;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,YAAY,EAAE,MAAM,GAAG,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,MAAM,EAAE,aAAa,CAAC,EAAE,MAAM,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAOtL"}
|
package/dist/card.js
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
import { schnorr } from '@noble/curves/secp256k1.js';
|
|
2
|
+
import { base64urlnopad } from '@scure/base';
|
|
3
|
+
import { sha256 } from '@noble/hashes/sha2.js';
|
|
4
|
+
import { bytesToHex, hexToBytes, utf8ToBytes } from '@noble/hashes/utils.js';
|
|
5
|
+
import { verifyLinkCard, isRelayUrl } from './link-card.js';
|
|
6
|
+
export const CARD_DOMAIN = 'nostr-contact-card:v1';
|
|
7
|
+
export const MAX_CARD_BYTES = 16 * 1024;
|
|
8
|
+
export const MAX_AGE_SECONDS = 30 * 24 * 3600;
|
|
9
|
+
export const MAX_RELAYS = 8;
|
|
10
|
+
export const MAX_BOXES = 4;
|
|
11
|
+
/** Longest name, display name or persona label, in code points. */
|
|
12
|
+
export const MAX_NAME = 100;
|
|
13
|
+
export const MAX_PERSONAS = 16;
|
|
14
|
+
const HEX64 = /^[0-9a-f]{64}$/, HEX128 = /^[0-9a-f]{128}$/, HEX32 = /^[0-9a-f]{32}$/;
|
|
15
|
+
const B64URL = /^[A-Za-z0-9_-]+$/;
|
|
16
|
+
const CARRIER = /^[A-Za-z0-9._-]{1,32}$/;
|
|
17
|
+
/** What no text field may carry: control, surrogate, unassigned, private-use, line and paragraph separators. */
|
|
18
|
+
const UNPRINTABLE = /[\p{Cc}\p{Cs}\p{Cn}\p{Co}\p{Zl}\p{Zp}]/u;
|
|
19
|
+
/** Invisible and direction-changing format characters that spoof a name; the format characters emoji need are handled apart. */
|
|
20
|
+
const INVISIBLE = /[\u200B\u200C\u200E\u200F\u202A-\u202E\u2060-\u2064\u2066-\u2069\uFEFF\u00AD\u061C\u180E]/u;
|
|
21
|
+
const VISIBLE = /[\p{L}\p{N}\p{S}\p{P}]/u;
|
|
22
|
+
const MARK_RUN = /\p{M}{5}/u;
|
|
23
|
+
const PICTOGRAPHIC = /\p{Extended_Pictographic}/u;
|
|
24
|
+
// base64url without padding, as the draft specifies; @scure/base is the
|
|
25
|
+
// same family as the curves and hashes and runs in a browser.
|
|
26
|
+
const b64url = {
|
|
27
|
+
encode: (b) => base64urlnopad.encode(b),
|
|
28
|
+
decode: (s) => base64urlnopad.decode(s.replace(/=+$/, '')),
|
|
29
|
+
};
|
|
30
|
+
const sha256hex = (b) => bytesToHex(sha256(b));
|
|
31
|
+
const utf8Strict = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true });
|
|
32
|
+
/**
|
|
33
|
+
* A name, display name or persona label a person will see: 1 to 100 code
|
|
34
|
+
* points, at least one visible one, no control, surrogate, unassigned or
|
|
35
|
+
* private-use character, no separator other than an ordinary space and none
|
|
36
|
+
* of those at the ends, no invisible or direction-changing format character,
|
|
37
|
+
* no run of five combining marks. The format characters emoji sequences use
|
|
38
|
+
* (the zero-width joiner and the tag characters) are allowed only beside a
|
|
39
|
+
* pictographic character, so a family or a flag reads and a hidden joiner
|
|
40
|
+
* does not.
|
|
41
|
+
*/
|
|
42
|
+
export function isGoodName(s) {
|
|
43
|
+
if (typeof s !== 'string')
|
|
44
|
+
return false;
|
|
45
|
+
const cps = [...s];
|
|
46
|
+
if (cps.length === 0 || cps.length > MAX_NAME)
|
|
47
|
+
return false;
|
|
48
|
+
if (UNPRINTABLE.test(s) || INVISIBLE.test(s) || MARK_RUN.test(s) || !VISIBLE.test(s))
|
|
49
|
+
return false;
|
|
50
|
+
if (s.startsWith(' ') || s.endsWith(' '))
|
|
51
|
+
return false;
|
|
52
|
+
for (let i = 0; i < cps.length; i++) {
|
|
53
|
+
const c = cps[i];
|
|
54
|
+
const code = c.codePointAt(0);
|
|
55
|
+
if (/\p{Zs}/u.test(c) && c !== ' ')
|
|
56
|
+
return false;
|
|
57
|
+
if (/\p{Cf}/u.test(c)) {
|
|
58
|
+
const near = (cps[i - 1] ?? '') + (cps[i + 1] ?? '');
|
|
59
|
+
if (code === 0x200d && PICTOGRAPHIC.test(near))
|
|
60
|
+
continue;
|
|
61
|
+
if (code >= 0xe0020 && code <= 0xe007f && PICTOGRAPHIC.test(cps.slice(Math.max(0, i - 8), i).join('')))
|
|
62
|
+
continue;
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
const goodText = isGoodName;
|
|
69
|
+
/**
|
|
70
|
+
* A bond handshake with only the fields the draft names, each checked, in
|
|
71
|
+
* canonical key order. Throws with a `handshake:` message on anything else.
|
|
72
|
+
*/
|
|
73
|
+
export function cleanBond(p) {
|
|
74
|
+
if (!p || typeof p !== 'object' || Array.isArray(p))
|
|
75
|
+
throw new Error('handshake: not an object');
|
|
76
|
+
const h = p;
|
|
77
|
+
if (h.v !== undefined && h.v !== 1)
|
|
78
|
+
throw new Error('handshake: v must be 1');
|
|
79
|
+
const pubkey = typeof h.pubkey === 'string' ? h.pubkey.toLowerCase() : '';
|
|
80
|
+
const nonce = typeof h.nonce === 'string' ? h.nonce.toLowerCase() : '';
|
|
81
|
+
if (!HEX64.test(pubkey))
|
|
82
|
+
throw new Error('handshake: pubkey must be 64 hex chars');
|
|
83
|
+
if (!HEX32.test(nonce))
|
|
84
|
+
throw new Error('handshake: nonce must be 32 hex chars');
|
|
85
|
+
if (h.displayName !== undefined && !goodText(h.displayName))
|
|
86
|
+
throw new Error('handshake: displayName');
|
|
87
|
+
const out = { v: 1, pubkey, nonce };
|
|
88
|
+
if (h.displayName !== undefined)
|
|
89
|
+
out.displayName = h.displayName;
|
|
90
|
+
if (h.personas !== undefined) {
|
|
91
|
+
if (!Array.isArray(h.personas) || h.personas.length > MAX_PERSONAS)
|
|
92
|
+
throw new Error('handshake: personas');
|
|
93
|
+
out.personas = h.personas.map((x) => {
|
|
94
|
+
const pk = x && typeof x === 'object' && typeof x.pubkey === 'string' ? x.pubkey.toLowerCase() : '';
|
|
95
|
+
if (!HEX64.test(pk))
|
|
96
|
+
throw new Error('handshake: persona pubkey');
|
|
97
|
+
if (x.label !== undefined && !goodText(x.label))
|
|
98
|
+
throw new Error('handshake: persona label');
|
|
99
|
+
return x.label !== undefined ? { pubkey: pk, label: x.label } : { pubkey: pk };
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
return out;
|
|
103
|
+
}
|
|
104
|
+
/** The canonical bytes of a bond handshake: fixed key order, no whitespace, absent keys omitted. */
|
|
105
|
+
export function handshakeBytes(p) {
|
|
106
|
+
const c = cleanBond(p);
|
|
107
|
+
const o = { v: 1, pubkey: c.pubkey };
|
|
108
|
+
if (c.displayName !== undefined)
|
|
109
|
+
o.displayName = c.displayName;
|
|
110
|
+
o.nonce = c.nonce;
|
|
111
|
+
if (c.personas !== undefined)
|
|
112
|
+
o.personas = c.personas;
|
|
113
|
+
return utf8ToBytes(JSON.stringify(o));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* §2 of the draft: the digest the card's signature covers. Fields are
|
|
117
|
+
* colon-joined; every field that could carry a separator is constrained by
|
|
118
|
+
* `readCard` step 2 (relays no comma, box cards base64url, carriers a
|
|
119
|
+
* short token alphabet and never an empty list, attest no colon, and no
|
|
120
|
+
* empty name or attest, which would hash the same as absence) so no two
|
|
121
|
+
* well-formed cards share a digest.
|
|
122
|
+
*/
|
|
123
|
+
export function cardDigest(c) {
|
|
124
|
+
const box = (b) => `${b.p}/${b.claim}/${b.card}/${(b.carriers ?? []).join('+')}`;
|
|
125
|
+
const s = [CARD_DOMAIN, c.p, c.rz, String(c.issued), String(c.expires), c.eph,
|
|
126
|
+
c.relays.join(','), c.boxes.map(box).join(','), c.attest ?? '',
|
|
127
|
+
c.bond ? sha256hex(handshakeBytes(c.bond)) : '', sha256hex(utf8ToBytes(c.name ?? ''))].join(':');
|
|
128
|
+
return sha256(utf8ToBytes(s));
|
|
129
|
+
}
|
|
130
|
+
/** Build and sign a card. Throws when it would not fit or would not verify. */
|
|
131
|
+
export function buildCard(o) {
|
|
132
|
+
const now = (o.now ?? (() => Math.floor(Date.now() / 1000)))();
|
|
133
|
+
const ttl = o.ttlSeconds ?? MAX_AGE_SECONDS;
|
|
134
|
+
if (ttl <= 0 || ttl > MAX_AGE_SECONDS)
|
|
135
|
+
throw new Error('ttl must be within 30 days');
|
|
136
|
+
const unsigned = {
|
|
137
|
+
v: 1,
|
|
138
|
+
p: bytesToHex(schnorr.getPublicKey(o.identityPrivateKey)),
|
|
139
|
+
rz: o.rz,
|
|
140
|
+
...(o.name !== undefined ? { name: o.name } : {}),
|
|
141
|
+
issued: now,
|
|
142
|
+
expires: now + ttl,
|
|
143
|
+
relays: o.relays ?? [],
|
|
144
|
+
boxes: o.boxes ?? [],
|
|
145
|
+
eph: bytesToHex(schnorr.getPublicKey(o.ephemeralPrivateKey)),
|
|
146
|
+
...(o.attest !== undefined ? { attest: o.attest } : {}),
|
|
147
|
+
...(o.bond !== undefined ? { bond: cleanBond({ v: 1, ...o.bond }) } : {}),
|
|
148
|
+
};
|
|
149
|
+
const card = { ...unsigned, sig: bytesToHex(schnorr.sign(cardDigest(unsigned), o.identityPrivateKey)) };
|
|
150
|
+
const encoded = encodeCard(card);
|
|
151
|
+
if (encoded.length > MAX_CARD_BYTES)
|
|
152
|
+
throw new Error('card exceeds 16 KiB; drop a box');
|
|
153
|
+
const r = readCard(encoded, now);
|
|
154
|
+
if (!r.ok)
|
|
155
|
+
throw new Error(`built a card that does not read: step ${r.step} ${r.reason}`);
|
|
156
|
+
return card;
|
|
157
|
+
}
|
|
158
|
+
export function encodeCard(card) {
|
|
159
|
+
return b64url.encode(utf8ToBytes(JSON.stringify(card)));
|
|
160
|
+
}
|
|
161
|
+
/** A link a person can send: the card rides after `#`, so no server sees it. */
|
|
162
|
+
export function cardLink(base, card) {
|
|
163
|
+
return `${base.replace(/#.*$/, '')}#${encodeCard(card)}`;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* §3 steps 1 to 5. The result names the step that failed, for the words a
|
|
167
|
+
* client shows. The card returned is rebuilt from the fields the draft
|
|
168
|
+
* names: an extra key on the wire, `__proto__` included, never reaches the
|
|
169
|
+
* caller under a verified signature.
|
|
170
|
+
*/
|
|
171
|
+
export function readCard(encoded, now) {
|
|
172
|
+
if (typeof encoded !== 'string')
|
|
173
|
+
return { ok: false, step: 1, reason: 'size' };
|
|
174
|
+
const body = encoded.slice(encoded.lastIndexOf('#') + 1);
|
|
175
|
+
if (body.length === 0 || body.length > MAX_CARD_BYTES)
|
|
176
|
+
return { ok: false, step: 1, reason: 'size' };
|
|
177
|
+
if (!Number.isFinite(now))
|
|
178
|
+
return { ok: false, step: 3, reason: 'clock' };
|
|
179
|
+
let c;
|
|
180
|
+
// Strict UTF-8: a byte sequence that is not UTF-8 is not a card, not a card with U+FFFD in it.
|
|
181
|
+
try {
|
|
182
|
+
c = JSON.parse(utf8Strict.decode(b64url.decode(body)));
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return { ok: false, step: 1, reason: 'decode' };
|
|
186
|
+
}
|
|
187
|
+
if (!c || typeof c !== 'object' || Array.isArray(c) || c.v !== 1)
|
|
188
|
+
return { ok: false, step: 1, reason: 'version' };
|
|
189
|
+
const hex = { p: '', rz: '', eph: '' };
|
|
190
|
+
for (const f of ['p', 'rz', 'eph']) {
|
|
191
|
+
if (typeof c[f] !== 'string')
|
|
192
|
+
return { ok: false, step: 2, reason: f };
|
|
193
|
+
hex[f] = c[f].toLowerCase();
|
|
194
|
+
if (!HEX64.test(hex[f]))
|
|
195
|
+
return { ok: false, step: 2, reason: f };
|
|
196
|
+
}
|
|
197
|
+
if (typeof c.sig !== 'string')
|
|
198
|
+
return { ok: false, step: 2, reason: 'sig' };
|
|
199
|
+
const sig = c.sig.toLowerCase();
|
|
200
|
+
if (!HEX128.test(sig))
|
|
201
|
+
return { ok: false, step: 2, reason: 'sig' };
|
|
202
|
+
if (c.name !== undefined && !goodText(c.name))
|
|
203
|
+
return { ok: false, step: 2, reason: 'name' };
|
|
204
|
+
if (!Array.isArray(c.relays) || c.relays.length > MAX_RELAYS || c.relays.some((r) => !isRelayUrl(r)))
|
|
205
|
+
return { ok: false, step: 2, reason: 'relays' };
|
|
206
|
+
if (!Array.isArray(c.boxes) || c.boxes.length > MAX_BOXES)
|
|
207
|
+
return { ok: false, step: 2, reason: 'boxes' };
|
|
208
|
+
const boxesClean = [];
|
|
209
|
+
for (const b of c.boxes) {
|
|
210
|
+
if (!b || typeof b !== 'object' || Array.isArray(b))
|
|
211
|
+
return { ok: false, step: 2, reason: 'box' };
|
|
212
|
+
const p = typeof b.p === 'string' ? b.p.toLowerCase() : '';
|
|
213
|
+
const claim = typeof b.claim === 'string' ? b.claim.toLowerCase() : '';
|
|
214
|
+
if (!HEX64.test(p))
|
|
215
|
+
return { ok: false, step: 2, reason: 'box p' };
|
|
216
|
+
if (!HEX64.test(claim))
|
|
217
|
+
return { ok: false, step: 2, reason: 'box claim' };
|
|
218
|
+
if (typeof b.card !== 'string' || !B64URL.test(b.card))
|
|
219
|
+
return { ok: false, step: 2, reason: 'box card' };
|
|
220
|
+
if (b.carriers !== undefined && (!Array.isArray(b.carriers) || b.carriers.length === 0 || b.carriers.length > 8 || b.carriers.some((x) => typeof x !== 'string' || !CARRIER.test(x))))
|
|
221
|
+
return { ok: false, step: 2, reason: 'box carriers' };
|
|
222
|
+
boxesClean.push({ p, claim, card: b.card, ...(b.carriers !== undefined ? { carriers: [...b.carriers] } : {}) });
|
|
223
|
+
}
|
|
224
|
+
if (c.attest !== undefined && (typeof c.attest !== 'string' || c.attest.length === 0 || c.attest.includes(':') || UNPRINTABLE.test(c.attest) || INVISIBLE.test(c.attest) || /\p{Z}/u.test(c.attest) || c.attest.length > 512))
|
|
225
|
+
return { ok: false, step: 2, reason: 'attest' };
|
|
226
|
+
let bond;
|
|
227
|
+
if (c.bond !== undefined) {
|
|
228
|
+
try {
|
|
229
|
+
bond = cleanBond(c.bond);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
return { ok: false, step: 2, reason: 'bond' };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
if (!Number.isSafeInteger(c.issued) || !Number.isSafeInteger(c.expires))
|
|
236
|
+
return { ok: false, step: 3, reason: 'times' };
|
|
237
|
+
if (c.expires <= now)
|
|
238
|
+
return { ok: false, step: 3, reason: 'expired' };
|
|
239
|
+
if (c.expires <= c.issued || c.expires - c.issued > MAX_AGE_SECONDS)
|
|
240
|
+
return { ok: false, step: 3, reason: 'expiry window' };
|
|
241
|
+
if (c.issued > now + 300)
|
|
242
|
+
return { ok: false, step: 3, reason: 'issued in the future' };
|
|
243
|
+
const unsigned = {
|
|
244
|
+
v: 1,
|
|
245
|
+
p: hex.p,
|
|
246
|
+
rz: hex.rz,
|
|
247
|
+
...(c.name !== undefined ? { name: c.name } : {}),
|
|
248
|
+
issued: c.issued,
|
|
249
|
+
expires: c.expires,
|
|
250
|
+
relays: [...c.relays],
|
|
251
|
+
boxes: boxesClean,
|
|
252
|
+
eph: hex.eph,
|
|
253
|
+
...(c.attest !== undefined ? { attest: c.attest } : {}),
|
|
254
|
+
...(bond ? { bond } : {}),
|
|
255
|
+
};
|
|
256
|
+
if (!schnorr.verify(hexToBytes(sig), cardDigest(unsigned), hexToBytes(unsigned.p)))
|
|
257
|
+
return { ok: false, step: 4, reason: 'signature' };
|
|
258
|
+
const card = { ...unsigned, sig };
|
|
259
|
+
const boxes = [];
|
|
260
|
+
for (const b of card.boxes) {
|
|
261
|
+
let bytes;
|
|
262
|
+
try {
|
|
263
|
+
bytes = b64url.decode(b.card);
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
return { ok: false, step: 5, reason: 'link: decode' };
|
|
267
|
+
}
|
|
268
|
+
const v = verifyLinkCard(bytes, now);
|
|
269
|
+
if (!v.ok)
|
|
270
|
+
return { ok: false, step: 5, reason: `link: ${v.reason}` };
|
|
271
|
+
boxes.push({ box: b, link: v.card });
|
|
272
|
+
}
|
|
273
|
+
return { ok: true, card, boxes };
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* §3 step 6: accept a fresh Link card from a box only under the node id the
|
|
277
|
+
* person endorsed. Pass the highest serial previously accepted for that node
|
|
278
|
+
* id, persisted by the caller; without it any unexpired old card of the same
|
|
279
|
+
* node replays, which is rule 8's job to stop and this function cannot do
|
|
280
|
+
* alone.
|
|
281
|
+
*/
|
|
282
|
+
export function refreshBox(pinnedNodeId, freshCard, now, highestSerial) {
|
|
283
|
+
const pin = pinnedNodeId instanceof Uint8Array ? bytesToHex(pinnedNodeId) : typeof pinnedNodeId === 'string' ? pinnedNodeId.toLowerCase() : '';
|
|
284
|
+
if (!HEX64.test(pin))
|
|
285
|
+
return { ok: false, reason: 'pinned node id is not 32 bytes of hex' };
|
|
286
|
+
const v = verifyLinkCard(freshCard, now, highestSerial);
|
|
287
|
+
if (!v.ok)
|
|
288
|
+
return { ok: false, reason: v.reason };
|
|
289
|
+
if (v.card.nodeId !== pin)
|
|
290
|
+
return { ok: false, reason: 'node id is not the endorsed one' };
|
|
291
|
+
return { ok: true, link: v.card };
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=card.js.map
|
package/dist/card.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"card.js","sourceRoot":"","sources":["../src/card.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { CARD_DOMAIN, MAX_CARD_BYTES, MAX_AGE_SECONDS, MAX_RELAYS, MAX_BOXES, MAX_NAME, MAX_PERSONAS, isGoodName, cleanBond, handshakeBytes, cardDigest, buildCard, encodeCard, cardLink, readCard, refreshBox } from './card.js';
|
|
2
|
+
export type { BondHandshake, Box, UnsignedCard, Card, BuildOptions, ReadOk, ReadResult } from './card.js';
|
|
3
|
+
export { verifyLinkCard, verifyStrict, isRelayUrl, buildLinkCard, LINK_CARD_MAX, LINK_CARD_MIN, LINK_CARD_MAX_AGE } from './link-card.js';
|
|
4
|
+
export type { LinkCard, LinkHint, LinkVerdict } from './link-card.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACjO,YAAY,EAAE,aAAa,EAAE,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AACzG,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACzI,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { CARD_DOMAIN, MAX_CARD_BYTES, MAX_AGE_SECONDS, MAX_RELAYS, MAX_BOXES, MAX_NAME, MAX_PERSONAS, isGoodName, cleanBond, handshakeBytes, cardDigest, buildCard, encodeCard, cardLink, readCard, refreshBox } from './card.js';
|
|
2
|
+
export { verifyLinkCard, verifyStrict, isRelayUrl, buildLinkCard, LINK_CARD_MAX, LINK_CARD_MIN, LINK_CARD_MAX_AGE } from './link-card.js';
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAEjO,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA"}
|