dacument 1.0.1 → 1.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.
@@ -23,4 +23,7 @@ export declare function verifyToken(publicJwk: JsonWebKey, token: string, expect
23
23
  header: SignedHeader;
24
24
  payload: unknown;
25
25
  } | false>;
26
+ export declare function validateActorKeyPair(privateJwk: JsonWebKey, publicJwk: JsonWebKey): Promise<void>;
27
+ export declare function signDetached(privateJwk: JsonWebKey, payload: string): Promise<string>;
28
+ export declare function verifyDetached(publicJwk: JsonWebKey, payload: string, signatureB64: string): Promise<boolean>;
26
29
  export {};
@@ -1,5 +1,6 @@
1
1
  import { Bytes } from "bytecodec";
2
2
  import { SigningAgent, VerificationAgent } from "zeyra";
3
+ const ACTOR_CHALLENGE = Bytes.fromString("dacument-actor-verify");
3
4
  function stableStringify(value) {
4
5
  if (value === null || typeof value !== "object")
5
6
  return JSON.stringify(value);
@@ -16,6 +17,11 @@ function decodePart(part) {
16
17
  const json = Bytes.toString(bytes);
17
18
  return JSON.parse(json);
18
19
  }
20
+ function toArrayBuffer(bytes) {
21
+ const buffer = new ArrayBuffer(bytes.byteLength);
22
+ new Uint8Array(buffer).set(bytes);
23
+ return buffer;
24
+ }
19
25
  export async function signToken(privateJwk, header, payload) {
20
26
  const headerJson = stableStringify(header);
21
27
  const payloadJson = stableStringify(payload);
@@ -59,6 +65,24 @@ export async function verifyToken(publicJwk, token, expectedTyp) {
59
65
  const verifier = new VerificationAgent(publicJwk);
60
66
  const signingInput = Bytes.fromString(`${headerB64}.${payloadB64}`);
61
67
  const signatureBytes = new Uint8Array(signature);
62
- const ok = await verifier.verify(signingInput, signatureBytes.buffer);
68
+ const ok = await verifier.verify(signingInput, toArrayBuffer(signatureBytes));
63
69
  return ok ? { header, payload } : false;
64
70
  }
71
+ export async function validateActorKeyPair(privateJwk, publicJwk) {
72
+ const signer = new SigningAgent(privateJwk);
73
+ const signatureBytes = new Uint8Array(await signer.sign(ACTOR_CHALLENGE));
74
+ const verifier = new VerificationAgent(publicJwk);
75
+ const ok = await verifier.verify(ACTOR_CHALLENGE, toArrayBuffer(signatureBytes));
76
+ if (!ok)
77
+ throw new Error("Dacument.setActorInfo: publicKeyJwk does not match privateKeyJwk");
78
+ }
79
+ export async function signDetached(privateJwk, payload) {
80
+ const signer = new SigningAgent(privateJwk);
81
+ const signature = await signer.sign(Bytes.fromString(payload));
82
+ return Bytes.toBase64UrlString(signature);
83
+ }
84
+ export async function verifyDetached(publicJwk, payload, signatureB64) {
85
+ const verifier = new VerificationAgent(publicJwk);
86
+ const signatureBytes = Bytes.fromBase64UrlString(signatureB64);
87
+ return verifier.verify(Bytes.fromString(payload), toArrayBuffer(signatureBytes));
88
+ }
@@ -27,6 +27,11 @@ export type RolePublicKeys = {
27
27
  manager: JsonWebKey;
28
28
  editor: JsonWebKey;
29
29
  };
30
+ export type ActorInfo = {
31
+ id: string;
32
+ privateKeyJwk: JsonWebKey;
33
+ publicKeyJwk: JsonWebKey;
34
+ };
30
35
  export type RegisterSchema<T extends JsTypeName = JsTypeName> = {
31
36
  crdt: "register";
32
37
  jsType: T;
@@ -64,7 +69,7 @@ export type RecordSchema<T extends JsTypeName = JsTypeName> = {
64
69
  export type FieldSchema = RegisterSchema | TextSchema | ArraySchema | SetSchema | MapSchema | RecordSchema;
65
70
  export type SchemaDefinition = Record<string, FieldSchema>;
66
71
  export type SchemaId = string;
67
- export type OpKind = "acl.set" | "register.set" | "text.patch" | "array.patch" | "map.patch" | "set.patch" | "record.patch" | "ack";
72
+ export type OpKind = "acl.set" | "register.set" | "text.patch" | "array.patch" | "map.patch" | "set.patch" | "record.patch" | "ack" | "reset";
68
73
  export type OpPayload = {
69
74
  iss: string;
70
75
  sub: string;
@@ -77,6 +82,17 @@ export type OpPayload = {
77
82
  };
78
83
  export type SignedOp = {
79
84
  token: string;
85
+ actorSig?: string;
86
+ };
87
+ export type ResetPatch = {
88
+ newDocId: string;
89
+ reason?: string;
90
+ };
91
+ export type ResetState = {
92
+ ts: HLCStamp;
93
+ by: string;
94
+ newDocId: string;
95
+ reason?: string;
80
96
  };
81
97
  export type DacumentChangeEvent = {
82
98
  type: "change";
@@ -100,11 +116,20 @@ export type DacumentRevokedEvent = {
100
116
  by: string;
101
117
  stamp: HLCStamp;
102
118
  };
119
+ export type DacumentResetEvent = {
120
+ type: "reset";
121
+ oldDocId: string;
122
+ newDocId: string;
123
+ ts: HLCStamp;
124
+ by: string;
125
+ reason?: string;
126
+ };
103
127
  export type DacumentEventMap = {
104
128
  change: DacumentChangeEvent;
105
129
  merge: DacumentMergeEvent;
106
130
  error: DacumentErrorEvent;
107
131
  revoked: DacumentRevokedEvent;
132
+ reset: DacumentResetEvent;
108
133
  };
109
134
  export type AclAssignment = {
110
135
  id: string;
@@ -112,6 +137,23 @@ export type AclAssignment = {
112
137
  role: Role;
113
138
  stamp: HLCStamp;
114
139
  by: string;
140
+ publicKeyJwk?: JsonWebKey;
141
+ };
142
+ export type VerifyActorIntegrityOptions = {
143
+ token?: string | SignedOp;
144
+ ops?: Array<string | SignedOp>;
145
+ snapshot?: DocSnapshot;
146
+ };
147
+ export type VerificationFailure = {
148
+ index: number;
149
+ reason: string;
150
+ };
151
+ export type VerificationResult = {
152
+ ok: boolean;
153
+ verified: number;
154
+ failed: number;
155
+ missing: number;
156
+ failures: VerificationFailure[];
115
157
  };
116
158
  export type DocSnapshot = {
117
159
  docId: string;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dacument",
3
- "version": "1.0.1",
4
- "description": "Schema-driven CRDT document with signed ops and role-based ACLs.",
3
+ "version": "1.2.0",
4
+ "description": "Schema-driven CRDT document with signed ops, role-based ACLs, and optional per-actor verification.",
5
5
  "keywords": [
6
6
  "crdt",
7
7
  "document",