@sumicom/quicksave-shared 0.7.1 → 0.8.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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAG3B,cAAc,eAAe,CAAC;AAG9B,cAAc,YAAY,CAAC;AAG3B,cAAc,aAAa,CAAC;AAG5B,cAAc,eAAe,CAAC;AAG9B,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,YAAY,CAAC;AAG3B,cAAc,eAAe,CAAC;AAG9B,cAAc,YAAY,CAAC;AAG3B,cAAc,aAAa,CAAC;AAG5B,cAAc,eAAe,CAAC;AAG9B,cAAc,kBAAkB,CAAC;AAGjC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -10,4 +10,8 @@ export * from './crypto.js';
10
10
  export * from './protocol.js';
11
11
  // Permission utilities
12
12
  export * from './permissions.js';
13
+ // Signed sync envelope
14
+ export * from './syncEnvelope.js';
15
+ // Signed V2 key-exchange helpers
16
+ export * from './keyExchange.js';
13
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,kBAAkB;AAClB,cAAc,eAAe,CAAC;AAE9B,kCAAkC;AAClC,cAAc,YAAY,CAAC;AAE3B,mBAAmB;AACnB,cAAc,aAAa,CAAC;AAE5B,qBAAqB;AACrB,cAAc,eAAe,CAAC;AAE9B,uBAAuB;AACvB,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,QAAQ;AACR,cAAc,YAAY,CAAC;AAE3B,kBAAkB;AAClB,cAAc,eAAe,CAAC;AAE9B,kCAAkC;AAClC,cAAc,YAAY,CAAC;AAE3B,mBAAmB;AACnB,cAAc,aAAa,CAAC;AAE5B,qBAAqB;AACrB,cAAc,eAAe,CAAC;AAE9B,uBAAuB;AACvB,cAAc,kBAAkB,CAAC;AAEjC,uBAAuB;AACvB,cAAc,mBAAmB,CAAC;AAElC,iCAAiC;AACjC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Canonical body signed by the PWA in a V2 key exchange. The agent
3
+ * re-derives this string locally and verifies the Ed25519 signature against
4
+ * the claimed `sigPubkey` (TOFU on first pair, pinned match on subsequent).
5
+ *
6
+ * Binding fields:
7
+ * - `agentId`: prevents an envelope captured by one agent from being replayed
8
+ * against another agent (each agent TOFU-pins a single group identity).
9
+ * - `sigPubkey`: prevents key-substitution — the claimed signing pubkey is
10
+ * itself part of the signed body, so an attacker can't swap it after the
11
+ * fact without re-signing.
12
+ * - `encryptedDEK`: binds the signature to this specific handshake's DEK so a
13
+ * captured envelope can't be spliced with a different DEK.
14
+ * - `timestamp`: freshness (agent enforces a ±bounded window).
15
+ *
16
+ * Separator `|` is not valid in base64url, so the fields cannot collide.
17
+ */
18
+ export declare function canonicalKeyExchangeV2Body(params: {
19
+ agentId: string;
20
+ sigPubkey: string;
21
+ encryptedDEK: string;
22
+ timestamp: number;
23
+ }): string;
24
+ export interface SignKeyExchangeV2Input {
25
+ agentId: string;
26
+ encryptedDEK: string;
27
+ timestamp: number;
28
+ signingPublicKey: Uint8Array;
29
+ signingSecretKey: Uint8Array;
30
+ /** base64 encoder; injected to avoid a crypto-lib-specific dependency here. */
31
+ encodeBase64: (bytes: Uint8Array) => string;
32
+ }
33
+ export interface SignedKeyExchangeV2 {
34
+ sigPubkey: string;
35
+ signature: string;
36
+ }
37
+ /**
38
+ * Produce the `sigPubkey + signature` pair the PWA attaches to the V2 key
39
+ * exchange envelope.
40
+ */
41
+ export declare function signKeyExchangeV2(input: SignKeyExchangeV2Input): SignedKeyExchangeV2;
42
+ export interface VerifyKeyExchangeV2Input {
43
+ agentId: string;
44
+ encryptedDEK: string;
45
+ timestamp: number;
46
+ sigPubkey: string;
47
+ signature: string;
48
+ /** base64 decoder (usually `decodeBase64` from crypto.ts). */
49
+ decodeBase64: (b64: string) => Uint8Array;
50
+ }
51
+ /**
52
+ * Verify the Ed25519 signature on a V2 key exchange. Does *not* check the
53
+ * timestamp window or whether `sigPubkey` matches a pinned identity — the
54
+ * caller is responsible for those policy decisions (unpaired vs paired
55
+ * branches diverge on how to interpret `sigPubkey`).
56
+ */
57
+ export declare function verifyKeyExchangeV2Signature(input: VerifyKeyExchangeV2Input): boolean;
58
+ //# sourceMappingURL=keyExchange.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyExchange.d.ts","sourceRoot":"","sources":["../src/keyExchange.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAQT;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,UAAU,CAAC;IAC7B,gBAAgB,EAAE,UAAU,CAAC;IAC7B,+EAA+E;IAC/E,YAAY,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,MAAM,CAAC;CAC7C;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,sBAAsB,GAC5B,mBAAmB,CAUrB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,YAAY,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,UAAU,CAAC;CAC3C;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,wBAAwB,GAC9B,OAAO,CAaT"}
@@ -0,0 +1,64 @@
1
+ import { sign, verify } from './crypto.js';
2
+ /**
3
+ * Canonical body signed by the PWA in a V2 key exchange. The agent
4
+ * re-derives this string locally and verifies the Ed25519 signature against
5
+ * the claimed `sigPubkey` (TOFU on first pair, pinned match on subsequent).
6
+ *
7
+ * Binding fields:
8
+ * - `agentId`: prevents an envelope captured by one agent from being replayed
9
+ * against another agent (each agent TOFU-pins a single group identity).
10
+ * - `sigPubkey`: prevents key-substitution — the claimed signing pubkey is
11
+ * itself part of the signed body, so an attacker can't swap it after the
12
+ * fact without re-signing.
13
+ * - `encryptedDEK`: binds the signature to this specific handshake's DEK so a
14
+ * captured envelope can't be spliced with a different DEK.
15
+ * - `timestamp`: freshness (agent enforces a ±bounded window).
16
+ *
17
+ * Separator `|` is not valid in base64url, so the fields cannot collide.
18
+ */
19
+ export function canonicalKeyExchangeV2Body(params) {
20
+ return [
21
+ 'key-exchange-v2',
22
+ params.agentId,
23
+ params.sigPubkey,
24
+ params.encryptedDEK,
25
+ String(params.timestamp),
26
+ ].join('|');
27
+ }
28
+ /**
29
+ * Produce the `sigPubkey + signature` pair the PWA attaches to the V2 key
30
+ * exchange envelope.
31
+ */
32
+ export function signKeyExchangeV2(input) {
33
+ const sigPubkey = input.encodeBase64(input.signingPublicKey);
34
+ const body = canonicalKeyExchangeV2Body({
35
+ agentId: input.agentId,
36
+ sigPubkey,
37
+ encryptedDEK: input.encryptedDEK,
38
+ timestamp: input.timestamp,
39
+ });
40
+ const signature = sign(body, input.signingSecretKey);
41
+ return { sigPubkey, signature };
42
+ }
43
+ /**
44
+ * Verify the Ed25519 signature on a V2 key exchange. Does *not* check the
45
+ * timestamp window or whether `sigPubkey` matches a pinned identity — the
46
+ * caller is responsible for those policy decisions (unpaired vs paired
47
+ * branches diverge on how to interpret `sigPubkey`).
48
+ */
49
+ export function verifyKeyExchangeV2Signature(input) {
50
+ try {
51
+ const body = canonicalKeyExchangeV2Body({
52
+ agentId: input.agentId,
53
+ sigPubkey: input.sigPubkey,
54
+ encryptedDEK: input.encryptedDEK,
55
+ timestamp: input.timestamp,
56
+ });
57
+ const pubKey = input.decodeBase64(input.sigPubkey);
58
+ return verify(body, input.signature, pubKey);
59
+ }
60
+ catch {
61
+ return false;
62
+ }
63
+ }
64
+ //# sourceMappingURL=keyExchange.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyExchange.js","sourceRoot":"","sources":["../src/keyExchange.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE3C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,0BAA0B,CAAC,MAK1C;IACC,OAAO;QACL,iBAAiB;QACjB,MAAM,CAAC,OAAO;QACd,MAAM,CAAC,SAAS;QAChB,MAAM,CAAC,YAAY;QACnB,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC;KACzB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAiBD;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAA6B;IAE7B,MAAM,SAAS,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC7D,MAAM,IAAI,GAAG,0BAA0B,CAAC;QACtC,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,SAAS;QACT,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACrD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAClC,CAAC;AAYD;;;;;GAKG;AACH,MAAM,UAAU,4BAA4B,CAC1C,KAA+B;IAE/B,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,0BAA0B,CAAC;YACtC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,YAAY,EAAE,KAAK,CAAC,YAAY;YAChC,SAAS,EAAE,KAAK,CAAC,SAAS;SAC3B,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACnD,OAAO,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEvD;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAO1E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAChC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,IAAI,GACZ;IACD,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,YAAY,EAAE,WAAW,CAAC;CAC3B,CAIA;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAclD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,WAAW,GAAG,WAAW,CAErE;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAyBvD,CAAC"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEvD;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAO1E;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAChC,IAAI,EAAE,WAAW,EACjB,OAAO,EAAE,IAAI,GACZ;IACD,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,YAAY,EAAE,WAAW,CAAC;CAC3B,CAIA;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAclD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAEzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAE3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,YAAY,EAAE,WAAW,GAAG,WAAW,CAErE;AAED;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CA0BvD,CAAC"}
package/dist/protocol.js CHANGED
@@ -83,5 +83,6 @@ export const REQUEST_RESPONSE_MAP = {
83
83
  // Session registry (history)
84
84
  'session:update-history': 'session:update-history:response',
85
85
  'session:delete-history': 'session:delete-history:response',
86
+ 'session:list-archived': 'session:list-archived:response',
86
87
  };
87
88
  //# sourceMappingURL=protocol.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAI,IAAiB,EAAE,OAAU;IAC5D,OAAO;QACL,EAAE,EAAE,iBAAiB,EAAE;QACvB,IAAI;QACJ,OAAO;QACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAiB,EACjB,OAAa;IAKb,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,GAAG,IAAI,WAA0B,CAAC;IACvD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEhC,IACE,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ;QAC7B,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EACpC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,MAAiB,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,YAAyB;IACtD,OAAO,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAgB,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC1D,YAAY,EAAE,qBAAqB;IACnC,UAAU,EAAE,mBAAmB;IAC/B,WAAW,EAAE,oBAAoB;IACjC,aAAa,EAAE,sBAAsB;IACrC,YAAY,EAAE,qBAAqB;IACnC,SAAS,EAAE,kBAAkB;IAC7B,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,uBAAuB;IACvC,aAAa,EAAE,sBAAsB;IACrC,aAAa,EAAE,sBAAsB;IACrC,mBAAmB,EAAE,4BAA4B;IACjD,oBAAoB,EAAE,6BAA6B;IACnD,qBAAqB,EAAE,8BAA8B;IACrD,SAAS,EAAE,eAAe;IAC1B,IAAI,EAAE,MAAM;IACZ,kBAAkB;IAClB,cAAc,EAAE,uBAAuB;IACvC,eAAe,EAAE,wBAAwB;IACzC,eAAe,EAAE,wBAAwB;IACzC,qBAAqB,EAAE,8BAA8B;IACrD,wBAAwB,EAAE,iCAAiC;IAC3D,6BAA6B;IAC7B,wBAAwB,EAAE,iCAAiC;IAC3D,wBAAwB,EAAE,iCAAiC;CAC5D,CAAC"}
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AACpE,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAI,IAAiB,EAAE,OAAU;IAC5D,OAAO;QACL,EAAE,EAAE,iBAAiB,EAAE;QACvB,IAAI;QACJ,OAAO;QACP,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;KACtB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAiB,EACjB,OAAa;IAKb,MAAM,OAAO,GAAG,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,MAAM,YAAY,GAAG,GAAG,IAAI,WAA0B,CAAC;IACvD,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AACnC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEhC,IACE,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,OAAO,MAAM,CAAC,EAAE,KAAK,QAAQ;QAC7B,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,OAAO,MAAM,CAAC,SAAS,KAAK,QAAQ,EACpC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5C,CAAC;IAED,OAAO,MAAiB,CAAC;AAC3B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAgB;IAChD,OAAO,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,YAAyB;IACtD,OAAO,YAAY,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAgB,CAAC;AAC9D,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAA2B;IAC1D,YAAY,EAAE,qBAAqB;IACnC,UAAU,EAAE,mBAAmB;IAC/B,WAAW,EAAE,oBAAoB;IACjC,aAAa,EAAE,sBAAsB;IACrC,YAAY,EAAE,qBAAqB;IACnC,SAAS,EAAE,kBAAkB;IAC7B,cAAc,EAAE,uBAAuB;IACvC,cAAc,EAAE,uBAAuB;IACvC,aAAa,EAAE,sBAAsB;IACrC,aAAa,EAAE,sBAAsB;IACrC,mBAAmB,EAAE,4BAA4B;IACjD,oBAAoB,EAAE,6BAA6B;IACnD,qBAAqB,EAAE,8BAA8B;IACrD,SAAS,EAAE,eAAe;IAC1B,IAAI,EAAE,MAAM;IACZ,kBAAkB;IAClB,cAAc,EAAE,uBAAuB;IACvC,eAAe,EAAE,wBAAwB;IACzC,eAAe,EAAE,wBAAwB;IACzC,qBAAqB,EAAE,8BAA8B;IACrD,wBAAwB,EAAE,iCAAiC;IAC3D,6BAA6B;IAC7B,wBAAwB,EAAE,iCAAiC;IAC3D,wBAAwB,EAAE,iCAAiC;IAC3D,uBAAuB,EAAE,gCAAgC;CAC1D,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Signed envelope for writes to `/sync/{keyHash}` routes. The envelope binds
3
+ * the ciphertext + action to a specific mailbox (`keyHash`) via Ed25519, and
4
+ * carries a nonce + timestamp so the relay can drop replays.
5
+ *
6
+ * Canonical body signed by the client (UTF-8, `|` separator):
7
+ * `${action}|${sigPubkey}|${ts}|${nonce}|${keyHash}|${ciphertextHash}`
8
+ *
9
+ * `ciphertextHash` is URL-safe-base64 of SHA-512 over the ciphertext bytes.
10
+ * For actions that carry no ciphertext (e.g. lock-release) it is the empty
11
+ * string.
12
+ */
13
+ export type SyncEnvelopeAction = 'sync-write' | 'sync-tombstone' | 'sync-lock-release';
14
+ export interface SignedSyncEnvelope {
15
+ v: 1;
16
+ action: SyncEnvelopeAction;
17
+ /** Absent for actions that don't carry a payload (lock-release). */
18
+ ciphertext?: string;
19
+ /** URL-safe base64 Ed25519 public key. */
20
+ sigPubkey: string;
21
+ ts: number;
22
+ nonce: string;
23
+ sig: string;
24
+ }
25
+ export declare function hashCiphertext(ciphertext: string): string;
26
+ export declare function canonicalEnvelopeBody(params: {
27
+ action: SyncEnvelopeAction;
28
+ sigPubkey: string;
29
+ ts: number;
30
+ nonce: string;
31
+ keyHash: string;
32
+ ciphertextHash: string;
33
+ }): string;
34
+ export interface CreateEnvelopeInput {
35
+ action: SyncEnvelopeAction;
36
+ keyHash: string;
37
+ ciphertext?: string;
38
+ signKeyPair: {
39
+ publicKey: Uint8Array;
40
+ secretKey: Uint8Array;
41
+ };
42
+ now?: () => number;
43
+ }
44
+ export declare function createSignedSyncEnvelope(input: CreateEnvelopeInput): SignedSyncEnvelope;
45
+ /**
46
+ * Type-guard for parsed JSON bodies on the relay side.
47
+ * Only checks shape; signature verification happens separately.
48
+ */
49
+ export declare function isSignedSyncEnvelope(x: unknown): x is SignedSyncEnvelope;
50
+ //# sourceMappingURL=syncEnvelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncEnvelope.d.ts","sourceRoot":"","sources":["../src/syncEnvelope.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,kBAAkB,GAC1B,YAAY,GACZ,gBAAgB,GAChB,mBAAmB,CAAC;AAExB,MAAM,WAAW,kBAAkB;IACjC,CAAC,EAAE,CAAC,CAAC;IACL,MAAM,EAAE,kBAAkB,CAAC;IAC3B,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;CACb;AAmBD,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE;IAC5C,MAAM,EAAE,kBAAkB,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,MAAM,CAST;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QAAE,SAAS,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE,UAAU,CAAA;KAAE,CAAC;IAC9D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,mBAAmB,GACzB,kBAAkB,CA0BpB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,kBAAkB,CAYxE"}
@@ -0,0 +1,71 @@
1
+ import nacl from 'tweetnacl';
2
+ function toUrlSafe(b64) {
3
+ return b64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/g, '');
4
+ }
5
+ function bytesToUrlSafe(bytes) {
6
+ let bin = '';
7
+ for (let i = 0; i < bytes.length; i++)
8
+ bin += String.fromCharCode(bytes[i]);
9
+ // btoa is available in browser + Node 16+ globals
10
+ return toUrlSafe(btoa(bin));
11
+ }
12
+ function randomNonce(size = 16) {
13
+ const buf = new Uint8Array(size);
14
+ (globalThis.crypto ?? require('crypto').webcrypto).getRandomValues(buf);
15
+ return bytesToUrlSafe(buf);
16
+ }
17
+ export function hashCiphertext(ciphertext) {
18
+ const bytes = new TextEncoder().encode(ciphertext);
19
+ return bytesToUrlSafe(nacl.hash(bytes));
20
+ }
21
+ export function canonicalEnvelopeBody(params) {
22
+ return [
23
+ params.action,
24
+ params.sigPubkey,
25
+ String(params.ts),
26
+ params.nonce,
27
+ params.keyHash,
28
+ params.ciphertextHash,
29
+ ].join('|');
30
+ }
31
+ export function createSignedSyncEnvelope(input) {
32
+ const ts = (input.now ?? Date.now)();
33
+ const nonce = randomNonce();
34
+ const sigPubkey = bytesToUrlSafe(input.signKeyPair.publicKey);
35
+ const ciphertextHash = input.ciphertext ? hashCiphertext(input.ciphertext) : '';
36
+ const canonical = canonicalEnvelopeBody({
37
+ action: input.action,
38
+ sigPubkey,
39
+ ts,
40
+ nonce,
41
+ keyHash: input.keyHash,
42
+ ciphertextHash,
43
+ });
44
+ const sigBytes = nacl.sign.detached(new TextEncoder().encode(canonical), input.signKeyPair.secretKey);
45
+ return {
46
+ v: 1,
47
+ action: input.action,
48
+ ciphertext: input.ciphertext,
49
+ sigPubkey,
50
+ ts,
51
+ nonce,
52
+ sig: bytesToUrlSafe(sigBytes),
53
+ };
54
+ }
55
+ /**
56
+ * Type-guard for parsed JSON bodies on the relay side.
57
+ * Only checks shape; signature verification happens separately.
58
+ */
59
+ export function isSignedSyncEnvelope(x) {
60
+ if (!x || typeof x !== 'object')
61
+ return false;
62
+ const e = x;
63
+ return (e.v === 1 &&
64
+ typeof e.action === 'string' &&
65
+ (e.ciphertext === undefined || typeof e.ciphertext === 'string') &&
66
+ typeof e.sigPubkey === 'string' &&
67
+ typeof e.ts === 'number' &&
68
+ typeof e.nonce === 'string' &&
69
+ typeof e.sig === 'string');
70
+ }
71
+ //# sourceMappingURL=syncEnvelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncEnvelope.js","sourceRoot":"","sources":["../src/syncEnvelope.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AA+B7B,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,cAAc,CAAC,KAAiB;IACvC,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5E,kDAAkD;IAClD,OAAO,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAC9B,CAAC;AAED,SAAS,WAAW,CAAC,IAAI,GAAG,EAAE;IAC5B,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC,UAAU,CAAC,MAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC;IACxE,OAAO,cAAc,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,UAAkB;IAC/C,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACnD,OAAO,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;AAC1C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAOrC;IACC,OAAO;QACL,MAAM,CAAC,MAAM;QACb,MAAM,CAAC,SAAS;QAChB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK;QACZ,MAAM,CAAC,OAAO;QACd,MAAM,CAAC,cAAc;KACtB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACd,CAAC;AAUD,MAAM,UAAU,wBAAwB,CACtC,KAA0B;IAE1B,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACrC,MAAM,KAAK,GAAG,WAAW,EAAE,CAAC;IAC5B,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAChF,MAAM,SAAS,GAAG,qBAAqB,CAAC;QACtC,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,SAAS;QACT,EAAE;QACF,KAAK;QACL,OAAO,EAAE,KAAK,CAAC,OAAO;QACtB,cAAc;KACf,CAAC,CAAC;IACH,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,CACjC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,EACnC,KAAK,CAAC,WAAW,CAAC,SAAS,CAC5B,CAAC;IACF,OAAO;QACL,CAAC,EAAE,CAAC;QACJ,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,UAAU,EAAE,KAAK,CAAC,UAAU;QAC5B,SAAS;QACT,EAAE;QACF,KAAK;QACL,GAAG,EAAE,cAAc,CAAC,QAAQ,CAAC;KAC9B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,oBAAoB,CAAC,CAAU;IAC7C,IAAI,CAAC,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9C,MAAM,CAAC,GAAG,CAA4B,CAAC;IACvC,OAAO,CACL,CAAC,CAAC,CAAC,KAAK,CAAC;QACT,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ;QAC5B,CAAC,CAAC,CAAC,UAAU,KAAK,SAAS,IAAI,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC;QAChE,OAAO,CAAC,CAAC,SAAS,KAAK,QAAQ;QAC/B,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ;QACxB,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ;QAC3B,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,CAC1B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=syncEnvelope.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"syncEnvelope.test.d.ts","sourceRoot":"","sources":["../src/syncEnvelope.test.ts"],"names":[],"mappings":""}