@nextera.one/axis-server-sdk 2.2.1 → 2.2.2

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 (49) hide show
  1. package/dist/axis-sensor-GBEI3Fab.d.mts +209 -0
  2. package/dist/axis-sensor-GBEI3Fab.d.ts +209 -0
  3. package/dist/cce/index.d.mts +162 -0
  4. package/dist/cce/index.d.ts +162 -0
  5. package/dist/cce/index.js +1502 -0
  6. package/dist/cce/index.js.map +1 -0
  7. package/dist/cce/index.mjs +1442 -0
  8. package/dist/cce/index.mjs.map +1 -0
  9. package/dist/cce-pipeline-B-zUBHo3.d.mts +294 -0
  10. package/dist/cce-pipeline-DbGBSsCG.d.ts +294 -0
  11. package/dist/idel/index.d.mts +24 -0
  12. package/dist/idel/index.d.ts +24 -0
  13. package/dist/idel/index.js +306 -0
  14. package/dist/idel/index.js.map +1 -0
  15. package/dist/idel/index.mjs +279 -0
  16. package/dist/idel/index.mjs.map +1 -0
  17. package/dist/idel.types-DuUAcOnQ.d.mts +83 -0
  18. package/dist/idel.types-DuUAcOnQ.d.ts +83 -0
  19. package/dist/index-B2G6cbRL.d.mts +824 -0
  20. package/dist/index-DbSxdR0f.d.ts +824 -0
  21. package/dist/index-_S4fmVUJ.d.mts +501 -0
  22. package/dist/index-l3Hhirqb.d.ts +501 -0
  23. package/dist/index.d.mts +91 -1891
  24. package/dist/index.d.ts +91 -1891
  25. package/dist/index.js +9339 -5123
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +10326 -5816
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/needle/index.d.mts +4 -0
  30. package/dist/needle/index.d.ts +4 -0
  31. package/dist/needle/index.js +3499 -0
  32. package/dist/needle/index.js.map +1 -0
  33. package/dist/needle/index.mjs +3528 -0
  34. package/dist/needle/index.mjs.map +1 -0
  35. package/dist/sensors/index.d.mts +5 -0
  36. package/dist/sensors/index.d.ts +5 -0
  37. package/dist/sensors/index.js +12860 -0
  38. package/dist/sensors/index.js.map +1 -0
  39. package/dist/sensors/index.mjs +12928 -0
  40. package/dist/sensors/index.mjs.map +1 -0
  41. package/dist/timeline/index.d.mts +54 -0
  42. package/dist/timeline/index.d.ts +54 -0
  43. package/dist/timeline/index.js +389 -0
  44. package/dist/timeline/index.js.map +1 -0
  45. package/dist/timeline/index.mjs +362 -0
  46. package/dist/timeline/index.mjs.map +1 -0
  47. package/dist/timeline.types-Cn0aqbUj.d.mts +125 -0
  48. package/dist/timeline.types-Cn0aqbUj.d.ts +125 -0
  49. package/package.json +28 -10
@@ -0,0 +1,1502 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/cce/index.ts
20
+ var cce_exports = {};
21
+ __export(cce_exports, {
22
+ CCE_AES_KEY_BYTES: () => CCE_AES_KEY_BYTES,
23
+ CCE_DERIVATION: () => CCE_DERIVATION,
24
+ CCE_ERROR: () => CCE_ERROR,
25
+ CCE_IV_BYTES: () => CCE_IV_BYTES,
26
+ CCE_NONCE_BYTES: () => CCE_NONCE_BYTES,
27
+ CCE_PROTOCOL_VERSION: () => CCE_PROTOCOL_VERSION,
28
+ CCE_TAG_BYTES: () => CCE_TAG_BYTES,
29
+ CceAudienceIntentBindingSensor: () => CceAudienceIntentBindingSensor,
30
+ CceCapsuleVerificationSensor: () => CceCapsuleVerificationSensor,
31
+ CceClientSignatureSensor: () => CceClientSignatureSensor,
32
+ CceEnvelopeValidationSensor: () => CceEnvelopeValidationSensor,
33
+ CceError: () => CceError,
34
+ CcePayloadDecryptionSensor: () => CcePayloadDecryptionSensor,
35
+ CceReplayProtectionSensor: () => CceReplayProtectionSensor,
36
+ CceTpsWindowSensor: () => CceTpsWindowSensor,
37
+ InMemoryCceReplayStore: () => InMemoryCceReplayStore,
38
+ InMemoryCceWitnessStore: () => InMemoryCceWitnessStore,
39
+ aesGcmDecrypt: () => aesGcmDecrypt,
40
+ aesGcmEncrypt: () => aesGcmEncrypt,
41
+ base64UrlDecode: () => base64UrlDecode,
42
+ base64UrlEncode: () => base64UrlEncode,
43
+ buildCceErrorResponse: () => buildCceErrorResponse,
44
+ buildCceResponse: () => buildCceResponse,
45
+ buildExecutionContext: () => buildExecutionContext,
46
+ buildWitnessRecord: () => buildWitnessRecord,
47
+ deriveRequestExecutionKey: () => deriveRequestExecutionKey,
48
+ deriveResponseExecutionKey: () => deriveResponseExecutionKey,
49
+ deriveWitnessKey: () => deriveWitnessKey,
50
+ executeCcePipeline: () => executeCcePipeline,
51
+ extractVerificationState: () => extractVerificationState,
52
+ generateAesKey: () => generateAesKey,
53
+ generateCceNonce: () => generateCceNonce,
54
+ generateIv: () => generateIv,
55
+ hashPayload: () => hashPayload,
56
+ nodeAesGcmProvider: () => nodeAesGcmProvider
57
+ });
58
+ module.exports = __toCommonJS(cce_exports);
59
+
60
+ // src/cce/cce.types.ts
61
+ var CCE_PROTOCOL_VERSION = "cce-v1";
62
+ var CCE_DERIVATION = {
63
+ /** Request execution context */
64
+ REQUEST: "axis:cce:req:v1",
65
+ /** Response execution context */
66
+ RESPONSE: "axis:cce:resp:v1",
67
+ /** Witness binding context */
68
+ WITNESS: "axis:cce:witness:v1"
69
+ };
70
+ var CCE_AES_KEY_BYTES = 32;
71
+ var CCE_IV_BYTES = 12;
72
+ var CCE_TAG_BYTES = 16;
73
+ var CCE_NONCE_BYTES = 32;
74
+ var CCE_ERROR = {
75
+ // Envelope errors
76
+ INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
77
+ UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
78
+ MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
79
+ MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
80
+ // Signature errors
81
+ CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
82
+ CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
83
+ // Capsule errors
84
+ CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
85
+ CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
86
+ CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
87
+ CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
88
+ CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
89
+ // Binding errors
90
+ AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
91
+ INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
92
+ TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
93
+ TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
94
+ // Replay / nonce errors
95
+ REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
96
+ NONCE_REUSED: "CCE_NONCE_REUSED",
97
+ // Decryption errors
98
+ DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
99
+ KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
100
+ AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
101
+ PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
102
+ // Schema / validation errors
103
+ PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
104
+ INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
105
+ // Policy errors
106
+ POLICY_DENIED: "CCE_POLICY_DENIED",
107
+ CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
108
+ // Handler errors
109
+ HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
110
+ HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
111
+ HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
112
+ // Response errors
113
+ RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
114
+ };
115
+ var CceError = class extends Error {
116
+ constructor(code, message, metadata) {
117
+ super(`[${code}] ${message}`);
118
+ this.code = code;
119
+ this.metadata = metadata;
120
+ this.name = "CceError";
121
+ }
122
+ /** Whether this error is safe to expose to the client */
123
+ get clientSafe() {
124
+ const internal = [
125
+ CCE_ERROR.DECRYPTION_FAILED,
126
+ CCE_ERROR.KEY_UNWRAP_FAILED,
127
+ CCE_ERROR.AEAD_TAG_MISMATCH,
128
+ CCE_ERROR.HANDLER_EXECUTION_FAILED,
129
+ CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
130
+ ];
131
+ return !internal.includes(this.code);
132
+ }
133
+ /** Get client-safe representation */
134
+ toClientError() {
135
+ if (this.clientSafe) {
136
+ return { code: this.code, message: this.message };
137
+ }
138
+ return {
139
+ code: CCE_ERROR.DECRYPTION_FAILED,
140
+ message: "Request processing failed"
141
+ };
142
+ }
143
+ };
144
+
145
+ // src/cce/cce-derivation.service.ts
146
+ var import_utils = require("@noble/hashes/utils.js");
147
+ var import_hkdf = require("@noble/hashes/hkdf.js");
148
+ var import_sha2 = require("@noble/hashes/sha2.js");
149
+ function buildSalt(capsuleId, capsuleNonce, requestNonce) {
150
+ const encoder = new TextEncoder();
151
+ const data = encoder.encode(
152
+ capsuleId + "|" + capsuleNonce + "|" + requestNonce
153
+ );
154
+ return (0, import_sha2.sha256)(data);
155
+ }
156
+ function buildInfo(contextPrefix, capsule, extraNonce) {
157
+ const encoder = new TextEncoder();
158
+ const parts = [
159
+ contextPrefix,
160
+ capsule.sub,
161
+ capsule.kid,
162
+ capsule.intent,
163
+ capsule.aud,
164
+ String(capsule.tps_from),
165
+ String(capsule.tps_to),
166
+ capsule.policy_hash ?? "",
167
+ capsule.ver
168
+ ];
169
+ if (extraNonce) {
170
+ parts.push(extraNonce);
171
+ }
172
+ return encoder.encode(parts.join("|"));
173
+ }
174
+ function deriveRequestExecutionKey(input) {
175
+ const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
176
+ const salt = buildSalt(
177
+ input.capsule.capsule_id,
178
+ input.capsule.capsule_nonce,
179
+ input.requestNonce
180
+ );
181
+ const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
182
+ return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
183
+ }
184
+ function deriveResponseExecutionKey(input) {
185
+ const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
186
+ const encoder = new TextEncoder();
187
+ const saltData = encoder.encode(
188
+ input.capsule.capsule_id + "|" + input.capsule.capsule_nonce + "|" + input.requestNonce + "|" + input.responseNonce
189
+ );
190
+ const salt = (0, import_sha2.sha256)(saltData);
191
+ const info = buildInfo(
192
+ CCE_DERIVATION.RESPONSE,
193
+ input.capsule,
194
+ input.responseNonce
195
+ );
196
+ return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
197
+ }
198
+ function deriveWitnessKey(input) {
199
+ const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
200
+ const salt = buildSalt(
201
+ input.capsule.capsule_id,
202
+ input.capsule.capsule_nonce,
203
+ input.requestNonce
204
+ );
205
+ const info = buildInfo(CCE_DERIVATION.WITNESS, input.capsule);
206
+ return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
207
+ }
208
+ function buildExecutionContext(input, requestId) {
209
+ const executionKey = deriveRequestExecutionKey(input);
210
+ const keyHash = (0, import_utils.bytesToHex)((0, import_sha2.sha256)(executionKey));
211
+ executionKey.fill(0);
212
+ return {
213
+ execution_key_hash: keyHash,
214
+ request_id: requestId,
215
+ capsule_id: input.capsule.capsule_id,
216
+ sub: input.capsule.sub,
217
+ kid: input.capsule.kid,
218
+ intent: input.capsule.intent,
219
+ aud: input.capsule.aud,
220
+ tps_from: input.capsule.tps_from,
221
+ tps_to: input.capsule.tps_to,
222
+ policy_hash: input.capsule.policy_hash,
223
+ derived_at: Math.floor(Date.now() / 1e3),
224
+ valid: true
225
+ };
226
+ }
227
+ function generateCceNonce() {
228
+ const bytes = new Uint8Array(CCE_NONCE_BYTES);
229
+ crypto.getRandomValues(bytes);
230
+ return (0, import_utils.bytesToHex)(bytes);
231
+ }
232
+
233
+ // src/cce/cce-crypto.ts
234
+ var import_utils2 = require("@noble/hashes/utils.js");
235
+ var import_sha22 = require("@noble/hashes/sha2.js");
236
+ var import_crypto = require("crypto");
237
+ function aesGcmEncrypt(key, plaintext, aad) {
238
+ if (key.length !== CCE_AES_KEY_BYTES) {
239
+ throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
240
+ }
241
+ const iv = (0, import_crypto.randomBytes)(CCE_IV_BYTES);
242
+ const cipher = (0, import_crypto.createCipheriv)("aes-256-gcm", key, iv);
243
+ if (aad) {
244
+ cipher.setAAD(aad);
245
+ }
246
+ const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
247
+ const tag = cipher.getAuthTag();
248
+ return {
249
+ iv: new Uint8Array(iv),
250
+ ciphertext: new Uint8Array(encrypted),
251
+ tag: new Uint8Array(tag)
252
+ };
253
+ }
254
+ function aesGcmDecrypt(key, iv, ciphertext, tag, aad) {
255
+ if (key.length !== CCE_AES_KEY_BYTES) {
256
+ throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
257
+ }
258
+ if (iv.length !== CCE_IV_BYTES) {
259
+ throw new Error(`IV must be ${CCE_IV_BYTES} bytes`);
260
+ }
261
+ if (tag.length !== CCE_TAG_BYTES) {
262
+ throw new Error(`Tag must be ${CCE_TAG_BYTES} bytes`);
263
+ }
264
+ try {
265
+ const decipher = (0, import_crypto.createDecipheriv)("aes-256-gcm", key, iv);
266
+ decipher.setAuthTag(tag);
267
+ if (aad) {
268
+ decipher.setAAD(aad);
269
+ }
270
+ const decrypted = Buffer.concat([
271
+ decipher.update(ciphertext),
272
+ decipher.final()
273
+ ]);
274
+ return new Uint8Array(decrypted);
275
+ } catch {
276
+ return null;
277
+ }
278
+ }
279
+ function generateAesKey() {
280
+ return new Uint8Array((0, import_crypto.randomBytes)(CCE_AES_KEY_BYTES));
281
+ }
282
+ function generateIv() {
283
+ return new Uint8Array((0, import_crypto.randomBytes)(CCE_IV_BYTES));
284
+ }
285
+ function base64UrlEncode(bytes) {
286
+ return Buffer.from(bytes).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
287
+ }
288
+ function base64UrlDecode(input) {
289
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
290
+ const padding = "=".repeat((4 - base64.length % 4) % 4);
291
+ return new Uint8Array(Buffer.from(base64 + padding, "base64"));
292
+ }
293
+ function hashPayload(payload) {
294
+ return (0, import_utils2.bytesToHex)((0, import_sha22.sha256)(payload));
295
+ }
296
+ var nodeAesGcmProvider = {
297
+ async decrypt(key, iv, ciphertext, tag, aad) {
298
+ return aesGcmDecrypt(key, iv, ciphertext, tag, aad);
299
+ }
300
+ };
301
+
302
+ // src/cce/cce-response.service.ts
303
+ var import_utils3 = require("@noble/hashes/utils.js");
304
+ var import_crypto2 = require("crypto");
305
+ async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
306
+ const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
307
+ const responseNonce = (0, import_utils3.bytesToHex)(
308
+ new Uint8Array((0, import_crypto2.randomBytes)(CCE_NONCE_BYTES))
309
+ );
310
+ const responseId = generateResponseId();
311
+ const aesKey = generateAesKey();
312
+ const aad = buildResponseAad(
313
+ request.request_id,
314
+ responseId,
315
+ request.correlation_id,
316
+ capsule.capsule_id,
317
+ responseNonce
318
+ );
319
+ const { iv, ciphertext, tag } = aesGcmEncrypt(aesKey, body, aad);
320
+ const encryptedKey = await clientKeyEncryptor.wrapKey(
321
+ aesKey,
322
+ request.client_kid,
323
+ clientPublicKeyHex
324
+ );
325
+ aesKey.fill(0);
326
+ const encryptedPayload = {
327
+ alg: "AES-256-GCM",
328
+ iv: base64UrlEncode(iv),
329
+ ciphertext: base64UrlEncode(ciphertext),
330
+ tag: base64UrlEncode(tag)
331
+ };
332
+ const algorithms = {
333
+ kem: encryptedKey.alg,
334
+ enc: "AES-256-GCM",
335
+ kdf: "HKDF-SHA256",
336
+ sig: "EdDSA"
337
+ };
338
+ const unsignedResponse = {
339
+ ver: CCE_PROTOCOL_VERSION,
340
+ response_id: responseId,
341
+ request_id: request.request_id,
342
+ correlation_id: request.correlation_id,
343
+ capsule_id: capsule.capsule_id,
344
+ encrypted_key: encryptedKey,
345
+ encrypted_payload: encryptedPayload,
346
+ response_nonce: responseNonce,
347
+ algorithms,
348
+ status,
349
+ ...witnessRef ? { witness_ref: witnessRef } : {}
350
+ };
351
+ const signPayload = new TextEncoder().encode(canonicalize(unsignedResponse));
352
+ const axisSig = await axisSigner.sign(signPayload);
353
+ const envelope = {
354
+ ...unsignedResponse,
355
+ axis_sig: axisSig
356
+ };
357
+ return {
358
+ envelope,
359
+ responsePayloadHash: hashPayload(body)
360
+ };
361
+ }
362
+ function buildCceErrorResponse(requestId, correlationId, status, errorCode, message) {
363
+ return {
364
+ ver: CCE_PROTOCOL_VERSION,
365
+ request_id: requestId,
366
+ correlation_id: correlationId,
367
+ status,
368
+ error: { code: errorCode, message }
369
+ };
370
+ }
371
+ function generateResponseId() {
372
+ const bytes = (0, import_crypto2.randomBytes)(16);
373
+ return "resp_" + (0, import_utils3.bytesToHex)(new Uint8Array(bytes)).slice(0, 24);
374
+ }
375
+ function buildResponseAad(requestId, responseId, correlationId, capsuleId, responseNonce) {
376
+ const parts = [
377
+ requestId,
378
+ responseId,
379
+ correlationId,
380
+ capsuleId,
381
+ responseNonce
382
+ ];
383
+ return new TextEncoder().encode(parts.join("|"));
384
+ }
385
+ function canonicalize(obj) {
386
+ if (Array.isArray(obj)) {
387
+ return "[" + obj.map(canonicalize).join(",") + "]";
388
+ }
389
+ if (obj !== null && typeof obj === "object") {
390
+ const sorted = Object.keys(obj).sort().map(
391
+ (k) => JSON.stringify(k) + ":" + canonicalize(obj[k])
392
+ );
393
+ return "{" + sorted.join(",") + "}";
394
+ }
395
+ return JSON.stringify(obj);
396
+ }
397
+
398
+ // src/cce/cce-witness.observer.ts
399
+ var import_utils4 = require("@noble/hashes/utils.js");
400
+ var import_hkdf2 = require("@noble/hashes/hkdf.js");
401
+ var import_sha23 = require("@noble/hashes/sha2.js");
402
+ var InMemoryCceWitnessStore = class {
403
+ constructor() {
404
+ this.records = [];
405
+ }
406
+ async record(witness) {
407
+ this.records.push(witness);
408
+ }
409
+ getByRequestId(requestId) {
410
+ return this.records.find((w) => w.request_id === requestId);
411
+ }
412
+ getByCapsuleId(capsuleId) {
413
+ return this.records.filter((w) => w.capsule_id === capsuleId);
414
+ }
415
+ };
416
+ function buildWitnessRecord(envelope, capsule, verification, execution, options) {
417
+ const witnessId = generateWitnessId(envelope.request_id, capsule.capsule_id);
418
+ const executionContextHash = computeExecutionContextHash(
419
+ options.axisLocalSecret,
420
+ capsule,
421
+ envelope.request_nonce
422
+ );
423
+ return {
424
+ witness_id: witnessId,
425
+ request_id: envelope.request_id,
426
+ capsule_id: capsule.capsule_id,
427
+ sub: capsule.sub,
428
+ intent: capsule.intent,
429
+ aud: capsule.aud,
430
+ tps_from: capsule.tps_from,
431
+ tps_to: capsule.tps_to,
432
+ timestamp: Math.floor(Date.now() / 1e3),
433
+ verification: {
434
+ client_sig: verification.clientSigVerified,
435
+ capsule_sig: verification.capsuleSigVerified,
436
+ tps_valid: verification.tpsValid,
437
+ audience_match: verification.audienceMatch,
438
+ intent_match: verification.intentMatch,
439
+ replay_clean: verification.replayClean,
440
+ nonce_unique: verification.nonceUnique,
441
+ decryption_ok: verification.decryptionOk
442
+ },
443
+ execution: {
444
+ status: execution.status,
445
+ handler_duration_ms: execution.handlerDurationMs,
446
+ ...execution.effect ? { effect: execution.effect } : {}
447
+ },
448
+ response_encrypted: options.responseEncrypted,
449
+ execution_context_hash: executionContextHash,
450
+ ...options.requestPayload ? { request_payload_hash: hashPayload(options.requestPayload) } : {},
451
+ ...options.responsePayload ? { response_payload_hash: hashPayload(options.responsePayload) } : {}
452
+ };
453
+ }
454
+ function extractVerificationState(metadata) {
455
+ return {
456
+ clientSigVerified: metadata.cceClientSigVerified === true,
457
+ capsuleSigVerified: metadata.cceCapsuleVerified === true,
458
+ tpsValid: metadata.cceTpsValid === true,
459
+ audienceMatch: metadata.cceBindingVerified === true,
460
+ intentMatch: metadata.cceBindingVerified === true,
461
+ replayClean: metadata.cceReplayClean === true,
462
+ nonceUnique: metadata.cceReplayClean === true,
463
+ decryptionOk: metadata.cceDecryptionOk === true
464
+ };
465
+ }
466
+ function generateWitnessId(requestId, capsuleId) {
467
+ const input = `witness:${requestId}:${capsuleId}:${Date.now()}`;
468
+ const hash = (0, import_sha23.sha256)(new TextEncoder().encode(input));
469
+ return "wit_" + (0, import_utils4.bytesToHex)(hash).slice(0, 24);
470
+ }
471
+ function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
472
+ const encoder = new TextEncoder();
473
+ const ikm = hexToBytes2(axisLocalSecret);
474
+ const salt = (0, import_sha23.sha256)(
475
+ encoder.encode(
476
+ capsule.capsule_id + "|" + capsule.capsule_nonce + "|" + requestNonce
477
+ )
478
+ );
479
+ const info = encoder.encode(
480
+ [
481
+ CCE_DERIVATION.WITNESS,
482
+ capsule.sub,
483
+ capsule.kid,
484
+ capsule.intent,
485
+ capsule.aud,
486
+ String(capsule.tps_from),
487
+ String(capsule.tps_to),
488
+ capsule.policy_hash ?? "",
489
+ capsule.ver
490
+ ].join("|")
491
+ );
492
+ const witnessKey = (0, import_hkdf2.hkdf)(import_sha23.sha256, ikm, salt, info, 32);
493
+ const hash = (0, import_utils4.bytesToHex)((0, import_sha23.sha256)(witnessKey));
494
+ witnessKey.fill(0);
495
+ return hash;
496
+ }
497
+ function hexToBytes2(hex) {
498
+ const bytes = new Uint8Array(hex.length / 2);
499
+ for (let i = 0; i < bytes.length; i++) {
500
+ bytes[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
501
+ }
502
+ return bytes;
503
+ }
504
+
505
+ // src/sensor/axis-sensor.ts
506
+ function normalizeSensorDecision(sensorDecision) {
507
+ if ("action" in sensorDecision) {
508
+ switch (sensorDecision.action) {
509
+ case "ALLOW":
510
+ return {
511
+ allow: true,
512
+ riskScore: 0,
513
+ reasons: [],
514
+ meta: sensorDecision.meta
515
+ };
516
+ case "DENY":
517
+ return {
518
+ allow: false,
519
+ riskScore: 100,
520
+ reasons: [sensorDecision.code, sensorDecision.reason].filter(
521
+ Boolean
522
+ ),
523
+ meta: sensorDecision.meta,
524
+ retryAfterMs: sensorDecision.retryAfterMs
525
+ };
526
+ case "THROTTLE":
527
+ return {
528
+ allow: false,
529
+ riskScore: 50,
530
+ reasons: ["RATE_LIMIT"],
531
+ retryAfterMs: sensorDecision.retryAfterMs,
532
+ meta: sensorDecision.meta
533
+ };
534
+ case "FLAG":
535
+ return {
536
+ allow: true,
537
+ riskScore: sensorDecision.scoreDelta,
538
+ reasons: sensorDecision.reasons,
539
+ meta: sensorDecision.meta
540
+ };
541
+ }
542
+ }
543
+ return {
544
+ allow: sensorDecision.allow,
545
+ riskScore: sensorDecision.riskScore,
546
+ reasons: sensorDecision.reasons,
547
+ tags: sensorDecision.tags,
548
+ meta: sensorDecision.meta,
549
+ tighten: sensorDecision.tighten,
550
+ retryAfterMs: sensorDecision.retryAfterMs
551
+ };
552
+ }
553
+
554
+ // src/cce/cce-pipeline.ts
555
+ async function executeCcePipeline(envelope, config) {
556
+ const startTime = Date.now();
557
+ if (envelope.ver !== CCE_PROTOCOL_VERSION) {
558
+ return {
559
+ ok: false,
560
+ error: {
561
+ code: CCE_ERROR.UNSUPPORTED_VERSION,
562
+ message: `Unsupported version: ${envelope.ver}`
563
+ },
564
+ status: "ERROR"
565
+ };
566
+ }
567
+ const sensorInput = {
568
+ intent: envelope.capsule.intent,
569
+ metadata: {
570
+ cce: true,
571
+ cceEnvelope: envelope,
572
+ contentType: "application/axis-cce"
573
+ }
574
+ };
575
+ const sortedSensors = [...config.sensors].sort(
576
+ (a, b) => (a.order ?? 999) - (b.order ?? 999)
577
+ );
578
+ for (const sensor of sortedSensors) {
579
+ if (sensor.supports && !sensor.supports(sensorInput)) {
580
+ continue;
581
+ }
582
+ let decision;
583
+ try {
584
+ decision = await sensor.run(sensorInput);
585
+ } catch (err) {
586
+ return {
587
+ ok: false,
588
+ error: {
589
+ code: CCE_ERROR.DECRYPTION_FAILED,
590
+ message: `Sensor ${sensor.name} failed`
591
+ },
592
+ status: "ERROR"
593
+ };
594
+ }
595
+ const normalized = normalizeSensorDecision(decision);
596
+ if (!normalized.allow) {
597
+ const code = normalized.reasons[0]?.split(":")[0] ?? CCE_ERROR.DECRYPTION_FAILED;
598
+ return {
599
+ ok: false,
600
+ error: { code, message: normalized.reasons.join("; ") },
601
+ status: "DENIED"
602
+ };
603
+ }
604
+ }
605
+ const capsule = sensorInput.metadata?.cceCapsule;
606
+ const decryptedPayload = sensorInput.metadata?.cceDecryptedPayload;
607
+ const clientKey = sensorInput.metadata?.cceClientKey;
608
+ if (!capsule || !decryptedPayload || !clientKey) {
609
+ return {
610
+ ok: false,
611
+ error: {
612
+ code: CCE_ERROR.DECRYPTION_FAILED,
613
+ message: "Sensor chain did not produce required outputs"
614
+ },
615
+ status: "ERROR"
616
+ };
617
+ }
618
+ const derivationInput = {
619
+ axisLocalSecret: config.axisLocalSecret,
620
+ capsule,
621
+ requestNonce: envelope.request_nonce
622
+ };
623
+ const executionContext = buildExecutionContext(
624
+ derivationInput,
625
+ envelope.request_id
626
+ );
627
+ if (config.policyEvaluator) {
628
+ try {
629
+ const policyDecision = await config.policyEvaluator.evaluate({
630
+ envelope,
631
+ capsule,
632
+ executionContext,
633
+ decryptedPayload,
634
+ clientPublicKeyHex: clientKey.publicKeyHex
635
+ });
636
+ if (!policyDecision.allow) {
637
+ const verification2 = extractVerificationState(sensorInput.metadata ?? {});
638
+ const witness2 = buildWitnessRecord(
639
+ envelope,
640
+ capsule,
641
+ verification2,
642
+ {
643
+ status: "DENIED",
644
+ handlerDurationMs: 0,
645
+ effect: "policy_denied"
646
+ },
647
+ {
648
+ axisLocalSecret: config.axisLocalSecret,
649
+ requestPayload: decryptedPayload,
650
+ responseEncrypted: false
651
+ }
652
+ );
653
+ await config.witnessStore.record(witness2);
654
+ return {
655
+ ok: false,
656
+ error: {
657
+ code: policyDecision.code ?? CCE_ERROR.POLICY_DENIED,
658
+ message: policyDecision.message ?? "Request denied by policy evaluator"
659
+ },
660
+ status: "DENIED"
661
+ };
662
+ }
663
+ } catch (err) {
664
+ return {
665
+ ok: false,
666
+ error: {
667
+ code: CCE_ERROR.POLICY_DENIED,
668
+ message: "Policy evaluator failed"
669
+ },
670
+ status: "ERROR"
671
+ };
672
+ }
673
+ }
674
+ const handler = config.handlers.get(capsule.intent);
675
+ if (!handler) {
676
+ return {
677
+ ok: false,
678
+ error: {
679
+ code: CCE_ERROR.HANDLER_NOT_FOUND,
680
+ message: `No handler for intent: ${capsule.intent}`
681
+ },
682
+ status: "ERROR"
683
+ };
684
+ }
685
+ const handlerContext = {
686
+ capsule,
687
+ executionContext,
688
+ envelope,
689
+ clientPublicKeyHex: clientKey.publicKeyHex,
690
+ intent: capsule.intent,
691
+ sub: capsule.sub
692
+ };
693
+ let result;
694
+ const handlerStart = Date.now();
695
+ try {
696
+ result = await handler(decryptedPayload, handlerContext);
697
+ } catch (err) {
698
+ const handlerDuration2 = Date.now() - handlerStart;
699
+ const verification2 = extractVerificationState(sensorInput.metadata ?? {});
700
+ const witness2 = buildWitnessRecord(
701
+ envelope,
702
+ capsule,
703
+ verification2,
704
+ { status: "FAILED", handlerDurationMs: handlerDuration2 },
705
+ {
706
+ axisLocalSecret: config.axisLocalSecret,
707
+ requestPayload: decryptedPayload,
708
+ responseEncrypted: false
709
+ }
710
+ );
711
+ await config.witnessStore.record(witness2);
712
+ return {
713
+ ok: false,
714
+ error: {
715
+ code: CCE_ERROR.HANDLER_EXECUTION_FAILED,
716
+ message: "Handler execution failed"
717
+ },
718
+ status: "FAILED"
719
+ };
720
+ }
721
+ const handlerDuration = Date.now() - handlerStart;
722
+ let responseEnvelope;
723
+ let responsePayloadHash;
724
+ try {
725
+ const responseResult = await buildCceResponse(
726
+ {
727
+ request: envelope,
728
+ capsule,
729
+ status: result.status,
730
+ body: result.body,
731
+ clientPublicKeyHex: clientKey.publicKeyHex
732
+ },
733
+ config.clientKeyEncryptor,
734
+ config.axisSigner
735
+ );
736
+ responseEnvelope = responseResult.envelope;
737
+ responsePayloadHash = responseResult.responsePayloadHash;
738
+ } catch (err) {
739
+ return {
740
+ ok: false,
741
+ error: {
742
+ code: CCE_ERROR.RESPONSE_ENCRYPTION_FAILED,
743
+ message: "Response encryption failed"
744
+ },
745
+ status: "ERROR"
746
+ };
747
+ }
748
+ const verification = extractVerificationState(sensorInput.metadata ?? {});
749
+ const witness = buildWitnessRecord(
750
+ envelope,
751
+ capsule,
752
+ verification,
753
+ {
754
+ status: result.status,
755
+ handlerDurationMs: handlerDuration,
756
+ effect: result.effect
757
+ },
758
+ {
759
+ axisLocalSecret: config.axisLocalSecret,
760
+ requestPayload: decryptedPayload,
761
+ responsePayload: result.body,
762
+ responseEncrypted: true
763
+ }
764
+ );
765
+ await config.witnessStore.record(witness);
766
+ return {
767
+ ok: true,
768
+ response: responseEnvelope,
769
+ witnessId: witness.witness_id
770
+ };
771
+ }
772
+
773
+ // src/cce/sensors/cce-envelope-validation.sensor.ts
774
+ var REQUIRED_FIELDS = [
775
+ "ver",
776
+ "request_id",
777
+ "correlation_id",
778
+ "client_kid",
779
+ "capsule",
780
+ "encrypted_key",
781
+ "encrypted_payload",
782
+ "request_nonce",
783
+ "client_sig",
784
+ "content_type",
785
+ "algorithms"
786
+ ];
787
+ var CceEnvelopeValidationSensor = class {
788
+ constructor() {
789
+ this.name = "cce.envelope.validation";
790
+ this.order = 5;
791
+ this.phase = "PRE_DECODE";
792
+ }
793
+ supports(input) {
794
+ return input.metadata?.cce === true || input.metadata?.contentType === "application/axis-cce";
795
+ }
796
+ async run(input) {
797
+ const envelope = input.metadata?.cceEnvelope;
798
+ if (!envelope) {
799
+ return {
800
+ allow: false,
801
+ riskScore: 100,
802
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
803
+ code: CCE_ERROR.INVALID_ENVELOPE
804
+ };
805
+ }
806
+ for (const field of REQUIRED_FIELDS) {
807
+ if (envelope[field] === void 0 || envelope[field] === null) {
808
+ return {
809
+ allow: false,
810
+ riskScore: 100,
811
+ reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: missing ${field}`],
812
+ code: CCE_ERROR.INVALID_ENVELOPE
813
+ };
814
+ }
815
+ }
816
+ if (envelope.ver !== CCE_PROTOCOL_VERSION) {
817
+ return {
818
+ allow: false,
819
+ riskScore: 100,
820
+ reasons: [`${CCE_ERROR.UNSUPPORTED_VERSION}: ${envelope.ver}`],
821
+ code: CCE_ERROR.UNSUPPORTED_VERSION
822
+ };
823
+ }
824
+ if (!/^[0-9a-f]+$/i.test(envelope.request_nonce)) {
825
+ return {
826
+ allow: false,
827
+ riskScore: 100,
828
+ reasons: [
829
+ `${CCE_ERROR.INVALID_ENVELOPE}: invalid request_nonce format`
830
+ ],
831
+ code: CCE_ERROR.INVALID_ENVELOPE
832
+ };
833
+ }
834
+ if (envelope.request_nonce.length !== CCE_NONCE_BYTES * 2) {
835
+ return {
836
+ allow: false,
837
+ riskScore: 100,
838
+ reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: request_nonce wrong length`],
839
+ code: CCE_ERROR.INVALID_ENVELOPE
840
+ };
841
+ }
842
+ const capsule = envelope.capsule;
843
+ if (!capsule.capsule_id || !capsule.ver || !capsule.sub || !capsule.kid || !capsule.intent || !capsule.aud || !capsule.issuer_sig) {
844
+ return {
845
+ allow: false,
846
+ riskScore: 100,
847
+ reasons: [`${CCE_ERROR.MISSING_CAPSULE}: incomplete capsule claims`],
848
+ code: CCE_ERROR.MISSING_CAPSULE
849
+ };
850
+ }
851
+ if (!envelope.encrypted_key.ciphertext || !envelope.encrypted_key.alg) {
852
+ return {
853
+ allow: false,
854
+ riskScore: 100,
855
+ reasons: [
856
+ `${CCE_ERROR.MISSING_ENCRYPTED_KEY}: incomplete encrypted_key`
857
+ ],
858
+ code: CCE_ERROR.MISSING_ENCRYPTED_KEY
859
+ };
860
+ }
861
+ input.metadata = input.metadata ?? {};
862
+ input.metadata.cceEnvelopeValid = true;
863
+ return {
864
+ decision: "ALLOW" /* ALLOW */,
865
+ allow: true,
866
+ riskScore: 0,
867
+ reasons: []
868
+ };
869
+ }
870
+ };
871
+
872
+ // src/cce/sensors/cce-client-signature.sensor.ts
873
+ var CceClientSignatureSensor = class {
874
+ constructor(keyResolver, signatureVerifier) {
875
+ this.keyResolver = keyResolver;
876
+ this.signatureVerifier = signatureVerifier;
877
+ this.name = "cce.client.signature";
878
+ this.order = 45;
879
+ this.phase = "POST_DECODE";
880
+ }
881
+ supports(input) {
882
+ return input.metadata?.cceEnvelopeValid === true;
883
+ }
884
+ async run(input) {
885
+ const envelope = input.metadata?.cceEnvelope;
886
+ if (!envelope) {
887
+ return {
888
+ allow: false,
889
+ riskScore: 100,
890
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
891
+ code: CCE_ERROR.INVALID_ENVELOPE
892
+ };
893
+ }
894
+ const keyRecord = await this.keyResolver.resolve(envelope.client_kid);
895
+ if (!keyRecord) {
896
+ return {
897
+ allow: false,
898
+ riskScore: 100,
899
+ reasons: [
900
+ `${CCE_ERROR.CLIENT_KEY_NOT_FOUND}: kid=${envelope.client_kid}`
901
+ ],
902
+ code: CCE_ERROR.CLIENT_KEY_NOT_FOUND
903
+ };
904
+ }
905
+ const { client_sig, ...signable } = envelope;
906
+ const canonical = canonicalize2(signable);
907
+ const message = new TextEncoder().encode(canonical);
908
+ const valid = await this.signatureVerifier.verify(
909
+ message,
910
+ client_sig.value,
911
+ keyRecord.publicKeyHex,
912
+ keyRecord.alg
913
+ );
914
+ if (!valid) {
915
+ return {
916
+ allow: false,
917
+ riskScore: 100,
918
+ reasons: [CCE_ERROR.CLIENT_SIG_INVALID],
919
+ code: CCE_ERROR.CLIENT_SIG_INVALID
920
+ };
921
+ }
922
+ input.metadata = input.metadata ?? {};
923
+ input.metadata.cceClientKey = keyRecord;
924
+ input.metadata.cceClientSigVerified = true;
925
+ return {
926
+ decision: "ALLOW" /* ALLOW */,
927
+ allow: true,
928
+ riskScore: 0,
929
+ reasons: [],
930
+ meta: { kid: envelope.client_kid }
931
+ };
932
+ }
933
+ };
934
+ function canonicalize2(obj) {
935
+ if (Array.isArray(obj)) {
936
+ return "[" + obj.map(canonicalize2).join(",") + "]";
937
+ }
938
+ if (obj !== null && typeof obj === "object") {
939
+ const sorted = Object.keys(obj).sort().map(
940
+ (k) => JSON.stringify(k) + ":" + canonicalize2(obj[k])
941
+ );
942
+ return "{" + sorted.join(",") + "}";
943
+ }
944
+ return JSON.stringify(obj);
945
+ }
946
+
947
+ // src/cce/sensors/cce-capsule-verification.sensor.ts
948
+ var import_blake3 = require("@noble/hashes/blake3.js");
949
+ var import_utils5 = require("@noble/hashes/utils.js");
950
+ var CceCapsuleVerificationSensor = class {
951
+ constructor(issuerKeyResolver, capsuleVerifier) {
952
+ this.issuerKeyResolver = issuerKeyResolver;
953
+ this.capsuleVerifier = capsuleVerifier;
954
+ this.name = "cce.capsule.verification";
955
+ this.order = 50;
956
+ this.phase = "POST_DECODE";
957
+ }
958
+ supports(input) {
959
+ return input.metadata?.cceEnvelopeValid === true;
960
+ }
961
+ async run(input) {
962
+ const capsule = input.metadata?.cceEnvelope?.capsule;
963
+ if (!capsule) {
964
+ return {
965
+ allow: false,
966
+ riskScore: 100,
967
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
968
+ code: CCE_ERROR.MISSING_CAPSULE
969
+ };
970
+ }
971
+ if (capsule.ver !== CCE_PROTOCOL_VERSION) {
972
+ return {
973
+ allow: false,
974
+ riskScore: 100,
975
+ reasons: [
976
+ `${CCE_ERROR.CAPSULE_SIG_INVALID}: wrong version ${capsule.ver}`
977
+ ],
978
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
979
+ };
980
+ }
981
+ const { capsule_id, issuer_sig, ...claimsBody } = capsule;
982
+ const expectedId = computeCceCapsuleId(claimsBody);
983
+ if (capsule_id !== expectedId) {
984
+ return {
985
+ allow: false,
986
+ riskScore: 100,
987
+ reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: content hash mismatch`],
988
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
989
+ };
990
+ }
991
+ const issuerKey = await this.issuerKeyResolver.resolve(
992
+ capsule.issuer_sig.kid
993
+ );
994
+ if (!issuerKey) {
995
+ return {
996
+ allow: false,
997
+ riskScore: 100,
998
+ reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: issuer key not found`],
999
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
1000
+ };
1001
+ }
1002
+ const { issuer_sig: sig, ...rest } = capsule;
1003
+ const sigValid = await this.capsuleVerifier.verify(
1004
+ rest,
1005
+ sig,
1006
+ issuerKey.publicKeyHex
1007
+ );
1008
+ if (!sigValid) {
1009
+ return {
1010
+ allow: false,
1011
+ riskScore: 100,
1012
+ reasons: [CCE_ERROR.CAPSULE_SIG_INVALID],
1013
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
1014
+ };
1015
+ }
1016
+ const nowSeconds = Math.floor(Date.now() / 1e3);
1017
+ if (capsule.exp < nowSeconds) {
1018
+ return {
1019
+ allow: false,
1020
+ riskScore: 100,
1021
+ reasons: [`${CCE_ERROR.CAPSULE_EXPIRED}: exp=${capsule.exp}`],
1022
+ code: CCE_ERROR.CAPSULE_EXPIRED
1023
+ };
1024
+ }
1025
+ if (capsule.iat > nowSeconds + 5) {
1026
+ return {
1027
+ allow: false,
1028
+ riskScore: 100,
1029
+ reasons: [`${CCE_ERROR.CAPSULE_NOT_YET_VALID}: iat=${capsule.iat}`],
1030
+ code: CCE_ERROR.CAPSULE_NOT_YET_VALID
1031
+ };
1032
+ }
1033
+ input.metadata = input.metadata ?? {};
1034
+ input.metadata.cceCapsuleVerified = true;
1035
+ input.metadata.cceCapsule = capsule;
1036
+ return {
1037
+ decision: "ALLOW" /* ALLOW */,
1038
+ allow: true,
1039
+ riskScore: 0,
1040
+ reasons: [],
1041
+ meta: { capsule_id: capsule.capsule_id }
1042
+ };
1043
+ }
1044
+ };
1045
+ function canonicalize3(obj) {
1046
+ if (Array.isArray(obj)) {
1047
+ return "[" + obj.map(canonicalize3).join(",") + "]";
1048
+ }
1049
+ if (obj !== null && typeof obj === "object") {
1050
+ const sorted = Object.keys(obj).sort().map(
1051
+ (k) => JSON.stringify(k) + ":" + canonicalize3(obj[k])
1052
+ );
1053
+ return "{" + sorted.join(",") + "}";
1054
+ }
1055
+ return JSON.stringify(obj);
1056
+ }
1057
+ function computeCceCapsuleId(claims) {
1058
+ const canonical = canonicalize3(claims);
1059
+ const hash = (0, import_blake3.blake3)(new TextEncoder().encode(canonical));
1060
+ return "cce_b3_" + (0, import_utils5.bytesToHex)(hash).slice(0, 32);
1061
+ }
1062
+
1063
+ // src/cce/sensors/cce-tps-window.sensor.ts
1064
+ var DEFAULT_SKEW_MS = 5e3;
1065
+ var CceTpsWindowSensor = class {
1066
+ constructor(skewMs = DEFAULT_SKEW_MS) {
1067
+ this.skewMs = skewMs;
1068
+ this.name = "cce.tps.window";
1069
+ this.order = 92;
1070
+ this.phase = "POST_DECODE";
1071
+ }
1072
+ supports(input) {
1073
+ return input.metadata?.cceCapsuleVerified === true;
1074
+ }
1075
+ async run(input) {
1076
+ const capsule = input.metadata?.cceCapsule;
1077
+ if (!capsule) {
1078
+ return {
1079
+ allow: false,
1080
+ riskScore: 100,
1081
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
1082
+ code: CCE_ERROR.MISSING_CAPSULE
1083
+ };
1084
+ }
1085
+ const nowMs = Date.now();
1086
+ if (nowMs > capsule.tps_to + this.skewMs) {
1087
+ return {
1088
+ allow: false,
1089
+ riskScore: 100,
1090
+ reasons: [
1091
+ `${CCE_ERROR.TPS_WINDOW_EXPIRED}: window ended at ${capsule.tps_to}, now=${nowMs}`
1092
+ ],
1093
+ code: CCE_ERROR.TPS_WINDOW_EXPIRED
1094
+ };
1095
+ }
1096
+ if (nowMs < capsule.tps_from - this.skewMs) {
1097
+ return {
1098
+ allow: false,
1099
+ riskScore: 100,
1100
+ reasons: [
1101
+ `${CCE_ERROR.TPS_WINDOW_FUTURE}: window starts at ${capsule.tps_from}, now=${nowMs}`
1102
+ ],
1103
+ code: CCE_ERROR.TPS_WINDOW_FUTURE
1104
+ };
1105
+ }
1106
+ input.metadata = input.metadata ?? {};
1107
+ input.metadata.cceTpsValid = true;
1108
+ return {
1109
+ decision: "ALLOW" /* ALLOW */,
1110
+ allow: true,
1111
+ riskScore: 0,
1112
+ reasons: []
1113
+ };
1114
+ }
1115
+ };
1116
+
1117
+ // src/cce/sensors/cce-audience-intent-binding.sensor.ts
1118
+ var CceAudienceIntentBindingSensor = class {
1119
+ constructor(axisAudience) {
1120
+ this.axisAudience = axisAudience;
1121
+ this.name = "cce.audience.intent.binding";
1122
+ this.order = 95;
1123
+ this.phase = "POST_DECODE";
1124
+ }
1125
+ supports(input) {
1126
+ return input.metadata?.cceCapsuleVerified === true;
1127
+ }
1128
+ async run(input) {
1129
+ const capsule = input.metadata?.cceCapsule;
1130
+ const envelope = input.metadata?.cceEnvelope;
1131
+ if (!capsule || !envelope) {
1132
+ return {
1133
+ allow: false,
1134
+ riskScore: 100,
1135
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
1136
+ code: CCE_ERROR.MISSING_CAPSULE
1137
+ };
1138
+ }
1139
+ if (capsule.aud !== this.axisAudience) {
1140
+ return {
1141
+ allow: false,
1142
+ riskScore: 100,
1143
+ reasons: [
1144
+ `${CCE_ERROR.AUDIENCE_MISMATCH}: capsule.aud=${capsule.aud}, expected=${this.axisAudience}`
1145
+ ],
1146
+ code: CCE_ERROR.AUDIENCE_MISMATCH
1147
+ };
1148
+ }
1149
+ const requestIntent = input.intent ?? input.metadata?.cceRequestIntent;
1150
+ if (requestIntent && capsule.intent !== requestIntent) {
1151
+ return {
1152
+ allow: false,
1153
+ riskScore: 100,
1154
+ reasons: [
1155
+ `${CCE_ERROR.INTENT_MISMATCH}: capsule.intent=${capsule.intent}, request=${requestIntent}`
1156
+ ],
1157
+ code: CCE_ERROR.INTENT_MISMATCH
1158
+ };
1159
+ }
1160
+ if (envelope.client_kid !== capsule.kid) {
1161
+ return {
1162
+ allow: false,
1163
+ riskScore: 100,
1164
+ reasons: [
1165
+ `${CCE_ERROR.INTENT_MISMATCH}: envelope.kid=${envelope.client_kid}, capsule.kid=${capsule.kid}`
1166
+ ],
1167
+ code: CCE_ERROR.INTENT_MISMATCH
1168
+ };
1169
+ }
1170
+ input.metadata = input.metadata ?? {};
1171
+ input.metadata.cceBindingVerified = true;
1172
+ return {
1173
+ decision: "ALLOW" /* ALLOW */,
1174
+ allow: true,
1175
+ riskScore: 0,
1176
+ reasons: []
1177
+ };
1178
+ }
1179
+ };
1180
+
1181
+ // src/cce/sensors/cce-replay-protection.sensor.ts
1182
+ var InMemoryCceReplayStore = class {
1183
+ constructor() {
1184
+ this.nonces = /* @__PURE__ */ new Map();
1185
+ this.consumed = /* @__PURE__ */ new Set();
1186
+ this.revoked = /* @__PURE__ */ new Set();
1187
+ }
1188
+ async checkAndMark(key, ttlMs) {
1189
+ this.cleanup();
1190
+ if (this.nonces.has(key)) return false;
1191
+ this.nonces.set(key, Date.now() + ttlMs);
1192
+ return true;
1193
+ }
1194
+ async isCapsuleConsumed(capsuleId) {
1195
+ return this.consumed.has(capsuleId);
1196
+ }
1197
+ async markCapsuleConsumed(capsuleId, _ttlMs) {
1198
+ this.consumed.add(capsuleId);
1199
+ }
1200
+ async isCapsuleRevoked(capsuleId) {
1201
+ return this.revoked.has(capsuleId);
1202
+ }
1203
+ /** Revoke a capsule (for testing/admin) */
1204
+ revoke(capsuleId) {
1205
+ this.revoked.add(capsuleId);
1206
+ }
1207
+ cleanup() {
1208
+ const now = Date.now();
1209
+ for (const [key, expiresAt] of this.nonces) {
1210
+ if (expiresAt < now) this.nonces.delete(key);
1211
+ }
1212
+ }
1213
+ };
1214
+ var CceReplayProtectionSensor = class {
1215
+ constructor(replayStore, options) {
1216
+ this.replayStore = replayStore;
1217
+ this.name = "cce.replay.protection";
1218
+ this.order = 98;
1219
+ this.phase = "POST_DECODE";
1220
+ this.nonceTtlMs = options?.nonceTtlMs ?? 5 * 60 * 1e3;
1221
+ }
1222
+ supports(input) {
1223
+ return input.metadata?.cceCapsuleVerified === true;
1224
+ }
1225
+ async run(input) {
1226
+ const capsule = input.metadata?.cceCapsule;
1227
+ const envelope = input.metadata?.cceEnvelope;
1228
+ if (!capsule || !envelope) {
1229
+ return {
1230
+ allow: false,
1231
+ riskScore: 100,
1232
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
1233
+ code: CCE_ERROR.MISSING_CAPSULE
1234
+ };
1235
+ }
1236
+ const revoked = await this.replayStore.isCapsuleRevoked(capsule.capsule_id);
1237
+ if (revoked) {
1238
+ return {
1239
+ allow: false,
1240
+ riskScore: 100,
1241
+ reasons: [`${CCE_ERROR.CAPSULE_REVOKED}: ${capsule.capsule_id}`],
1242
+ code: CCE_ERROR.CAPSULE_REVOKED
1243
+ };
1244
+ }
1245
+ if (capsule.mode === "SINGLE_USE") {
1246
+ const consumed = await this.replayStore.isCapsuleConsumed(
1247
+ capsule.capsule_id
1248
+ );
1249
+ if (consumed) {
1250
+ return {
1251
+ allow: false,
1252
+ riskScore: 100,
1253
+ reasons: [`${CCE_ERROR.CAPSULE_CONSUMED}: ${capsule.capsule_id}`],
1254
+ code: CCE_ERROR.CAPSULE_CONSUMED
1255
+ };
1256
+ }
1257
+ }
1258
+ const nonceKey = `cce:nonce:${capsule.sub}:${capsule.aud}:${capsule.intent}:${envelope.request_nonce}`;
1259
+ const nonceValid = await this.replayStore.checkAndMark(
1260
+ nonceKey,
1261
+ this.nonceTtlMs
1262
+ );
1263
+ if (!nonceValid) {
1264
+ return {
1265
+ allow: false,
1266
+ riskScore: 100,
1267
+ reasons: [
1268
+ `${CCE_ERROR.NONCE_REUSED}: ${envelope.request_nonce.slice(0, 16)}...`
1269
+ ],
1270
+ code: CCE_ERROR.NONCE_REUSED
1271
+ };
1272
+ }
1273
+ if (capsule.mode === "SINGLE_USE") {
1274
+ const capsuleTtl = (capsule.exp - capsule.iat) * 1e3 + 6e4;
1275
+ await this.replayStore.markCapsuleConsumed(
1276
+ capsule.capsule_id,
1277
+ capsuleTtl
1278
+ );
1279
+ }
1280
+ input.metadata = input.metadata ?? {};
1281
+ input.metadata.cceReplayClean = true;
1282
+ return {
1283
+ decision: "ALLOW" /* ALLOW */,
1284
+ allow: true,
1285
+ riskScore: 0,
1286
+ reasons: []
1287
+ };
1288
+ }
1289
+ };
1290
+
1291
+ // src/cce/sensors/cce-payload-decryption.sensor.ts
1292
+ var CcePayloadDecryptionSensor = class {
1293
+ constructor(keyProvider, aesProvider, maxPayloadBytes = 64 * 1024, payloadValidator) {
1294
+ this.keyProvider = keyProvider;
1295
+ this.aesProvider = aesProvider;
1296
+ this.maxPayloadBytes = maxPayloadBytes;
1297
+ this.payloadValidator = payloadValidator;
1298
+ this.name = "cce.payload.decryption";
1299
+ this.order = 145;
1300
+ this.phase = "POST_DECODE";
1301
+ }
1302
+ supports(input) {
1303
+ return input.metadata?.cceEnvelopeValid === true && input.metadata?.cceClientSigVerified === true && input.metadata?.cceCapsuleVerified === true && input.metadata?.cceReplayClean === true;
1304
+ }
1305
+ async run(input) {
1306
+ const envelope = input.metadata?.cceEnvelope;
1307
+ if (!envelope) {
1308
+ return {
1309
+ allow: false,
1310
+ riskScore: 100,
1311
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
1312
+ code: CCE_ERROR.INVALID_ENVELOPE
1313
+ };
1314
+ }
1315
+ let aesKey;
1316
+ try {
1317
+ aesKey = await this.keyProvider.unwrapKey(
1318
+ envelope.encrypted_key.ciphertext,
1319
+ envelope.encrypted_key.alg,
1320
+ envelope.encrypted_key.axis_kid,
1321
+ envelope.encrypted_key.ephemeral_pk
1322
+ );
1323
+ } catch {
1324
+ return {
1325
+ allow: false,
1326
+ riskScore: 100,
1327
+ reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
1328
+ code: CCE_ERROR.KEY_UNWRAP_FAILED
1329
+ };
1330
+ }
1331
+ if (!aesKey) {
1332
+ return {
1333
+ allow: false,
1334
+ riskScore: 100,
1335
+ reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
1336
+ code: CCE_ERROR.KEY_UNWRAP_FAILED
1337
+ };
1338
+ }
1339
+ let iv;
1340
+ let ciphertext;
1341
+ let tag;
1342
+ try {
1343
+ iv = base64UrlDecode2(envelope.encrypted_payload.iv);
1344
+ ciphertext = base64UrlDecode2(envelope.encrypted_payload.ciphertext);
1345
+ tag = base64UrlDecode2(envelope.encrypted_payload.tag);
1346
+ } catch {
1347
+ return {
1348
+ allow: false,
1349
+ riskScore: 100,
1350
+ reasons: [`${CCE_ERROR.DECRYPTION_FAILED}: invalid base64url encoding`],
1351
+ code: CCE_ERROR.DECRYPTION_FAILED
1352
+ };
1353
+ }
1354
+ if (ciphertext.length > this.maxPayloadBytes) {
1355
+ return {
1356
+ allow: false,
1357
+ riskScore: 100,
1358
+ reasons: [
1359
+ `${CCE_ERROR.PAYLOAD_TOO_LARGE}: ${ciphertext.length} > ${this.maxPayloadBytes}`
1360
+ ],
1361
+ code: CCE_ERROR.PAYLOAD_TOO_LARGE
1362
+ };
1363
+ }
1364
+ const aad = buildAad(envelope);
1365
+ let plaintext;
1366
+ try {
1367
+ plaintext = await this.aesProvider.decrypt(
1368
+ aesKey,
1369
+ iv,
1370
+ ciphertext,
1371
+ tag,
1372
+ aad
1373
+ );
1374
+ } catch {
1375
+ plaintext = null;
1376
+ } finally {
1377
+ aesKey.fill(0);
1378
+ }
1379
+ if (!plaintext) {
1380
+ return {
1381
+ allow: false,
1382
+ riskScore: 100,
1383
+ reasons: [CCE_ERROR.AEAD_TAG_MISMATCH],
1384
+ code: CCE_ERROR.AEAD_TAG_MISMATCH
1385
+ };
1386
+ }
1387
+ const capsule = input.metadata?.cceCapsule;
1388
+ if (capsule && isJsonContentType(envelope.content_type)) {
1389
+ const parsed = tryParseJsonObject(plaintext);
1390
+ if (parsed && typeof parsed.intent === "string") {
1391
+ if (parsed.intent !== capsule.intent) {
1392
+ return {
1393
+ allow: false,
1394
+ riskScore: 100,
1395
+ reasons: [
1396
+ `${CCE_ERROR.INTENT_SCHEMA_MISMATCH}: payload.intent=${parsed.intent}, capsule.intent=${capsule.intent}`
1397
+ ],
1398
+ code: CCE_ERROR.INTENT_SCHEMA_MISMATCH
1399
+ };
1400
+ }
1401
+ input.metadata = input.metadata ?? {};
1402
+ input.metadata.cceRequestIntent = parsed.intent;
1403
+ }
1404
+ }
1405
+ if (this.payloadValidator) {
1406
+ const verdict = await this.payloadValidator.validate(plaintext, envelope);
1407
+ if (!verdict.ok) {
1408
+ const code = verdict.code ?? CCE_ERROR.PAYLOAD_SCHEMA_INVALID;
1409
+ return {
1410
+ allow: false,
1411
+ riskScore: 100,
1412
+ reasons: [verdict.reason ?? code],
1413
+ code
1414
+ };
1415
+ }
1416
+ if (verdict.intent) {
1417
+ input.metadata = input.metadata ?? {};
1418
+ input.metadata.cceRequestIntent = verdict.intent;
1419
+ }
1420
+ }
1421
+ input.metadata = input.metadata ?? {};
1422
+ input.metadata.cceDecryptedPayload = plaintext;
1423
+ input.metadata.cceDecryptionOk = true;
1424
+ return {
1425
+ decision: "ALLOW" /* ALLOW */,
1426
+ allow: true,
1427
+ riskScore: 0,
1428
+ reasons: []
1429
+ };
1430
+ }
1431
+ };
1432
+ function buildAad(envelope) {
1433
+ const parts = [
1434
+ envelope.ver,
1435
+ envelope.request_id,
1436
+ envelope.correlation_id,
1437
+ envelope.client_kid,
1438
+ envelope.capsule.capsule_id,
1439
+ envelope.capsule.intent,
1440
+ envelope.capsule.aud,
1441
+ envelope.request_nonce
1442
+ ];
1443
+ return new TextEncoder().encode(parts.join("|"));
1444
+ }
1445
+ function isJsonContentType(contentType) {
1446
+ return typeof contentType === "string" && contentType.toLowerCase().includes("application/json");
1447
+ }
1448
+ function tryParseJsonObject(payload) {
1449
+ try {
1450
+ const parsed = JSON.parse(new TextDecoder().decode(payload));
1451
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
1452
+ return parsed;
1453
+ }
1454
+ return null;
1455
+ } catch {
1456
+ return null;
1457
+ }
1458
+ }
1459
+ function base64UrlDecode2(input) {
1460
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
1461
+ const padding = "=".repeat((4 - base64.length % 4) % 4);
1462
+ return new Uint8Array(Buffer.from(base64 + padding, "base64"));
1463
+ }
1464
+ // Annotate the CommonJS export names for ESM import in node:
1465
+ 0 && (module.exports = {
1466
+ CCE_AES_KEY_BYTES,
1467
+ CCE_DERIVATION,
1468
+ CCE_ERROR,
1469
+ CCE_IV_BYTES,
1470
+ CCE_NONCE_BYTES,
1471
+ CCE_PROTOCOL_VERSION,
1472
+ CCE_TAG_BYTES,
1473
+ CceAudienceIntentBindingSensor,
1474
+ CceCapsuleVerificationSensor,
1475
+ CceClientSignatureSensor,
1476
+ CceEnvelopeValidationSensor,
1477
+ CceError,
1478
+ CcePayloadDecryptionSensor,
1479
+ CceReplayProtectionSensor,
1480
+ CceTpsWindowSensor,
1481
+ InMemoryCceReplayStore,
1482
+ InMemoryCceWitnessStore,
1483
+ aesGcmDecrypt,
1484
+ aesGcmEncrypt,
1485
+ base64UrlDecode,
1486
+ base64UrlEncode,
1487
+ buildCceErrorResponse,
1488
+ buildCceResponse,
1489
+ buildExecutionContext,
1490
+ buildWitnessRecord,
1491
+ deriveRequestExecutionKey,
1492
+ deriveResponseExecutionKey,
1493
+ deriveWitnessKey,
1494
+ executeCcePipeline,
1495
+ extractVerificationState,
1496
+ generateAesKey,
1497
+ generateCceNonce,
1498
+ generateIv,
1499
+ hashPayload,
1500
+ nodeAesGcmProvider
1501
+ });
1502
+ //# sourceMappingURL=index.js.map