@viewportai/daemon 0.5.3 → 0.6.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.
Files changed (96) hide show
  1. package/dist/cli/commands.d.ts +1 -0
  2. package/dist/cli/commands.d.ts.map +1 -1
  3. package/dist/cli/commands.js +1 -0
  4. package/dist/cli/commands.js.map +1 -1
  5. package/dist/cli/context-access-command.d.ts +0 -6
  6. package/dist/cli/context-access-command.d.ts.map +1 -1
  7. package/dist/cli/context-access-command.js +1 -71
  8. package/dist/cli/context-access-command.js.map +1 -1
  9. package/dist/cli/context-command.d.ts.map +1 -1
  10. package/dist/cli/context-command.js +526 -38
  11. package/dist/cli/context-command.js.map +1 -1
  12. package/dist/cli/context-vault-metadata-command.d.ts.map +1 -1
  13. package/dist/cli/context-vault-metadata-command.js +6 -1
  14. package/dist/cli/context-vault-metadata-command.js.map +1 -1
  15. package/dist/cli/lifecycle-commands.d.ts.map +1 -1
  16. package/dist/cli/lifecycle-commands.js +2 -8
  17. package/dist/cli/lifecycle-commands.js.map +1 -1
  18. package/dist/cli/unlock-command.d.ts +2 -0
  19. package/dist/cli/unlock-command.d.ts.map +1 -0
  20. package/dist/cli/unlock-command.js +35 -0
  21. package/dist/cli/unlock-command.js.map +1 -0
  22. package/dist/context/local-edge-store.d.ts +11 -0
  23. package/dist/context/local-edge-store.d.ts.map +1 -1
  24. package/dist/context/local-edge-store.js +25 -0
  25. package/dist/context/local-edge-store.js.map +1 -1
  26. package/dist/context/local-edge-sync.d.ts +2 -15
  27. package/dist/context/local-edge-sync.d.ts.map +1 -1
  28. package/dist/context/local-edge-sync.js +244 -85
  29. package/dist/context/local-edge-sync.js.map +1 -1
  30. package/dist/context/local-edge-types.d.ts +12 -0
  31. package/dist/context/local-edge-types.d.ts.map +1 -1
  32. package/dist/hooks/trusted-edge-plan-artifacts.d.ts +30 -27
  33. package/dist/hooks/trusted-edge-plan-artifacts.d.ts.map +1 -1
  34. package/dist/hooks/trusted-edge-plan-artifacts.js +71 -89
  35. package/dist/hooks/trusted-edge-plan-artifacts.js.map +1 -1
  36. package/dist/index.d.ts +1 -0
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +3 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/security/epoch-enrollment.d.ts +48 -0
  41. package/dist/security/epoch-enrollment.d.ts.map +1 -0
  42. package/dist/security/epoch-enrollment.js +290 -0
  43. package/dist/security/epoch-enrollment.js.map +1 -0
  44. package/dist/security/epoch-protocol.d.ts +181 -0
  45. package/dist/security/epoch-protocol.d.ts.map +1 -0
  46. package/dist/security/epoch-protocol.js +285 -0
  47. package/dist/security/epoch-protocol.js.map +1 -0
  48. package/dist/security/epoch-public-pins.d.ts +19 -0
  49. package/dist/security/epoch-public-pins.d.ts.map +1 -0
  50. package/dist/security/epoch-public-pins.js +129 -0
  51. package/dist/security/epoch-public-pins.js.map +1 -0
  52. package/dist/security/epoch-recovery.d.ts +56 -0
  53. package/dist/security/epoch-recovery.d.ts.map +1 -0
  54. package/dist/security/epoch-recovery.js +314 -0
  55. package/dist/security/epoch-recovery.js.map +1 -0
  56. package/dist/security/epoch-store.d.ts +111 -0
  57. package/dist/security/epoch-store.d.ts.map +1 -0
  58. package/dist/security/epoch-store.js +224 -0
  59. package/dist/security/epoch-store.js.map +1 -0
  60. package/dist/security/epoch-sync.d.ts +47 -0
  61. package/dist/security/epoch-sync.d.ts.map +1 -0
  62. package/dist/security/epoch-sync.js +371 -0
  63. package/dist/security/epoch-sync.js.map +1 -0
  64. package/dist/security/team-epoch-grants.d.ts +28 -0
  65. package/dist/security/team-epoch-grants.d.ts.map +1 -0
  66. package/dist/security/team-epoch-grants.js +256 -0
  67. package/dist/security/team-epoch-grants.js.map +1 -0
  68. package/dist/server/http-context-routes.d.ts +2 -1
  69. package/dist/server/http-context-routes.d.ts.map +1 -1
  70. package/dist/server/http-context-routes.js +46 -15
  71. package/dist/server/http-context-routes.js.map +1 -1
  72. package/dist/server/http-server.js +1 -1
  73. package/dist/server/http-server.js.map +1 -1
  74. package/dist/server/rate-limiter.d.ts.map +1 -1
  75. package/dist/server/rate-limiter.js +2 -1
  76. package/dist/server/rate-limiter.js.map +1 -1
  77. package/dist/server/trusted-edge-command-capability.d.ts +1 -1
  78. package/dist/server/trusted-edge-command-capability.d.ts.map +1 -1
  79. package/dist/server/trusted-edge-command-capability.js +11 -0
  80. package/dist/server/trusted-edge-command-capability.js.map +1 -1
  81. package/dist/server/ws-command-handlers.d.ts.map +1 -1
  82. package/dist/server/ws-command-handlers.js +124 -28
  83. package/dist/server/ws-command-handlers.js.map +1 -1
  84. package/dist/server/ws-protocol.d.ts +268 -44
  85. package/dist/server/ws-protocol.d.ts.map +1 -1
  86. package/dist/server/ws-protocol.js +81 -19
  87. package/dist/server/ws-protocol.js.map +1 -1
  88. package/dist/startup.d.ts.map +1 -1
  89. package/dist/startup.js +0 -17
  90. package/dist/startup.js.map +1 -1
  91. package/docs/protocol-matrix.json +40 -8
  92. package/node_modules/@viewportai/context-engine/src/repo/materializer.js +20 -5
  93. package/node_modules/@viewportai/context-engine/src/repo/membership.js +15 -0
  94. package/node_modules/@viewportai/context-engine/src/repo/sync.js +4 -4
  95. package/node_modules/@viewportai/context-engine/src/repo/vault.js +8 -3
  96. package/package.json +1 -1
@@ -0,0 +1,285 @@
1
+ import crypto from 'node:crypto';
2
+ export const USER_EPOCH_SCHEMA = 'viewport.user_crypto_epoch/v1';
3
+ export const TEAM_EPOCH_SCHEMA = 'viewport.team_crypto_epoch/v1';
4
+ export const DEVICE_ENROLLMENT_SCHEMA = 'viewport.device_enrollment/v1';
5
+ export const RESOURCE_GRANT_SCHEMA = 'viewport.resource_key_grant/v1';
6
+ export const WRAPPED_KEY_ENVELOPE_SCHEMA = 'viewport.wrapped_key_envelope/v1';
7
+ export const TRUSTED_EDGE_CRYPTO_PROTOCOL_HEADER = 'X-Viewport-Crypto-Protocol';
8
+ export const TRUSTED_EDGE_CRYPTO_PROTOCOL_VERSION = 'viewport.trusted_edge_crypto/v2';
9
+ const PRIVATE_JWK_FIELDS = new Set([
10
+ 'd',
11
+ 'p',
12
+ 'q',
13
+ 'dp',
14
+ 'dq',
15
+ 'qi',
16
+ 'oth',
17
+ 'k',
18
+ 'x5c_private',
19
+ 'hpkePrivateKey',
20
+ 'privateKey',
21
+ 'secretKey',
22
+ ]);
23
+ export function canonicalJson(value) {
24
+ return JSON.stringify(canonicalize(value));
25
+ }
26
+ export function sha256Base64Url(value) {
27
+ return crypto.createHash('sha256').update(value).digest('base64url');
28
+ }
29
+ export function fingerprintPayload(value) {
30
+ return `sha256:${sha256Base64Url(canonicalJson(value))}`;
31
+ }
32
+ export function epochFingerprint(epoch) {
33
+ return fingerprintPayload({
34
+ schema: epoch.schema,
35
+ workspaceId: epoch.workspaceId,
36
+ subjectType: epoch.subjectType,
37
+ subjectId: epoch.subjectId,
38
+ epoch: epoch.epoch,
39
+ encryptionPublicKeyJwk: epoch.encryptionPublicKeyJwk,
40
+ signingPublicKeyJwk: epoch.signingPublicKeyJwk,
41
+ previousEpochFingerprint: epoch.previousEpochFingerprint ?? null,
42
+ });
43
+ }
44
+ export function deviceEnrollmentFingerprint(request) {
45
+ assertNoPrivateKeyMaterial(request.encryptionPublicKeyJwk);
46
+ assertNoPrivateKeyMaterial(request.signingPublicKeyJwk);
47
+ return fingerprintPayload({
48
+ schema: request.schema,
49
+ workspaceId: request.workspaceId,
50
+ deviceId: request.deviceId,
51
+ deviceLabel: request.deviceLabel,
52
+ encryptionPublicKeyJwk: request.encryptionPublicKeyJwk,
53
+ signingPublicKeyJwk: request.signingPublicKeyJwk,
54
+ nonce: request.nonce,
55
+ });
56
+ }
57
+ export function signDeviceEnrollmentRequest(input) {
58
+ const key = crypto.createPrivateKey({
59
+ key: input.signingPrivateKeyJwk,
60
+ format: 'jwk',
61
+ });
62
+ return {
63
+ payload: input.payload,
64
+ signature: crypto
65
+ .sign(null, Buffer.from(canonicalJson(input.payload)), key)
66
+ .toString('base64url'),
67
+ };
68
+ }
69
+ export function userEpochDeviceMaterializationPayload(input) {
70
+ return {
71
+ schema: 'viewport.user_epoch_device_materialization/v1',
72
+ workspaceId: input.workspaceId,
73
+ userId: input.userId,
74
+ enrollmentId: input.enrollmentId,
75
+ grantId: input.grantId,
76
+ userCryptoEpochId: input.userCryptoEpochId,
77
+ userEpochFingerprint: input.userEpochFingerprint,
78
+ recipientFingerprint: input.recipientFingerprint,
79
+ };
80
+ }
81
+ export function signUserEpochDeviceMaterialization(input) {
82
+ const key = crypto.createPrivateKey({
83
+ key: input.signingPrivateKeyJwk,
84
+ format: 'jwk',
85
+ });
86
+ return {
87
+ payload: input.payload,
88
+ signature: crypto
89
+ .sign(null, Buffer.from(canonicalJson(input.payload)), key)
90
+ .toString('base64url'),
91
+ signedByUserEpochFingerprint: input.signedByUserEpochFingerprint,
92
+ };
93
+ }
94
+ export function teamEpochMemberMaterializationPayload(input) {
95
+ return {
96
+ schema: 'viewport.team_epoch_member_materialization/v1',
97
+ workspaceId: input.workspaceId,
98
+ grantId: input.grantId,
99
+ teamCryptoEpochId: input.teamCryptoEpochId,
100
+ teamEpochFingerprint: input.teamEpochFingerprint,
101
+ recipientUserCryptoEpochId: input.recipientUserCryptoEpochId,
102
+ recipientUserEpochFingerprint: input.recipientUserEpochFingerprint,
103
+ };
104
+ }
105
+ export function signTeamEpochMemberMaterialization(input) {
106
+ const key = crypto.createPrivateKey({
107
+ key: input.signingPrivateKeyJwk,
108
+ format: 'jwk',
109
+ });
110
+ return {
111
+ payload: input.payload,
112
+ signature: crypto
113
+ .sign(null, Buffer.from(canonicalJson(input.payload)), key)
114
+ .toString('base64url'),
115
+ signedByTeamEpochFingerprint: input.signedByTeamEpochFingerprint,
116
+ };
117
+ }
118
+ export function contextGrantMaterializationPayload(input) {
119
+ return {
120
+ schema: 'viewport.context_vault_grant_materialization/v1',
121
+ workspaceId: input.workspaceId,
122
+ contextResourceId: input.contextResourceId,
123
+ grantEventId: input.grantEventId,
124
+ recipientName: input.recipientName,
125
+ keyEpoch: input.keyEpoch,
126
+ };
127
+ }
128
+ export function signContextGrantMaterialization(input) {
129
+ const key = crypto.createPrivateKey({
130
+ key: input.signingPrivateKeyJwk,
131
+ format: 'jwk',
132
+ });
133
+ return {
134
+ payload: input.payload,
135
+ signature: crypto
136
+ .sign(null, Buffer.from(canonicalJson(input.payload)), key)
137
+ .toString('base64url'),
138
+ signedByEpochFingerprint: input.signedByEpochFingerprint,
139
+ };
140
+ }
141
+ export function epochTransitionPayload(input) {
142
+ if (input.from.workspaceId !== input.to.workspaceId) {
143
+ throw new Error('Epoch transition workspace mismatch.');
144
+ }
145
+ if (input.from.subjectType !== input.to.subjectType ||
146
+ input.from.subjectId !== input.to.subjectId) {
147
+ throw new Error('Epoch transition subject mismatch.');
148
+ }
149
+ if (input.to.epoch !== input.from.epoch + 1) {
150
+ throw new Error('Epoch transition must advance by exactly one epoch.');
151
+ }
152
+ return {
153
+ schema: 'viewport.epoch_transition/v1',
154
+ workspaceId: input.from.workspaceId,
155
+ subjectType: input.from.subjectType,
156
+ subjectId: input.from.subjectId,
157
+ fromEpoch: input.from.epoch,
158
+ fromEpochFingerprint: epochFingerprint(input.from),
159
+ toEpoch: input.to.epoch,
160
+ toEpochFingerprint: epochFingerprint(input.to),
161
+ reason: input.reason,
162
+ createdAt: input.createdAt,
163
+ };
164
+ }
165
+ export function signEpochTransition(input) {
166
+ const key = crypto.createPrivateKey({
167
+ key: input.signingPrivateKeyJwk,
168
+ format: 'jwk',
169
+ });
170
+ const signature = crypto
171
+ .sign(null, Buffer.from(canonicalJson(input.payload)), key)
172
+ .toString('base64url');
173
+ return {
174
+ payload: input.payload,
175
+ signature,
176
+ signedByEpochFingerprint: input.signedByEpochFingerprint,
177
+ };
178
+ }
179
+ export function verifyEpochTransition(input) {
180
+ if (input.signed.signedByEpochFingerprint !== input.expectedFromEpochFingerprint)
181
+ return false;
182
+ if (input.signed.payload.fromEpochFingerprint !== input.expectedFromEpochFingerprint)
183
+ return false;
184
+ if (input.signed.payload.toEpochFingerprint !== input.expectedToEpochFingerprint)
185
+ return false;
186
+ const key = crypto.createPublicKey({
187
+ key: input.signingPublicKeyJwk,
188
+ format: 'jwk',
189
+ });
190
+ return crypto.verify(null, Buffer.from(canonicalJson(input.signed.payload)), key, Buffer.from(input.signed.signature, 'base64url'));
191
+ }
192
+ export function wrapJsonForX25519Recipient(input) {
193
+ assertNoPrivateKeyMaterial(input.recipientPublicKeyJwk);
194
+ const ephemeral = crypto.generateKeyPairSync('x25519');
195
+ const recipientPublicKey = crypto.createPublicKey({
196
+ key: input.recipientPublicKeyJwk,
197
+ format: 'jwk',
198
+ });
199
+ const sharedSecret = crypto.diffieHellman({
200
+ privateKey: ephemeral.privateKey,
201
+ publicKey: recipientPublicKey,
202
+ });
203
+ const aad = Buffer.from(canonicalJson(input.aad));
204
+ const iv = crypto.randomBytes(12);
205
+ const cipher = crypto.createCipheriv('aes-256-gcm', deriveWrapKey(sharedSecret), iv);
206
+ cipher.setAAD(aad);
207
+ const ciphertext = Buffer.concat([
208
+ cipher.update(Buffer.from(canonicalJson(input.payload))),
209
+ cipher.final(),
210
+ ]);
211
+ return {
212
+ schema: WRAPPED_KEY_ENVELOPE_SCHEMA,
213
+ alg: 'x25519-hkdf-sha256-aes-256-gcm',
214
+ ephemeralPublicKeyJwk: ephemeral.publicKey.export({ format: 'jwk' }),
215
+ iv: iv.toString('base64url'),
216
+ ciphertext: ciphertext.toString('base64url'),
217
+ tag: cipher.getAuthTag().toString('base64url'),
218
+ aadDigest: fingerprintPayload(input.aad),
219
+ createdAt: input.createdAt ?? new Date().toISOString(),
220
+ };
221
+ }
222
+ export function unwrapJsonFromX25519Envelope(input) {
223
+ if (input.envelope.schema !== WRAPPED_KEY_ENVELOPE_SCHEMA) {
224
+ throw new Error('Unsupported wrapped key envelope schema.');
225
+ }
226
+ if (input.envelope.alg !== 'x25519-hkdf-sha256-aes-256-gcm') {
227
+ throw new Error('Unsupported wrapped key envelope algorithm.');
228
+ }
229
+ const expectedAadDigest = fingerprintPayload(input.aad);
230
+ if (input.envelope.aadDigest !== expectedAadDigest) {
231
+ throw new Error('Wrapped key envelope AAD mismatch.');
232
+ }
233
+ const recipientPrivateKey = crypto.createPrivateKey({
234
+ key: input.recipientPrivateKeyJwk,
235
+ format: 'jwk',
236
+ });
237
+ const ephemeralPublicKey = crypto.createPublicKey({
238
+ key: input.envelope.ephemeralPublicKeyJwk,
239
+ format: 'jwk',
240
+ });
241
+ const sharedSecret = crypto.diffieHellman({
242
+ privateKey: recipientPrivateKey,
243
+ publicKey: ephemeralPublicKey,
244
+ });
245
+ const decipher = crypto.createDecipheriv('aes-256-gcm', deriveWrapKey(sharedSecret), Buffer.from(input.envelope.iv, 'base64url'));
246
+ decipher.setAAD(Buffer.from(canonicalJson(input.aad)));
247
+ decipher.setAuthTag(Buffer.from(input.envelope.tag, 'base64url'));
248
+ const plaintext = Buffer.concat([
249
+ decipher.update(Buffer.from(input.envelope.ciphertext, 'base64url')),
250
+ decipher.final(),
251
+ ]);
252
+ return JSON.parse(plaintext.toString('utf8'));
253
+ }
254
+ export function assertNoPrivateKeyMaterial(value, path = '$') {
255
+ if (Array.isArray(value)) {
256
+ value.forEach((item, index) => assertNoPrivateKeyMaterial(item, `${path}[${index}]`));
257
+ return;
258
+ }
259
+ if (!value || typeof value !== 'object')
260
+ return;
261
+ for (const [key, child] of Object.entries(value)) {
262
+ if (PRIVATE_JWK_FIELDS.has(key)) {
263
+ throw new Error(`Private key material is not allowed at ${path}.${key}.`);
264
+ }
265
+ assertNoPrivateKeyMaterial(child, `${path}.${key}`);
266
+ }
267
+ }
268
+ function deriveWrapKey(sharedSecret) {
269
+ return Buffer.from(crypto.hkdfSync('sha256', sharedSecret, Buffer.from('viewport-wrapped-key-envelope-salt-v1'), Buffer.from('viewport-wrapped-key-envelope/v1'), 32));
270
+ }
271
+ function canonicalize(value) {
272
+ if (Array.isArray(value))
273
+ return value.map((item) => canonicalize(item));
274
+ if (!value || typeof value !== 'object')
275
+ return value;
276
+ return Object.keys(value)
277
+ .sort()
278
+ .reduce((acc, key) => {
279
+ const child = value[key];
280
+ if (child !== undefined)
281
+ acc[key] = canonicalize(child);
282
+ return acc;
283
+ }, {});
284
+ }
285
+ //# sourceMappingURL=epoch-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epoch-protocol.js","sourceRoot":"","sources":["../../src/security/epoch-protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { type JsonValue } from './epoch-protocol.js';
2
+ import { type LocalPublicEpochPin } from './epoch-store.js';
3
+ export interface PublicEpochForPinning {
4
+ platformEpochId: string;
5
+ workspaceId: string;
6
+ subjectType: 'user' | 'team';
7
+ subjectId: string;
8
+ epoch: number;
9
+ schema: 'viewport.user_crypto_epoch/v1' | 'viewport.team_crypto_epoch/v1';
10
+ fingerprint: string;
11
+ encryptionPublicKeyJwk: JsonValue;
12
+ signingPublicKeyJwk: JsonValue;
13
+ previousEpochFingerprint?: string | null;
14
+ continuityPayload?: JsonValue | null;
15
+ continuitySignature?: string | null;
16
+ signedByEpochFingerprint?: string | null;
17
+ }
18
+ export declare function validateAndPinPublicEpoch(epoch: PublicEpochForPinning, home?: string): Promise<LocalPublicEpochPin>;
19
+ //# sourceMappingURL=epoch-public-pins.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epoch-public-pins.d.ts","sourceRoot":"","sources":["../../src/security/epoch-public-pins.ts"],"names":[],"mappings":"AACA,OAAO,EAKL,KAAK,SAAS,EAEf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,qBAAqB;IACpC,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,+BAA+B,GAAG,+BAA+B,CAAC;IAC1E,WAAW,EAAE,MAAM,CAAC;IACpB,sBAAsB,EAAE,SAAS,CAAC;IAClC,mBAAmB,EAAE,SAAS,CAAC;IAC/B,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzC,iBAAiB,CAAC,EAAE,SAAS,GAAG,IAAI,CAAC;IACrC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1C;AAED,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,qBAAqB,EAC5B,IAAI,SAAc,GACjB,OAAO,CAAC,mBAAmB,CAAC,CAoD9B"}
@@ -0,0 +1,129 @@
1
+ import { configDir } from '../core/config.js';
2
+ import { epochFingerprint, verifyEpochTransition, } from './epoch-protocol.js';
3
+ import { getLocalPublicEpochPin, upsertLocalPublicEpochPin, } from './epoch-store.js';
4
+ export async function validateAndPinPublicEpoch(epoch, home = configDir()) {
5
+ const descriptor = publicEpochDescriptor(epoch);
6
+ const computedFingerprint = epochFingerprint(descriptor);
7
+ if (computedFingerprint !== epoch.fingerprint) {
8
+ throw new Error(`Fetched ${epoch.subjectType} epoch fingerprint mismatch for ${epoch.subjectId}.`);
9
+ }
10
+ const previous = await getLocalPublicEpochPin({
11
+ workspaceId: epoch.workspaceId,
12
+ subjectType: epoch.subjectType,
13
+ subjectId: epoch.subjectId,
14
+ }, home);
15
+ if (previous) {
16
+ if (epoch.epoch < previous.epoch) {
17
+ throw new Error(`Fetched ${epoch.subjectType} epoch rollback for ${epoch.subjectId}: ${epoch.epoch} < ${previous.epoch}.`);
18
+ }
19
+ if (epoch.epoch === previous.epoch && epoch.fingerprint !== previous.fingerprint) {
20
+ throw new Error(`Fetched ${epoch.subjectType} epoch replacement for ${epoch.subjectId} requires signed continuity.`);
21
+ }
22
+ if (epoch.epoch > previous.epoch) {
23
+ assertSignedContinuity({ previous, next: epoch });
24
+ }
25
+ }
26
+ return upsertLocalPublicEpochPin({
27
+ workspaceId: epoch.workspaceId,
28
+ subjectType: epoch.subjectType,
29
+ subjectId: epoch.subjectId,
30
+ platformEpochId: epoch.platformEpochId,
31
+ epoch: epoch.epoch,
32
+ schema: epoch.schema,
33
+ fingerprint: epoch.fingerprint,
34
+ encryptionPublicKeyJwk: epoch.encryptionPublicKeyJwk,
35
+ signingPublicKeyJwk: epoch.signingPublicKeyJwk,
36
+ previousEpochFingerprint: epoch.previousEpochFingerprint ?? null,
37
+ continuityPayload: epoch.continuityPayload ?? null,
38
+ continuitySignature: epoch.continuitySignature ?? null,
39
+ signedByEpochFingerprint: epoch.signedByEpochFingerprint ?? null,
40
+ }, home);
41
+ }
42
+ function assertSignedContinuity(input) {
43
+ if (input.next.previousEpochFingerprint !== input.previous.fingerprint) {
44
+ throw new Error(`Fetched ${input.next.subjectType} epoch ${input.next.epoch} does not continue from pinned epoch ${input.previous.epoch}.`);
45
+ }
46
+ if (!input.next.continuityPayload || !input.next.continuitySignature) {
47
+ throw new Error(`Fetched ${input.next.subjectType} epoch ${input.next.epoch} is missing signed continuity.`);
48
+ }
49
+ const signed = {
50
+ payload: epochTransitionPayload(input.next.continuityPayload),
51
+ signature: input.next.continuitySignature,
52
+ signedByEpochFingerprint: input.next.signedByEpochFingerprint ?? input.next.previousEpochFingerprint ?? '',
53
+ };
54
+ const ok = verifyEpochTransition({
55
+ signed,
56
+ signingPublicKeyJwk: input.previous.signingPublicKeyJwk,
57
+ expectedFromEpochFingerprint: input.previous.fingerprint,
58
+ expectedToEpochFingerprint: input.next.fingerprint,
59
+ });
60
+ if (!ok) {
61
+ throw new Error(`Fetched ${input.next.subjectType} epoch ${input.next.epoch} continuity signature is invalid.`);
62
+ }
63
+ }
64
+ function publicEpochDescriptor(epoch) {
65
+ return {
66
+ schema: epoch.schema,
67
+ workspaceId: epoch.workspaceId,
68
+ subjectType: epoch.subjectType,
69
+ subjectId: epoch.subjectId,
70
+ epoch: epoch.epoch,
71
+ encryptionPublicKeyJwk: epoch.encryptionPublicKeyJwk,
72
+ signingPublicKeyJwk: epoch.signingPublicKeyJwk,
73
+ previousEpochFingerprint: epoch.previousEpochFingerprint ?? null,
74
+ createdAt: 'pinning-fingerprint-input',
75
+ };
76
+ }
77
+ function epochTransitionPayload(value) {
78
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
79
+ throw new Error('Epoch continuity payload must be an object.');
80
+ }
81
+ const data = value;
82
+ return {
83
+ schema: 'viewport.epoch_transition/v1',
84
+ workspaceId: stringField(data, 'workspaceId'),
85
+ subjectType: subjectTypeField(data, 'subjectType'),
86
+ subjectId: stringField(data, 'subjectId'),
87
+ fromEpoch: numberField(data, 'fromEpoch'),
88
+ fromEpochFingerprint: stringField(data, 'fromEpochFingerprint'),
89
+ toEpoch: numberField(data, 'toEpoch'),
90
+ toEpochFingerprint: stringField(data, 'toEpochFingerprint'),
91
+ reason: reasonField(data, 'reason'),
92
+ createdAt: stringField(data, 'createdAt'),
93
+ };
94
+ }
95
+ function stringField(value, field) {
96
+ const child = value[field];
97
+ if (typeof child !== 'string' || child.trim() === '') {
98
+ throw new Error(`Epoch continuity payload missing ${field}.`);
99
+ }
100
+ return child;
101
+ }
102
+ function numberField(value, field) {
103
+ const child = value[field];
104
+ if (typeof child !== 'number') {
105
+ throw new Error(`Epoch continuity payload missing numeric ${field}.`);
106
+ }
107
+ return child;
108
+ }
109
+ function subjectTypeField(value, field) {
110
+ const child = stringField(value, field);
111
+ if (child !== 'user' && child !== 'team') {
112
+ throw new Error(`Epoch continuity payload has unsupported ${field}.`);
113
+ }
114
+ return child;
115
+ }
116
+ function reasonField(value, field) {
117
+ const child = stringField(value, field);
118
+ if (child === 'initial' ||
119
+ child === 'device_enrolled' ||
120
+ child === 'device_revoked' ||
121
+ child === 'member_added' ||
122
+ child === 'member_revoked' ||
123
+ child === 'manual_rotation' ||
124
+ child === 'recovery') {
125
+ return child;
126
+ }
127
+ throw new Error(`Epoch continuity payload has unsupported ${field}.`);
128
+ }
129
+ //# sourceMappingURL=epoch-public-pins.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epoch-public-pins.js","sourceRoot":"","sources":["../../src/security/epoch-public-pins.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import { transportFetch } from '../cli/network.js';
2
+ import { type LocalUserCryptoEpoch } from './epoch-store.js';
3
+ import { type JsonValue } from './epoch-protocol.js';
4
+ import { type CryptoEpochSyncTarget } from './epoch-sync.js';
5
+ export declare const USER_EPOCH_RECOVERY_BACKUP_SCHEMA = "viewport.user_epoch_recovery_backup/v1";
6
+ declare const USER_EPOCH_RECOVERY_ENVELOPE_SCHEMA = "viewport.user_epoch_recovery_envelope/v1";
7
+ declare const RECOVERY_KDF = "scrypt-sha256/v1";
8
+ interface UserKeyBackupResponse {
9
+ id: string;
10
+ workspace_id: string;
11
+ user_id: number | string;
12
+ user_crypto_epoch_id: string;
13
+ schema: typeof USER_EPOCH_RECOVERY_BACKUP_SCHEMA;
14
+ status: string;
15
+ kdf: typeof RECOVERY_KDF;
16
+ kdf_params: RecoveryKdfParams;
17
+ encrypted_payload: RecoveryEnvelope;
18
+ created_at?: string | null;
19
+ }
20
+ interface RecoveryKdfParams {
21
+ salt: string;
22
+ keyLength: number;
23
+ N: number;
24
+ r: number;
25
+ p: number;
26
+ }
27
+ interface RecoveryEnvelope {
28
+ schema: typeof USER_EPOCH_RECOVERY_ENVELOPE_SCHEMA;
29
+ alg: 'aes-256-gcm';
30
+ aad: JsonValue;
31
+ iv: string;
32
+ ciphertext: string;
33
+ tag: string;
34
+ aadDigest: string;
35
+ createdAt: string;
36
+ }
37
+ export declare function generateUserEpochRecoveryKey(): string;
38
+ export declare function createUserEpochRecoveryBackup(options: {
39
+ target: CryptoEpochSyncTarget;
40
+ recoveryKey: string;
41
+ home?: string;
42
+ fetchImpl?: typeof transportFetch;
43
+ }): Promise<UserKeyBackupResponse>;
44
+ export declare function restoreUserEpochFromRecoveryBackup(options: {
45
+ target: CryptoEpochSyncTarget;
46
+ recoveryKey: string;
47
+ home?: string;
48
+ fetchImpl?: typeof transportFetch;
49
+ }): Promise<{
50
+ backup: UserKeyBackupResponse;
51
+ restoredEpoch: LocalUserCryptoEpoch;
52
+ rotatedEpoch: LocalUserCryptoEpoch;
53
+ rotatedBackup: UserKeyBackupResponse;
54
+ }>;
55
+ export {};
56
+ //# sourceMappingURL=epoch-recovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"epoch-recovery.d.ts","sourceRoot":"","sources":["../../src/security/epoch-recovery.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAyB,KAAK,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAEpF,eAAO,MAAM,iCAAiC,2CAA2C,CAAC;AAE1F,QAAA,MAAM,mCAAmC,6CAA6C,CAAC;AACvF,QAAA,MAAM,YAAY,qBAAqB,CAAC;AAWxC,UAAU,qBAAqB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,MAAM,EAAE,OAAO,iCAAiC,CAAC;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,OAAO,YAAY,CAAC;IACzB,UAAU,EAAE,iBAAiB,CAAC;IAC9B,iBAAiB,EAAE,gBAAgB,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED,UAAU,iBAAiB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,UAAU,gBAAgB;IACxB,MAAM,EAAE,OAAO,mCAAmC,CAAC;IACnD,GAAG,EAAE,aAAa,CAAC;IACnB,GAAG,EAAE,SAAS,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,4BAA4B,IAAI,MAAM,CAErD;AAED,wBAAsB,6BAA6B,CAAC,OAAO,EAAE;IAC3D,MAAM,EAAE,qBAAqB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,cAAc,CAAC;CACnC,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAkDjC;AAED,wBAAsB,kCAAkC,CAAC,OAAO,EAAE;IAChE,MAAM,EAAE,qBAAqB,CAAC;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,cAAc,CAAC;CACnC,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,qBAAqB,CAAC;IAC9B,aAAa,EAAE,oBAAoB,CAAC;IACpC,YAAY,EAAE,oBAAoB,CAAC;IACnC,aAAa,EAAE,qBAAqB,CAAC;CACtC,CAAC,CAqCD"}