@weaveprotocol/core 0.1.2 → 0.2.1
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/README.md +322 -45
- package/dist/doors/doors.d.ts +139 -0
- package/dist/doors/doors.d.ts.map +1 -0
- package/dist/doors/doors.js +210 -0
- package/dist/doors/doors.js.map +1 -0
- package/dist/doors/index.d.ts +9 -0
- package/dist/doors/index.d.ts.map +1 -0
- package/dist/doors/index.js +7 -0
- package/dist/doors/index.js.map +1 -0
- package/dist/identity/contact-key.d.ts +68 -0
- package/dist/identity/contact-key.d.ts.map +1 -0
- package/dist/identity/contact-key.js +185 -0
- package/dist/identity/contact-key.js.map +1 -0
- package/dist/index.d.ts +16 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -5
- package/dist/index.js.map +1 -1
- package/dist/network/index.d.ts +2 -0
- package/dist/network/index.d.ts.map +1 -1
- package/dist/network/index.js +1 -0
- package/dist/network/index.js.map +1 -1
- package/dist/network/mailbox.d.ts +49 -0
- package/dist/network/mailbox.d.ts.map +1 -0
- package/dist/network/mailbox.js +125 -0
- package/dist/network/mailbox.js.map +1 -0
- package/dist/network/mesh.d.ts +6 -0
- package/dist/network/mesh.d.ts.map +1 -1
- package/dist/network/mesh.js +11 -1
- package/dist/network/mesh.js.map +1 -1
- package/dist/network/multi-signaling.d.ts +12 -2
- package/dist/network/multi-signaling.d.ts.map +1 -1
- package/dist/network/multi-signaling.js +86 -14
- package/dist/network/multi-signaling.js.map +1 -1
- package/dist/network/peer-auth.d.ts +50 -16
- package/dist/network/peer-auth.d.ts.map +1 -1
- package/dist/network/peer-auth.js +52 -15
- package/dist/network/peer-auth.js.map +1 -1
- package/dist/node/carrier.d.ts +87 -0
- package/dist/node/carrier.d.ts.map +1 -1
- package/dist/node/carrier.js +180 -59
- package/dist/node/carrier.js.map +1 -1
- package/dist/node/copy.d.ts.map +1 -1
- package/dist/node/copy.js +6 -3
- package/dist/node/copy.js.map +1 -1
- package/dist/node/host.d.ts +117 -0
- package/dist/node/host.d.ts.map +1 -0
- package/dist/node/host.js +192 -0
- package/dist/node/host.js.map +1 -0
- package/dist/node/index.d.ts +6 -2
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -0
- package/dist/node/index.js.map +1 -1
- package/dist/node/node.d.ts.map +1 -1
- package/dist/node/node.js +958 -25
- package/dist/node/node.js.map +1 -1
- package/dist/node/space-runtime.d.ts +42 -25
- package/dist/node/space-runtime.d.ts.map +1 -1
- package/dist/node/space-runtime.js +734 -35
- package/dist/node/space-runtime.js.map +1 -1
- package/dist/node/types.d.ts +375 -3
- package/dist/node/types.d.ts.map +1 -1
- package/dist/privacy/space-encryption.d.ts +16 -0
- package/dist/privacy/space-encryption.d.ts.map +1 -1
- package/dist/privacy/space-encryption.js +40 -0
- package/dist/privacy/space-encryption.js.map +1 -1
- package/dist/query/engine.js +1 -1
- package/dist/query/engine.js.map +1 -1
- package/dist/query/types.d.ts +7 -0
- package/dist/query/types.d.ts.map +1 -1
- package/dist/query/types.js.map +1 -1
- package/dist/react/use-query.d.ts +1 -1
- package/dist/react/use-query.d.ts.map +1 -1
- package/dist/records/topics.d.ts +21 -0
- package/dist/records/topics.d.ts.map +1 -0
- package/dist/records/topics.js +86 -0
- package/dist/records/topics.js.map +1 -0
- package/dist/schema/collection-def.d.ts +7 -0
- package/dist/schema/collection-def.d.ts.map +1 -1
- package/dist/schema/collection-def.js +4 -0
- package/dist/schema/collection-def.js.map +1 -1
- package/dist/schema/expression.d.ts +2 -0
- package/dist/schema/expression.d.ts.map +1 -1
- package/dist/schema/expression.js +1 -0
- package/dist/schema/expression.js.map +1 -1
- package/dist/schemas/contacts.d.ts +214 -0
- package/dist/schemas/contacts.d.ts.map +1 -0
- package/dist/schemas/contacts.js +98 -0
- package/dist/schemas/contacts.js.map +1 -0
- package/dist/schemas/index.d.ts +2 -0
- package/dist/schemas/index.d.ts.map +1 -1
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/index.js.map +1 -1
- package/dist/session/auth.d.ts.map +1 -1
- package/dist/session/auth.js +15 -3
- package/dist/session/auth.js.map +1 -1
- package/dist/session/connect.d.ts +25 -1
- package/dist/session/connect.d.ts.map +1 -1
- package/dist/session/connect.js +9 -2
- package/dist/session/connect.js.map +1 -1
- package/dist/session/hosting.d.ts +155 -0
- package/dist/session/hosting.d.ts.map +1 -0
- package/dist/session/hosting.js +160 -0
- package/dist/session/hosting.js.map +1 -0
- package/dist/space/account-registry.d.ts +6 -0
- package/dist/space/account-registry.d.ts.map +1 -1
- package/dist/space/account-registry.js +16 -4
- package/dist/space/account-registry.js.map +1 -1
- package/dist/space/notify.d.ts +88 -0
- package/dist/space/notify.d.ts.map +1 -0
- package/dist/space/notify.js +127 -0
- package/dist/space/notify.js.map +1 -0
- package/dist/space/pass.d.ts +6 -0
- package/dist/space/pass.d.ts.map +1 -1
- package/dist/space/pass.js +5 -2
- package/dist/space/pass.js.map +1 -1
- package/dist/space/roles.d.ts +71 -0
- package/dist/space/roles.d.ts.map +1 -1
- package/dist/space/roles.js +114 -0
- package/dist/space/roles.js.map +1 -1
- package/dist/space/space-access.d.ts +24 -0
- package/dist/space/space-access.d.ts.map +1 -1
- package/dist/space/space-access.js +24 -0
- package/dist/space/space-access.js.map +1 -1
- package/dist/space/space-manager.d.ts +35 -1
- package/dist/space/space-manager.d.ts.map +1 -1
- package/dist/space/space-manager.js +72 -25
- package/dist/space/space-manager.js.map +1 -1
- package/dist/storage/blob/memory.d.ts +9 -0
- package/dist/storage/blob/memory.d.ts.map +1 -0
- package/dist/storage/blob/memory.js +20 -0
- package/dist/storage/blob/memory.js.map +1 -0
- package/dist/storage/blob/s3.d.ts +16 -0
- package/dist/storage/blob/s3.d.ts.map +1 -0
- package/dist/storage/blob/s3.js +86 -0
- package/dist/storage/blob/s3.js.map +1 -0
- package/dist/storage/blob-store.d.ts +26 -0
- package/dist/storage/blob-store.d.ts.map +1 -0
- package/dist/storage/blob-store.js +2 -0
- package/dist/storage/blob-store.js.map +1 -0
- package/dist/storage/encrypted-adapter.d.ts +3 -3
- package/dist/storage/encrypted-adapter.js +3 -3
- package/dist/storage/folder-adapter.d.ts +8 -8
- package/dist/storage/folder-adapter.d.ts.map +1 -1
- package/dist/storage/folder-adapter.js +7 -7
- package/dist/storage/folder-reconcile.d.ts +12 -14
- package/dist/storage/folder-reconcile.d.ts.map +1 -1
- package/dist/storage/folder-reconcile.js +20 -14
- package/dist/storage/folder-reconcile.js.map +1 -1
- package/dist/storage/index.d.ts +0 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/index.js +0 -1
- package/dist/storage/index.js.map +1 -1
- package/dist/storage/indexeddb-adapter.d.ts.map +1 -1
- package/dist/storage/indexeddb-adapter.js +8 -9
- package/dist/storage/indexeddb-adapter.js.map +1 -1
- package/dist/storage/mirror.d.ts +68 -0
- package/dist/storage/mirror.d.ts.map +1 -0
- package/dist/storage/mirror.js +174 -0
- package/dist/storage/mirror.js.map +1 -0
- package/dist/storage/segment.d.ts +20 -0
- package/dist/storage/segment.d.ts.map +1 -0
- package/dist/storage/segment.js +27 -0
- package/dist/storage/segment.js.map +1 -0
- package/dist/storage/storage-provider.d.ts +36 -40
- package/dist/storage/storage-provider.d.ts.map +1 -1
- package/dist/storage/storage-provider.js +208 -117
- package/dist/storage/storage-provider.js.map +1 -1
- package/dist/sync/index.d.ts +1 -1
- package/dist/sync/index.d.ts.map +1 -1
- package/dist/sync/index.js +1 -1
- package/dist/sync/index.js.map +1 -1
- package/dist/sync/negentropy.d.ts +68 -0
- package/dist/sync/negentropy.d.ts.map +1 -0
- package/dist/sync/negentropy.js +379 -0
- package/dist/sync/negentropy.js.map +1 -0
- package/dist/sync/sync-engine.d.ts +45 -13
- package/dist/sync/sync-engine.d.ts.map +1 -1
- package/dist/sync/sync-engine.js +290 -207
- package/dist/sync/sync-engine.js.map +1 -1
- package/dist/sync/sync-messages.d.ts +42 -32
- package/dist/sync/sync-messages.d.ts.map +1 -1
- package/dist/sync/sync-messages.js +1 -1
- package/dist/sync/sync-messages.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/hash.d.ts +9 -0
- package/dist/utils/hash.d.ts.map +1 -1
- package/dist/utils/hash.js +33 -0
- package/dist/utils/hash.js.map +1 -1
- package/package.json +8 -3
- package/dist/storage/mst.d.ts +0 -121
- package/dist/storage/mst.d.ts.map +0 -1
- package/dist/storage/mst.js +0 -402
- package/dist/storage/mst.js.map +0 -1
- package/dist/sync/anti-entropy.d.ts +0 -49
- package/dist/sync/anti-entropy.d.ts.map +0 -1
- package/dist/sync/anti-entropy.js +0 -62
- package/dist/sync/anti-entropy.js.map +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module doors
|
|
3
|
+
* Doors: how someone you share no space with can ask to become your contact.
|
|
4
|
+
*
|
|
5
|
+
* A DID is a name, not an address — knowing it must not be enough to reach
|
|
6
|
+
* you. A **door** is an address you hand out on purpose, and can close:
|
|
7
|
+
*
|
|
8
|
+
* - a **door key**, derived from your contact key and the door's id
|
|
9
|
+
* (`deriveDoorKeyBytes`), which says nothing about the account behind it,
|
|
10
|
+
* and a **signing key** beside it (`deriveDoorSignKeyBytes`) that proves
|
|
11
|
+
* ownership of the door — to a relay clearing its mailbox, and to a knocker
|
|
12
|
+
* when you answer;
|
|
13
|
+
* - the **relays** whose mailboxes hold knocks on it — two or three, chosen by
|
|
14
|
+
* you, so no one relay can shut it.
|
|
15
|
+
*
|
|
16
|
+
* Both travel in a **door code** (a link, a QR code, a line in a bio). Someone
|
|
17
|
+
* with it **knocks**: makes a private space for the two of you, and leaves its
|
|
18
|
+
* invite, sealed to the door key, in the door's mailboxes. The knock is signed
|
|
19
|
+
* by the knocker's session key under their account's note, like a record, so
|
|
20
|
+
* it proves who knocked before anyone joins anything. Opening the door is
|
|
21
|
+
* joining that space.
|
|
22
|
+
*
|
|
23
|
+
* ```
|
|
24
|
+
* code = base64url(JSON { v: 1, key, sign, relays, name? })
|
|
25
|
+
* topic = base64url(SHA-256("weave/door-topic/v1|" + sign))
|
|
26
|
+
* knock = sealFor(key, { body, sig }, "weave/knock/v1|" + key)
|
|
27
|
+
* body = { v: 1, door: key, from, name, invite, note?, at, session, proof }
|
|
28
|
+
* sig = session key signs canonical(body)
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* The relay sees a topic and a sealed blob: not whose door it is, not who
|
|
32
|
+
* knocked, not what they said. See `docs/spec/07-doors.md`.
|
|
33
|
+
*/
|
|
34
|
+
import type { CryptoProvider } from '../types.js';
|
|
35
|
+
/** A door names at most this many relays: enough that one going away doesn't matter */
|
|
36
|
+
export declare const MAX_DOOR_RELAYS = 3;
|
|
37
|
+
/** How long a knock waits in a mailbox, and so how old one may be when opened */
|
|
38
|
+
export declare const KNOCK_TTL_SECONDS: number;
|
|
39
|
+
/**
|
|
40
|
+
* How far a knock's own time may be from when the relay took it. A knock is
|
|
41
|
+
* dropped as soon as it is signed, so its time is checked against the relay's
|
|
42
|
+
* — which the knocker can't choose — and a note that ran out can't be used by
|
|
43
|
+
* dating a knock back to when it was good.
|
|
44
|
+
*/
|
|
45
|
+
export declare const KNOCK_DROP_WINDOW_SECONDS = 600;
|
|
46
|
+
/** What a door code says: where to knock, and whose door the owner says it is */
|
|
47
|
+
export interface DoorCode {
|
|
48
|
+
readonly v: 1;
|
|
49
|
+
/** The door key's public half: a compressed P-256 point, base64url. Knocks are sealed to it. */
|
|
50
|
+
readonly key: string;
|
|
51
|
+
/** The door's signing key's public half, likewise. Its hash is the door's topic. */
|
|
52
|
+
readonly sign: string;
|
|
53
|
+
/** Relays whose mailboxes hold knocks on it, 1–3 */
|
|
54
|
+
readonly relays: ReadonlyArray<string>;
|
|
55
|
+
/** Who the owner says they are — shown to the knocker, and proves nothing */
|
|
56
|
+
readonly name?: string;
|
|
57
|
+
}
|
|
58
|
+
/** What a knock carries, signed by the knocker's session key */
|
|
59
|
+
export interface KnockBody {
|
|
60
|
+
readonly v: 1;
|
|
61
|
+
/** The door knocked on: its key. Binds the knock to this door. */
|
|
62
|
+
readonly door: string;
|
|
63
|
+
/** The knocker's account */
|
|
64
|
+
readonly from: string;
|
|
65
|
+
/** The name they give */
|
|
66
|
+
readonly name: string;
|
|
67
|
+
/** The invite to the space for two they made */
|
|
68
|
+
readonly invite: string;
|
|
69
|
+
readonly note?: string;
|
|
70
|
+
/** When it was signed, Unix seconds */
|
|
71
|
+
readonly at: number;
|
|
72
|
+
/** The session key that signed it */
|
|
73
|
+
readonly session: string;
|
|
74
|
+
/** The note from `from` to `session`: a UCAN whose chain ends at `from` */
|
|
75
|
+
readonly proof: string;
|
|
76
|
+
}
|
|
77
|
+
/** A knock that opened and checked out */
|
|
78
|
+
export interface OpenedKnock {
|
|
79
|
+
readonly from: string;
|
|
80
|
+
readonly name: string;
|
|
81
|
+
readonly note?: string;
|
|
82
|
+
readonly invite: string;
|
|
83
|
+
/** The id of the space for two */
|
|
84
|
+
readonly pairSpace: string;
|
|
85
|
+
/** When it was signed, ms */
|
|
86
|
+
readonly at: number;
|
|
87
|
+
}
|
|
88
|
+
/** Cuts text to at most `max` characters without splitting one (a surrogate pair stays whole) */
|
|
89
|
+
export declare function clip(text: string, max: number): string;
|
|
90
|
+
/** Encodes a door code: what goes in a link or a QR code */
|
|
91
|
+
export declare function encodeDoorCode(code: Omit<DoorCode, 'v'>): string;
|
|
92
|
+
/**
|
|
93
|
+
* Reads a door code, or a link carrying one after `#door=` or `door=`.
|
|
94
|
+
* @throws When it isn't one, saying why
|
|
95
|
+
*/
|
|
96
|
+
export declare function parseDoorCode(text: string): DoorCode;
|
|
97
|
+
/** Why a value is not a door code, or null */
|
|
98
|
+
export declare function checkDoorCode(value: unknown): string | null;
|
|
99
|
+
/**
|
|
100
|
+
* The mailbox topic of a door: a hash of its signing key. The relay can't tell
|
|
101
|
+
* whose door it is, and can check that whoever clears it holds that key.
|
|
102
|
+
*/
|
|
103
|
+
export declare function doorTopic(sign: string): Promise<string>;
|
|
104
|
+
/**
|
|
105
|
+
* What a door's owner signs to clear knocks from a relay's mailbox: the topic,
|
|
106
|
+
* the relay's one-time challenge, and which knocks (`*` for all of them).
|
|
107
|
+
*/
|
|
108
|
+
export declare const purgeMessage: (topic: string, nonce: string, ids: ReadonlyArray<string> | null) => Uint8Array<ArrayBufferLike>;
|
|
109
|
+
/** Signs a relay's purge challenge with the door's signing key */
|
|
110
|
+
export declare function signPurge(signKey: Uint8Array, topic: string, nonce: string, ids: ReadonlyArray<string> | null): Promise<string>;
|
|
111
|
+
export declare function signAnswer(signKey: Uint8Array, pairSpace: string, did: string): Promise<string>;
|
|
112
|
+
export declare function checkAnswer(sign: string, pairSpace: string, did: string, signature: string): Promise<boolean>;
|
|
113
|
+
/** A knock's id: the hash of its sealed blob, as relays file it */
|
|
114
|
+
export declare function knockId(blob: string): Promise<string>;
|
|
115
|
+
/**
|
|
116
|
+
* Makes a knock: the body, signed by the session key, sealed to the door key.
|
|
117
|
+
* @returns The sealed blob, for relays' mailboxes
|
|
118
|
+
*/
|
|
119
|
+
export declare function sealKnock(door: string, knock: {
|
|
120
|
+
readonly from: string;
|
|
121
|
+
readonly name: string;
|
|
122
|
+
readonly invite: string;
|
|
123
|
+
readonly note?: string;
|
|
124
|
+
}, session: {
|
|
125
|
+
readonly did: string;
|
|
126
|
+
readonly key: CryptoKey;
|
|
127
|
+
readonly proof: string;
|
|
128
|
+
}, provider: CryptoProvider): Promise<string>;
|
|
129
|
+
/**
|
|
130
|
+
* Opens a knock left on a door, and checks it through: sealed to this door;
|
|
131
|
+
* signed by a session key that its account's note vouches for, for the whole
|
|
132
|
+
* account and not by an agent; signed when the relay took it; recent; and
|
|
133
|
+
* carrying an invite to a private space that account made.
|
|
134
|
+
* @param doorKey The door key's private scalar (`deriveDoorKeyBytes`)
|
|
135
|
+
* @param receivedAt When the relay took it, ms, as `fetch` says
|
|
136
|
+
* @returns The knock, or null when it is anything less
|
|
137
|
+
*/
|
|
138
|
+
export declare function openKnock(doorKey: Uint8Array, blob: string, receivedAt: number, provider: CryptoProvider): Promise<OpenedKnock | null>;
|
|
139
|
+
//# sourceMappingURL=doors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doors.d.ts","sourceRoot":"","sources":["../../src/doors/doors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import { contactKeyPair, contactPublicKey, isContactPublicKey, openSealed, sealFor, signWithScalar, verifyWithPoint } from '../identity/contact-key.js';
|
|
2
|
+
import { didToPublicKey } from '../identity/did.js';
|
|
3
|
+
import { resolveDelegationRoot, UCAN_CLOCK_SKEW_SECONDS } from '../identity/ucan.js';
|
|
4
|
+
import { isAgentNote } from '../identity/agent-note.js';
|
|
5
|
+
import { canonicalize } from '../schema/expression.js';
|
|
6
|
+
import { parseSpaceInvite } from '../space/space-manager.js';
|
|
7
|
+
import { checkSpace } from '../space/space-access.js';
|
|
8
|
+
import { checkRelays } from '../space/roles.js';
|
|
9
|
+
import { sha256 } from '../utils/hash.js';
|
|
10
|
+
import { base64UrlDecode, base64UrlEncode, utf8Decode, utf8Encode } from '../utils/encoding.js';
|
|
11
|
+
/** A door names at most this many relays: enough that one going away doesn't matter */
|
|
12
|
+
export const MAX_DOOR_RELAYS = 3;
|
|
13
|
+
/** How long a knock waits in a mailbox, and so how old one may be when opened */
|
|
14
|
+
export const KNOCK_TTL_SECONDS = 14 * 24 * 3600;
|
|
15
|
+
/**
|
|
16
|
+
* How far a knock's own time may be from when the relay took it. A knock is
|
|
17
|
+
* dropped as soon as it is signed, so its time is checked against the relay's
|
|
18
|
+
* — which the knocker can't choose — and a note that ran out can't be used by
|
|
19
|
+
* dating a knock back to when it was good.
|
|
20
|
+
*/
|
|
21
|
+
export const KNOCK_DROP_WINDOW_SECONDS = 600;
|
|
22
|
+
const MAX_NAME = 64;
|
|
23
|
+
const MAX_NOTE = 2000;
|
|
24
|
+
const MAX_INVITE = 6000;
|
|
25
|
+
const MAX_PROOF = 4096;
|
|
26
|
+
/** Cuts text to at most `max` characters without splitting one (a surrogate pair stays whole) */
|
|
27
|
+
export function clip(text, max) {
|
|
28
|
+
const chars = Array.from(text);
|
|
29
|
+
return chars.length <= max ? text : chars.slice(0, max).join('');
|
|
30
|
+
}
|
|
31
|
+
/** Encodes a door code: what goes in a link or a QR code */
|
|
32
|
+
export function encodeDoorCode(code) {
|
|
33
|
+
const problem = checkDoorCode({ v: 1, ...code });
|
|
34
|
+
if (problem)
|
|
35
|
+
throw new Error(problem);
|
|
36
|
+
return base64UrlEncode(utf8Encode(canonicalize({ v: 1, key: code.key, sign: code.sign, relays: [...code.relays], ...(code.name ? { name: code.name } : {}) })));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Reads a door code, or a link carrying one after `#door=` or `door=`.
|
|
40
|
+
* @throws When it isn't one, saying why
|
|
41
|
+
*/
|
|
42
|
+
export function parseDoorCode(text) {
|
|
43
|
+
const trimmed = text.trim();
|
|
44
|
+
const found = /(?:^|[#?&])door=([A-Za-z0-9_-]+)/.exec(trimmed);
|
|
45
|
+
const raw = found ? found[1] : trimmed;
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(utf8Decode(base64UrlDecode(raw)));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
throw new Error('That is not a door code — it may be cut short.');
|
|
52
|
+
}
|
|
53
|
+
const problem = checkDoorCode(parsed);
|
|
54
|
+
if (problem)
|
|
55
|
+
throw new Error(`That door code doesn't work: ${problem}`);
|
|
56
|
+
const code = parsed;
|
|
57
|
+
return Object.freeze({ v: 1, key: code.key, sign: code.sign, relays: Object.freeze([...code.relays]), ...(code.name ? { name: code.name } : {}) });
|
|
58
|
+
}
|
|
59
|
+
/** Why a value is not a door code, or null */
|
|
60
|
+
export function checkDoorCode(value) {
|
|
61
|
+
const code = value;
|
|
62
|
+
if (!code || typeof code !== 'object' || code.v !== 1)
|
|
63
|
+
return 'it is not a version 1 door';
|
|
64
|
+
if (!isContactPublicKey(code.key))
|
|
65
|
+
return 'its key is not a P-256 public key';
|
|
66
|
+
if (!isContactPublicKey(code.sign) || code.sign === code.key)
|
|
67
|
+
return 'its signing key is not a P-256 public key of its own';
|
|
68
|
+
if (!Array.isArray(code.relays) || code.relays.length === 0 || code.relays.length > MAX_DOOR_RELAYS) {
|
|
69
|
+
return `it names 1–${MAX_DOOR_RELAYS} relays`;
|
|
70
|
+
}
|
|
71
|
+
const relays = checkRelays(code.relays);
|
|
72
|
+
if (relays)
|
|
73
|
+
return relays;
|
|
74
|
+
if (code.name !== undefined && (typeof code.name !== 'string' || Array.from(code.name).length > MAX_NAME))
|
|
75
|
+
return `its name is text of at most ${MAX_NAME} characters`;
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The mailbox topic of a door: a hash of its signing key. The relay can't tell
|
|
80
|
+
* whose door it is, and can check that whoever clears it holds that key.
|
|
81
|
+
*/
|
|
82
|
+
export async function doorTopic(sign) {
|
|
83
|
+
return base64UrlEncode(await sha256(utf8Encode(`weave/door-topic/v1|${sign}`)));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* What a door's owner signs to clear knocks from a relay's mailbox: the topic,
|
|
87
|
+
* the relay's one-time challenge, and which knocks (`*` for all of them).
|
|
88
|
+
*/
|
|
89
|
+
export const purgeMessage = (topic, nonce, ids) => utf8Encode(`weave/door-purge/v1|${topic}|${nonce}|${ids ? [...ids].sort().join(',') : '*'}`);
|
|
90
|
+
/** Signs a relay's purge challenge with the door's signing key */
|
|
91
|
+
export function signPurge(signKey, topic, nonce, ids) {
|
|
92
|
+
return signWithScalar(signKey, purgeMessage(topic, nonce, ids));
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The answer to a knock: the door's owner, signing with the door's signing key
|
|
96
|
+
* that the account which joined the space for two is theirs. Without it,
|
|
97
|
+
* whoever joined first — someone the invite was passed on to — would be taken
|
|
98
|
+
* for the person behind the door.
|
|
99
|
+
*/
|
|
100
|
+
const answerMessage = (pairSpace, did) => utf8Encode(`weave/knock-answer/v1|${pairSpace}|${did}`);
|
|
101
|
+
export function signAnswer(signKey, pairSpace, did) {
|
|
102
|
+
return signWithScalar(signKey, answerMessage(pairSpace, did));
|
|
103
|
+
}
|
|
104
|
+
export function checkAnswer(sign, pairSpace, did, signature) {
|
|
105
|
+
return verifyWithPoint(sign, answerMessage(pairSpace, did), signature);
|
|
106
|
+
}
|
|
107
|
+
/** A knock's id: the hash of its sealed blob, as relays file it */
|
|
108
|
+
export async function knockId(blob) {
|
|
109
|
+
return base64UrlEncode(await sha256(utf8Encode(blob)));
|
|
110
|
+
}
|
|
111
|
+
const knockContext = (door) => `weave/knock/v1|${door}`;
|
|
112
|
+
/**
|
|
113
|
+
* Makes a knock: the body, signed by the session key, sealed to the door key.
|
|
114
|
+
* @returns The sealed blob, for relays' mailboxes
|
|
115
|
+
*/
|
|
116
|
+
export async function sealKnock(door, knock, session, provider) {
|
|
117
|
+
const note = knock.note ? clip(knock.note.trim(), MAX_NOTE) : undefined;
|
|
118
|
+
const body = {
|
|
119
|
+
v: 1,
|
|
120
|
+
door,
|
|
121
|
+
from: knock.from,
|
|
122
|
+
name: clip(knock.name.trim(), MAX_NAME) || 'Someone',
|
|
123
|
+
invite: knock.invite,
|
|
124
|
+
...(note ? { note } : {}),
|
|
125
|
+
at: Math.floor(Date.now() / 1000),
|
|
126
|
+
session: session.did,
|
|
127
|
+
proof: session.proof,
|
|
128
|
+
};
|
|
129
|
+
const sig = base64UrlEncode(await provider.sign(session.key, utf8Encode(canonicalize(body))));
|
|
130
|
+
return sealFor(door, { body, sig }, knockContext(door));
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Opens a knock left on a door, and checks it through: sealed to this door;
|
|
134
|
+
* signed by a session key that its account's note vouches for, for the whole
|
|
135
|
+
* account and not by an agent; signed when the relay took it; recent; and
|
|
136
|
+
* carrying an invite to a private space that account made.
|
|
137
|
+
* @param doorKey The door key's private scalar (`deriveDoorKeyBytes`)
|
|
138
|
+
* @param receivedAt When the relay took it, ms, as `fetch` says
|
|
139
|
+
* @returns The knock, or null when it is anything less
|
|
140
|
+
*/
|
|
141
|
+
export async function openKnock(doorKey, blob, receivedAt, provider) {
|
|
142
|
+
const door = contactPublicKey(doorKey);
|
|
143
|
+
const opened = (await openSealed((await contactKeyPair(doorKey)).privateKey, blob, knockContext(door)));
|
|
144
|
+
const body = opened?.body;
|
|
145
|
+
if (!body || typeof opened.sig !== 'string')
|
|
146
|
+
return null;
|
|
147
|
+
if (body.v !== 1 || body.door !== door)
|
|
148
|
+
return null;
|
|
149
|
+
if (typeof body.from !== 'string' || typeof body.session !== 'string' || typeof body.name !== 'string')
|
|
150
|
+
return null;
|
|
151
|
+
if (Array.from(body.name).length > MAX_NAME)
|
|
152
|
+
return null;
|
|
153
|
+
if (typeof body.invite !== 'string' || body.invite.length > MAX_INVITE)
|
|
154
|
+
return null;
|
|
155
|
+
if (typeof body.proof !== 'string' || body.proof.length > MAX_PROOF)
|
|
156
|
+
return null;
|
|
157
|
+
if (body.note !== undefined && (typeof body.note !== 'string' || Array.from(body.note).length > MAX_NOTE))
|
|
158
|
+
return null;
|
|
159
|
+
if (!Number.isSafeInteger(body.at) || !Number.isFinite(receivedAt))
|
|
160
|
+
return null;
|
|
161
|
+
const now = Math.floor(Date.now() / 1000);
|
|
162
|
+
if (body.at > now + UCAN_CLOCK_SKEW_SECONDS || body.at < now - KNOCK_TTL_SECONDS)
|
|
163
|
+
return null;
|
|
164
|
+
// Signed when it was dropped, not dated back to when a note was still good.
|
|
165
|
+
const dropped = Math.floor(receivedAt / 1000);
|
|
166
|
+
if (body.at > dropped + UCAN_CLOCK_SKEW_SECONDS || body.at < dropped - KNOCK_DROP_WINDOW_SECONDS)
|
|
167
|
+
return null;
|
|
168
|
+
// Signed by the session key it names…
|
|
169
|
+
let signed = false;
|
|
170
|
+
try {
|
|
171
|
+
const key = await provider.importPublicKey(didToPublicKey(body.session).publicKeyBytes);
|
|
172
|
+
signed = await provider.verify(key, base64UrlDecode(opened.sig), utf8Encode(canonicalize(body)));
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
if (!signed)
|
|
178
|
+
return null;
|
|
179
|
+
// …which the account it claims had delegated to when it signed. Agents never knock.
|
|
180
|
+
if (isAgentNote(body.proof))
|
|
181
|
+
return null;
|
|
182
|
+
const chain = await resolveDelegationRoot(body.proof, () => null, provider, { at: body.at }).catch(() => null);
|
|
183
|
+
if (!chain?.valid || chain.audience !== body.session || chain.rootDid !== body.from)
|
|
184
|
+
return null;
|
|
185
|
+
// Knocking makes a space and hands out its invite: only a note for the whole
|
|
186
|
+
// account, to write, may. An app given one space, or only to read, may not.
|
|
187
|
+
if (!chain.capabilities.some((capability) => capability.with === '*' && (capability.can === 'expression/*' || capability.can === '*')))
|
|
188
|
+
return null;
|
|
189
|
+
// A private space the knocker made, with its key: anything else isn't a space for two from them.
|
|
190
|
+
let invited;
|
|
191
|
+
try {
|
|
192
|
+
invited = parseSpaceInvite(body.invite);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
if (invited.space.creator !== body.from || invited.space.visibility !== 'private' || !invited.key)
|
|
198
|
+
return null;
|
|
199
|
+
if ((await checkSpace(invited.space)) !== null)
|
|
200
|
+
return null;
|
|
201
|
+
return Object.freeze({
|
|
202
|
+
from: body.from,
|
|
203
|
+
name: clip(body.name, MAX_NAME) || 'Someone',
|
|
204
|
+
...(body.note ? { note: body.note } : {}),
|
|
205
|
+
invite: body.invite,
|
|
206
|
+
pairSpace: invited.space.id,
|
|
207
|
+
at: body.at * 1000,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
//# sourceMappingURL=doors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doors.js","sourceRoot":"","sources":["../../src/doors/doors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module doors
|
|
3
|
+
* Doors and knocks — see `doors.ts`, and `node.doors` for the API an app uses.
|
|
4
|
+
*/
|
|
5
|
+
export { encodeDoorCode, parseDoorCode, checkDoorCode, doorTopic, knockId, sealKnock, openKnock, signPurge, purgeMessage, signAnswer, checkAnswer, clip, KNOCK_DROP_WINDOW_SECONDS, MAX_DOOR_RELAYS, KNOCK_TTL_SECONDS, } from './doors.js';
|
|
6
|
+
export type { DoorCode, KnockBody, OpenedKnock } from './doors.js';
|
|
7
|
+
export { createMailboxClient } from '../network/mailbox.js';
|
|
8
|
+
export type { MailboxClient, MailboxOptions, MailItem } from '../network/mailbox.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/doors/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,cAAc,EACd,aAAa,EACb,aAAa,EACb,SAAS,EACT,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,EACT,YAAY,EACZ,UAAU,EACV,WAAW,EACX,IAAI,EACJ,yBAAyB,EACzB,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module doors
|
|
3
|
+
* Doors and knocks — see `doors.ts`, and `node.doors` for the API an app uses.
|
|
4
|
+
*/
|
|
5
|
+
export { encodeDoorCode, parseDoorCode, checkDoorCode, doorTopic, knockId, sealKnock, openKnock, signPurge, purgeMessage, signAnswer, checkAnswer, clip, KNOCK_DROP_WINDOW_SECONDS, MAX_DOOR_RELAYS, KNOCK_TTL_SECONDS, } from './doors.js';
|
|
6
|
+
export { createMailboxClient } from '../network/mailbox.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/doors/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACL,cAAc,EACd,aAAa,EACb,aAAa,EACb,SAAS,EACT,OAAO,EACP,SAAS,EACT,SAAS,EACT,SAAS,EACT,YAAY,EACZ,UAAU,EACV,WAAW,EACX,IAAI,EACJ,yBAAyB,EACzB,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export interface ContactKeyPair {
|
|
2
|
+
/** The public half: a compressed P-256 point, base64url. What goes on a profile. */
|
|
3
|
+
readonly publicKey: string;
|
|
4
|
+
/** The private half, for opening what was sealed to the public one. Not extractable. */
|
|
5
|
+
readonly privateKey: CryptoKey;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The contact key's private scalar, from the account seed — 32 bytes. This is
|
|
9
|
+
* what an account home hands an app it lets handle contacts.
|
|
10
|
+
*/
|
|
11
|
+
export declare function deriveContactKeyBytes(seed: Uint8Array): Promise<Uint8Array>;
|
|
12
|
+
/**
|
|
13
|
+
* An account's **member key** for one space: the same kind of key pair, derived
|
|
14
|
+
* from the account's vault key and the space id. When a private space's key
|
|
15
|
+
* changes, the new key is sealed to each member's member key (`sys.box`).
|
|
16
|
+
*
|
|
17
|
+
* One per space, not one per account, so an account home can hand an app the
|
|
18
|
+
* member keys for exactly the spaces it grants — and a new space key reaches
|
|
19
|
+
* that app without it holding anything that opens other spaces' keys.
|
|
20
|
+
* @param accountKey The vault key bytes (`deriveVaultKeyBytes(seed)`)
|
|
21
|
+
*/
|
|
22
|
+
export declare function deriveMemberKeyBytes(accountKey: Uint8Array, spaceId: string): Promise<Uint8Array>;
|
|
23
|
+
/**
|
|
24
|
+
* A **door key**: the key a door's knocks are sealed to (`doors/doors.ts`).
|
|
25
|
+
* Derived from the contact key and the door's id, so every device and app
|
|
26
|
+
* holding the contact key opens the same doors, and a new door is a new id.
|
|
27
|
+
*
|
|
28
|
+
* Not the contact key itself: that one's public half is on your profile in
|
|
29
|
+
* every space you write in, and a door is handed to people who may not know
|
|
30
|
+
* who you are yet. A door key says nothing about the account behind it.
|
|
31
|
+
* @param contactKey The contact key's private scalar (`deriveContactKeyBytes`)
|
|
32
|
+
* @param doorId The door's id, as its `std.door` record names it
|
|
33
|
+
*/
|
|
34
|
+
export declare function deriveDoorKeyBytes(contactKey: Uint8Array, doorId: string): Promise<Uint8Array>;
|
|
35
|
+
/**
|
|
36
|
+
* A door's **signing key**: what proves you own a door, without saying whose
|
|
37
|
+
* it is — to a relay, when clearing the door's mailbox, and to someone who
|
|
38
|
+
* knocked, when you answer. Separate from the door key, which only opens
|
|
39
|
+
* knocks: one key should not both sign and decrypt.
|
|
40
|
+
*/
|
|
41
|
+
export declare function deriveDoorSignKeyBytes(contactKey: Uint8Array, doorId: string): Promise<Uint8Array>;
|
|
42
|
+
/**
|
|
43
|
+
* Signs with a P-256 private scalar: ECDSA over SHA-256, 64 bytes r ‖ s,
|
|
44
|
+
* base64url — for door signing keys.
|
|
45
|
+
*/
|
|
46
|
+
export declare function signWithScalar(secret: Uint8Array, data: Uint8Array): Promise<string>;
|
|
47
|
+
/** Checks what `signWithScalar` signed, against a compressed public key (base64url) */
|
|
48
|
+
export declare function verifyWithPoint(publicKey: string, data: Uint8Array, signature: string): Promise<boolean>;
|
|
49
|
+
/** The public half, from the private scalar */
|
|
50
|
+
export declare function contactPublicKey(secret: Uint8Array): string;
|
|
51
|
+
/** Whether a string is a contact key's public half: a point on P-256 */
|
|
52
|
+
export declare function isContactPublicKey(value: unknown): value is string;
|
|
53
|
+
/** The key pair, from the private scalar (`deriveContactKeyBytes`) */
|
|
54
|
+
export declare function contactKeyPair(secret: Uint8Array): Promise<ContactKeyPair>;
|
|
55
|
+
/**
|
|
56
|
+
* Seals a value so only the holder of a contact key can open it.
|
|
57
|
+
* @param recipient The contact key's public half, as a profile carries it
|
|
58
|
+
* @param value Anything JSON can carry
|
|
59
|
+
* @param context What the sealed value belongs to; opening needs the same
|
|
60
|
+
* @returns base64url: the ephemeral public point, the IV, and the ciphertext
|
|
61
|
+
*/
|
|
62
|
+
export declare function sealFor(recipient: string, value: unknown, context: string): Promise<string>;
|
|
63
|
+
/**
|
|
64
|
+
* Opens what `sealFor` sealed.
|
|
65
|
+
* @returns The value, or null when it was not sealed for this key, or for this context, or was changed
|
|
66
|
+
*/
|
|
67
|
+
export declare function openSealed(privateKey: CryptoKey, sealed: string, context: string): Promise<unknown>;
|
|
68
|
+
//# sourceMappingURL=contact-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contact-key.d.ts","sourceRoot":"","sources":["../../src/identity/contact-key.ts"],"names":[],"mappings":"AAoCA,MAAM,WAAW,cAAc;IAC7B,oFAAoF;IACpF,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;CAChC;AAYD;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAEjF;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CAAC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAEvG;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAEpG;AAED;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAAC,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAExG;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB1F;AAED,uFAAuF;AACvF,wBAAsB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAQ9G;AAED,+CAA+C;AAC/C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAE3D;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAQlE;AAED,sEAAsE;AACtE,wBAAsB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAiBhF;AASD;;;;;;GAMG;AACH,wBAAsB,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAqBjG;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CA2BzG"}
|