@nextera.one/axis-server-sdk 1.5.0 → 1.7.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.
package/dist/index.mjs CHANGED
@@ -405,6 +405,626 @@ var SensorDecisions = {
405
405
  }
406
406
  };
407
407
 
408
+ // src/cce/cce-derivation.service.ts
409
+ import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
410
+ import { hkdf } from "@noble/hashes/hkdf.js";
411
+ import { sha256 } from "@noble/hashes/sha2.js";
412
+
413
+ // src/cce/cce.types.ts
414
+ var CCE_PROTOCOL_VERSION = "cce-v1";
415
+ var CCE_DERIVATION = {
416
+ /** Request execution context */
417
+ REQUEST: "axis:cce:req:v1",
418
+ /** Response execution context */
419
+ RESPONSE: "axis:cce:resp:v1",
420
+ /** Witness binding context */
421
+ WITNESS: "axis:cce:witness:v1"
422
+ };
423
+ var CCE_AES_KEY_BYTES = 32;
424
+ var CCE_IV_BYTES = 12;
425
+ var CCE_TAG_BYTES = 16;
426
+ var CCE_NONCE_BYTES = 32;
427
+ var CCE_ERROR = {
428
+ // Envelope errors
429
+ INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
430
+ UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
431
+ MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
432
+ MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
433
+ // Signature errors
434
+ CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
435
+ CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
436
+ // Capsule errors
437
+ CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
438
+ CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
439
+ CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
440
+ CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
441
+ CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
442
+ // Binding errors
443
+ AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
444
+ INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
445
+ TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
446
+ TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
447
+ // Replay / nonce errors
448
+ REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
449
+ NONCE_REUSED: "CCE_NONCE_REUSED",
450
+ // Decryption errors
451
+ DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
452
+ KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
453
+ AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
454
+ PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
455
+ // Schema / validation errors
456
+ PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
457
+ INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
458
+ // Policy errors
459
+ POLICY_DENIED: "CCE_POLICY_DENIED",
460
+ CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
461
+ // Handler errors
462
+ HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
463
+ HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
464
+ HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
465
+ // Response errors
466
+ RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
467
+ };
468
+ var CceError = class extends Error {
469
+ constructor(code, message, metadata) {
470
+ super(`[${code}] ${message}`);
471
+ this.code = code;
472
+ this.metadata = metadata;
473
+ this.name = "CceError";
474
+ }
475
+ /** Whether this error is safe to expose to the client */
476
+ get clientSafe() {
477
+ const internal = [
478
+ CCE_ERROR.DECRYPTION_FAILED,
479
+ CCE_ERROR.KEY_UNWRAP_FAILED,
480
+ CCE_ERROR.AEAD_TAG_MISMATCH,
481
+ CCE_ERROR.HANDLER_EXECUTION_FAILED,
482
+ CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
483
+ ];
484
+ return !internal.includes(this.code);
485
+ }
486
+ /** Get client-safe representation */
487
+ toClientError() {
488
+ if (this.clientSafe) {
489
+ return { code: this.code, message: this.message };
490
+ }
491
+ return {
492
+ code: CCE_ERROR.DECRYPTION_FAILED,
493
+ message: "Request processing failed"
494
+ };
495
+ }
496
+ };
497
+
498
+ // src/cce/cce-derivation.service.ts
499
+ function buildSalt(capsuleId, capsuleNonce, requestNonce) {
500
+ const encoder = new TextEncoder();
501
+ const data = encoder.encode(
502
+ capsuleId + "|" + capsuleNonce + "|" + requestNonce
503
+ );
504
+ return sha256(data);
505
+ }
506
+ function buildInfo(contextPrefix, capsule, extraNonce) {
507
+ const encoder = new TextEncoder();
508
+ const parts = [
509
+ contextPrefix,
510
+ capsule.sub,
511
+ capsule.kid,
512
+ capsule.intent,
513
+ capsule.aud,
514
+ String(capsule.tps_from),
515
+ String(capsule.tps_to),
516
+ capsule.policy_hash ?? "",
517
+ capsule.ver
518
+ ];
519
+ if (extraNonce) {
520
+ parts.push(extraNonce);
521
+ }
522
+ return encoder.encode(parts.join("|"));
523
+ }
524
+ function deriveRequestExecutionKey(input) {
525
+ const ikm = hexToBytes(input.axisLocalSecret);
526
+ const salt = buildSalt(
527
+ input.capsule.capsule_id,
528
+ input.capsule.capsule_nonce,
529
+ input.requestNonce
530
+ );
531
+ const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
532
+ return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
533
+ }
534
+ function deriveResponseExecutionKey(input) {
535
+ const ikm = hexToBytes(input.axisLocalSecret);
536
+ const encoder = new TextEncoder();
537
+ const saltData = encoder.encode(
538
+ input.capsule.capsule_id + "|" + input.capsule.capsule_nonce + "|" + input.requestNonce + "|" + input.responseNonce
539
+ );
540
+ const salt = sha256(saltData);
541
+ const info = buildInfo(
542
+ CCE_DERIVATION.RESPONSE,
543
+ input.capsule,
544
+ input.responseNonce
545
+ );
546
+ return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
547
+ }
548
+ function deriveWitnessKey(input) {
549
+ const ikm = hexToBytes(input.axisLocalSecret);
550
+ const salt = buildSalt(
551
+ input.capsule.capsule_id,
552
+ input.capsule.capsule_nonce,
553
+ input.requestNonce
554
+ );
555
+ const info = buildInfo(CCE_DERIVATION.WITNESS, input.capsule);
556
+ return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
557
+ }
558
+ function buildExecutionContext(input, requestId) {
559
+ const executionKey = deriveRequestExecutionKey(input);
560
+ const keyHash = bytesToHex(sha256(executionKey));
561
+ executionKey.fill(0);
562
+ return {
563
+ execution_key_hash: keyHash,
564
+ request_id: requestId,
565
+ capsule_id: input.capsule.capsule_id,
566
+ sub: input.capsule.sub,
567
+ kid: input.capsule.kid,
568
+ intent: input.capsule.intent,
569
+ aud: input.capsule.aud,
570
+ tps_from: input.capsule.tps_from,
571
+ tps_to: input.capsule.tps_to,
572
+ policy_hash: input.capsule.policy_hash,
573
+ derived_at: Math.floor(Date.now() / 1e3),
574
+ valid: true
575
+ };
576
+ }
577
+ function generateCceNonce() {
578
+ const bytes2 = new Uint8Array(CCE_NONCE_BYTES);
579
+ crypto.getRandomValues(bytes2);
580
+ return bytesToHex(bytes2);
581
+ }
582
+
583
+ // src/cce/cce-response.service.ts
584
+ import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils.js";
585
+ import { randomBytes as randomBytes2 } from "crypto";
586
+
587
+ // src/cce/cce-crypto.ts
588
+ import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
589
+ import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
590
+ import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
591
+ function aesGcmEncrypt(key, plaintext, aad) {
592
+ if (key.length !== CCE_AES_KEY_BYTES) {
593
+ throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
594
+ }
595
+ const iv = randomBytes(CCE_IV_BYTES);
596
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
597
+ if (aad) {
598
+ cipher.setAAD(aad);
599
+ }
600
+ const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
601
+ const tag = cipher.getAuthTag();
602
+ return {
603
+ iv: new Uint8Array(iv),
604
+ ciphertext: new Uint8Array(encrypted),
605
+ tag: new Uint8Array(tag)
606
+ };
607
+ }
608
+ function aesGcmDecrypt(key, iv, ciphertext, tag, aad) {
609
+ if (key.length !== CCE_AES_KEY_BYTES) {
610
+ throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
611
+ }
612
+ if (iv.length !== CCE_IV_BYTES) {
613
+ throw new Error(`IV must be ${CCE_IV_BYTES} bytes`);
614
+ }
615
+ if (tag.length !== CCE_TAG_BYTES) {
616
+ throw new Error(`Tag must be ${CCE_TAG_BYTES} bytes`);
617
+ }
618
+ try {
619
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
620
+ decipher.setAuthTag(tag);
621
+ if (aad) {
622
+ decipher.setAAD(aad);
623
+ }
624
+ const decrypted = Buffer.concat([
625
+ decipher.update(ciphertext),
626
+ decipher.final()
627
+ ]);
628
+ return new Uint8Array(decrypted);
629
+ } catch {
630
+ return null;
631
+ }
632
+ }
633
+ function generateAesKey() {
634
+ return new Uint8Array(randomBytes(CCE_AES_KEY_BYTES));
635
+ }
636
+ function generateIv() {
637
+ return new Uint8Array(randomBytes(CCE_IV_BYTES));
638
+ }
639
+ function base64UrlEncode(bytes2) {
640
+ return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
641
+ }
642
+ function base64UrlDecode(input) {
643
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
644
+ const padding = "=".repeat((4 - base64.length % 4) % 4);
645
+ return new Uint8Array(Buffer.from(base64 + padding, "base64"));
646
+ }
647
+ function hashPayload(payload) {
648
+ return bytesToHex2(sha2562(payload));
649
+ }
650
+ var nodeAesGcmProvider = {
651
+ async decrypt(key, iv, ciphertext, tag, aad) {
652
+ return aesGcmDecrypt(key, iv, ciphertext, tag, aad);
653
+ }
654
+ };
655
+
656
+ // src/cce/cce-response.service.ts
657
+ async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
658
+ const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
659
+ const responseNonce = bytesToHex3(
660
+ new Uint8Array(randomBytes2(CCE_NONCE_BYTES))
661
+ );
662
+ const responseId = generateResponseId();
663
+ const aesKey = generateAesKey();
664
+ const aad = buildResponseAad(
665
+ request.request_id,
666
+ responseId,
667
+ request.correlation_id,
668
+ capsule.capsule_id,
669
+ responseNonce
670
+ );
671
+ const { iv, ciphertext, tag } = aesGcmEncrypt(aesKey, body, aad);
672
+ const encryptedKey = await clientKeyEncryptor.wrapKey(
673
+ aesKey,
674
+ request.client_kid,
675
+ clientPublicKeyHex
676
+ );
677
+ aesKey.fill(0);
678
+ const encryptedPayload = {
679
+ alg: "AES-256-GCM",
680
+ iv: base64UrlEncode(iv),
681
+ ciphertext: base64UrlEncode(ciphertext),
682
+ tag: base64UrlEncode(tag)
683
+ };
684
+ const algorithms = {
685
+ kem: encryptedKey.alg,
686
+ enc: "AES-256-GCM",
687
+ kdf: "HKDF-SHA256",
688
+ sig: "EdDSA"
689
+ };
690
+ const unsignedResponse = {
691
+ ver: CCE_PROTOCOL_VERSION,
692
+ response_id: responseId,
693
+ request_id: request.request_id,
694
+ correlation_id: request.correlation_id,
695
+ encrypted_key: encryptedKey,
696
+ encrypted_payload: encryptedPayload,
697
+ response_nonce: responseNonce,
698
+ algorithms,
699
+ status,
700
+ ...witnessRef ? { witness_ref: witnessRef } : {}
701
+ };
702
+ const signPayload = new TextEncoder().encode(canonicalize(unsignedResponse));
703
+ const axisSig = await axisSigner.sign(signPayload);
704
+ const envelope = {
705
+ ...unsignedResponse,
706
+ axis_sig: axisSig
707
+ };
708
+ return {
709
+ envelope,
710
+ responsePayloadHash: hashPayload(body)
711
+ };
712
+ }
713
+ function buildCceErrorResponse(requestId, correlationId, status, errorCode, message) {
714
+ return {
715
+ ver: CCE_PROTOCOL_VERSION,
716
+ request_id: requestId,
717
+ correlation_id: correlationId,
718
+ status,
719
+ error: { code: errorCode, message }
720
+ };
721
+ }
722
+ function generateResponseId() {
723
+ const bytes2 = randomBytes2(16);
724
+ return "resp_" + bytesToHex3(new Uint8Array(bytes2)).slice(0, 24);
725
+ }
726
+ function buildResponseAad(requestId, responseId, correlationId, capsuleId, responseNonce) {
727
+ const parts = [
728
+ requestId,
729
+ responseId,
730
+ correlationId,
731
+ capsuleId,
732
+ responseNonce
733
+ ];
734
+ return new TextEncoder().encode(parts.join("|"));
735
+ }
736
+ function canonicalize(obj) {
737
+ if (Array.isArray(obj)) {
738
+ return "[" + obj.map(canonicalize).join(",") + "]";
739
+ }
740
+ if (obj !== null && typeof obj === "object") {
741
+ const sorted = Object.keys(obj).sort().map(
742
+ (k) => JSON.stringify(k) + ":" + canonicalize(obj[k])
743
+ );
744
+ return "{" + sorted.join(",") + "}";
745
+ }
746
+ return JSON.stringify(obj);
747
+ }
748
+
749
+ // src/cce/cce-witness.observer.ts
750
+ import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils.js";
751
+ import { hkdf as hkdf2 } from "@noble/hashes/hkdf.js";
752
+ import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
753
+ var InMemoryCceWitnessStore = class {
754
+ constructor() {
755
+ this.records = [];
756
+ }
757
+ async record(witness) {
758
+ this.records.push(witness);
759
+ }
760
+ getByRequestId(requestId) {
761
+ return this.records.find((w) => w.request_id === requestId);
762
+ }
763
+ getByCapsuleId(capsuleId) {
764
+ return this.records.filter((w) => w.capsule_id === capsuleId);
765
+ }
766
+ };
767
+ function buildWitnessRecord(envelope, capsule, verification, execution, options) {
768
+ const witnessId = generateWitnessId(envelope.request_id, capsule.capsule_id);
769
+ const executionContextHash = computeExecutionContextHash(
770
+ options.axisLocalSecret,
771
+ capsule,
772
+ envelope.request_nonce
773
+ );
774
+ return {
775
+ witness_id: witnessId,
776
+ request_id: envelope.request_id,
777
+ capsule_id: capsule.capsule_id,
778
+ sub: capsule.sub,
779
+ intent: capsule.intent,
780
+ aud: capsule.aud,
781
+ tps_from: capsule.tps_from,
782
+ tps_to: capsule.tps_to,
783
+ timestamp: Math.floor(Date.now() / 1e3),
784
+ verification: {
785
+ client_sig: verification.clientSigVerified,
786
+ capsule_sig: verification.capsuleSigVerified,
787
+ tps_valid: verification.tpsValid,
788
+ audience_match: verification.audienceMatch,
789
+ intent_match: verification.intentMatch,
790
+ replay_clean: verification.replayClean,
791
+ nonce_unique: verification.nonceUnique,
792
+ decryption_ok: verification.decryptionOk
793
+ },
794
+ execution: {
795
+ status: execution.status,
796
+ handler_duration_ms: execution.handlerDurationMs,
797
+ ...execution.effect ? { effect: execution.effect } : {}
798
+ },
799
+ response_encrypted: options.responseEncrypted,
800
+ execution_context_hash: executionContextHash,
801
+ ...options.requestPayload ? { request_payload_hash: hashPayload(options.requestPayload) } : {},
802
+ ...options.responsePayload ? { response_payload_hash: hashPayload(options.responsePayload) } : {}
803
+ };
804
+ }
805
+ function extractVerificationState(metadata) {
806
+ return {
807
+ clientSigVerified: metadata.cceClientSigVerified === true,
808
+ capsuleSigVerified: metadata.cceCapsuleVerified === true,
809
+ tpsValid: metadata.cceTpsValid === true,
810
+ audienceMatch: metadata.cceBindingVerified === true,
811
+ intentMatch: metadata.cceBindingVerified === true,
812
+ replayClean: metadata.cceReplayClean === true,
813
+ nonceUnique: metadata.cceReplayClean === true,
814
+ decryptionOk: metadata.cceDecryptionOk === true
815
+ };
816
+ }
817
+ function generateWitnessId(requestId, capsuleId) {
818
+ const input = `witness:${requestId}:${capsuleId}:${Date.now()}`;
819
+ const hash = sha2563(new TextEncoder().encode(input));
820
+ return "wit_" + bytesToHex4(hash).slice(0, 24);
821
+ }
822
+ function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
823
+ const encoder = new TextEncoder();
824
+ const ikm = hexToBytes2(axisLocalSecret);
825
+ const salt = sha2563(
826
+ encoder.encode(
827
+ capsule.capsule_id + "|" + capsule.capsule_nonce + "|" + requestNonce
828
+ )
829
+ );
830
+ const info = encoder.encode(
831
+ [
832
+ CCE_DERIVATION.WITNESS,
833
+ capsule.sub,
834
+ capsule.kid,
835
+ capsule.intent,
836
+ capsule.aud,
837
+ String(capsule.tps_from),
838
+ String(capsule.tps_to),
839
+ capsule.policy_hash ?? "",
840
+ capsule.ver
841
+ ].join("|")
842
+ );
843
+ const witnessKey = hkdf2(sha2563, ikm, salt, info, 32);
844
+ const hash = bytesToHex4(sha2563(witnessKey));
845
+ witnessKey.fill(0);
846
+ return hash;
847
+ }
848
+ function hexToBytes2(hex) {
849
+ const bytes2 = new Uint8Array(hex.length / 2);
850
+ for (let i = 0; i < bytes2.length; i++) {
851
+ bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
852
+ }
853
+ return bytes2;
854
+ }
855
+
856
+ // src/cce/cce-pipeline.ts
857
+ async function executeCcePipeline(envelope, config) {
858
+ const startTime = Date.now();
859
+ if (envelope.ver !== CCE_PROTOCOL_VERSION) {
860
+ return {
861
+ ok: false,
862
+ error: {
863
+ code: CCE_ERROR.UNSUPPORTED_VERSION,
864
+ message: `Unsupported version: ${envelope.ver}`
865
+ },
866
+ status: "ERROR"
867
+ };
868
+ }
869
+ const sensorInput = {
870
+ intent: envelope.capsule.intent,
871
+ metadata: {
872
+ cce: true,
873
+ cceEnvelope: envelope,
874
+ contentType: "application/axis-cce"
875
+ }
876
+ };
877
+ const sortedSensors = [...config.sensors].sort(
878
+ (a, b) => (a.order ?? 999) - (b.order ?? 999)
879
+ );
880
+ for (const sensor of sortedSensors) {
881
+ if (sensor.supports && !sensor.supports(sensorInput)) {
882
+ continue;
883
+ }
884
+ let decision;
885
+ try {
886
+ decision = await sensor.run(sensorInput);
887
+ } catch (err) {
888
+ return {
889
+ ok: false,
890
+ error: {
891
+ code: CCE_ERROR.DECRYPTION_FAILED,
892
+ message: `Sensor ${sensor.name} failed`
893
+ },
894
+ status: "ERROR"
895
+ };
896
+ }
897
+ const normalized = normalizeSensorDecision(decision);
898
+ if (!normalized.allow) {
899
+ const code = normalized.reasons[0]?.split(":")[0] ?? CCE_ERROR.DECRYPTION_FAILED;
900
+ return {
901
+ ok: false,
902
+ error: { code, message: normalized.reasons.join("; ") },
903
+ status: "DENIED"
904
+ };
905
+ }
906
+ }
907
+ const capsule = sensorInput.metadata?.cceCapsule;
908
+ const decryptedPayload = sensorInput.metadata?.cceDecryptedPayload;
909
+ const clientKey = sensorInput.metadata?.cceClientKey;
910
+ if (!capsule || !decryptedPayload || !clientKey) {
911
+ return {
912
+ ok: false,
913
+ error: {
914
+ code: CCE_ERROR.DECRYPTION_FAILED,
915
+ message: "Sensor chain did not produce required outputs"
916
+ },
917
+ status: "ERROR"
918
+ };
919
+ }
920
+ const derivationInput = {
921
+ axisLocalSecret: config.axisLocalSecret,
922
+ capsule,
923
+ requestNonce: envelope.request_nonce
924
+ };
925
+ const executionContext = buildExecutionContext(
926
+ derivationInput,
927
+ envelope.request_id
928
+ );
929
+ const handler = config.handlers.get(capsule.intent);
930
+ if (!handler) {
931
+ return {
932
+ ok: false,
933
+ error: {
934
+ code: CCE_ERROR.HANDLER_NOT_FOUND,
935
+ message: `No handler for intent: ${capsule.intent}`
936
+ },
937
+ status: "ERROR"
938
+ };
939
+ }
940
+ const handlerContext = {
941
+ capsule,
942
+ executionContext,
943
+ envelope,
944
+ clientPublicKeyHex: clientKey.publicKeyHex,
945
+ intent: capsule.intent,
946
+ sub: capsule.sub
947
+ };
948
+ let result;
949
+ const handlerStart = Date.now();
950
+ try {
951
+ result = await handler(decryptedPayload, handlerContext);
952
+ } catch (err) {
953
+ const handlerDuration2 = Date.now() - handlerStart;
954
+ const verification2 = extractVerificationState(sensorInput.metadata ?? {});
955
+ const witness2 = buildWitnessRecord(
956
+ envelope,
957
+ capsule,
958
+ verification2,
959
+ { status: "FAILED", handlerDurationMs: handlerDuration2 },
960
+ {
961
+ axisLocalSecret: config.axisLocalSecret,
962
+ requestPayload: decryptedPayload,
963
+ responseEncrypted: false
964
+ }
965
+ );
966
+ await config.witnessStore.record(witness2);
967
+ return {
968
+ ok: false,
969
+ error: {
970
+ code: CCE_ERROR.HANDLER_EXECUTION_FAILED,
971
+ message: "Handler execution failed"
972
+ },
973
+ status: "FAILED"
974
+ };
975
+ }
976
+ const handlerDuration = Date.now() - handlerStart;
977
+ let responseEnvelope;
978
+ let responsePayloadHash;
979
+ try {
980
+ const responseResult = await buildCceResponse(
981
+ {
982
+ request: envelope,
983
+ capsule,
984
+ status: result.status,
985
+ body: result.body,
986
+ clientPublicKeyHex: clientKey.publicKeyHex
987
+ },
988
+ config.clientKeyEncryptor,
989
+ config.axisSigner
990
+ );
991
+ responseEnvelope = responseResult.envelope;
992
+ responsePayloadHash = responseResult.responsePayloadHash;
993
+ } catch (err) {
994
+ return {
995
+ ok: false,
996
+ error: {
997
+ code: CCE_ERROR.RESPONSE_ENCRYPTION_FAILED,
998
+ message: "Response encryption failed"
999
+ },
1000
+ status: "ERROR"
1001
+ };
1002
+ }
1003
+ const verification = extractVerificationState(sensorInput.metadata ?? {});
1004
+ const witness = buildWitnessRecord(
1005
+ envelope,
1006
+ capsule,
1007
+ verification,
1008
+ {
1009
+ status: result.status,
1010
+ handlerDurationMs: handlerDuration,
1011
+ effect: result.effect
1012
+ },
1013
+ {
1014
+ axisLocalSecret: config.axisLocalSecret,
1015
+ requestPayload: decryptedPayload,
1016
+ responsePayload: result.body,
1017
+ responseEncrypted: true
1018
+ }
1019
+ );
1020
+ await config.witnessStore.record(witness);
1021
+ return {
1022
+ ok: true,
1023
+ response: responseEnvelope,
1024
+ witnessId: witness.witness_id
1025
+ };
1026
+ }
1027
+
408
1028
  // src/engine/intent.router.ts
409
1029
  var IntentRouter = class {
410
1030
  constructor(moduleRef) {
@@ -422,6 +1042,10 @@ var IntentRouter = class {
422
1042
  this.intentValidators = /* @__PURE__ */ new Map();
423
1043
  /** Per-intent operation kind */
424
1044
  this.intentKinds = /* @__PURE__ */ new Map();
1045
+ /** CCE handler registry */
1046
+ this.cceHandlers = /* @__PURE__ */ new Map();
1047
+ /** CCE pipeline configuration (set via configureCce) */
1048
+ this.ccePipelineConfig = null;
425
1049
  }
426
1050
  getSchema(intent) {
427
1051
  return this.intentSchemas.get(intent);
@@ -685,6 +1309,58 @@ var IntentRouter = class {
685
1309
  }
686
1310
  }
687
1311
  }
1312
+ // ===========================================================================
1313
+ // CCE — Capsule-Carried Encryption Support
1314
+ // ===========================================================================
1315
+ /**
1316
+ * Configure the CCE pipeline.
1317
+ * Must be called before routeCce() can process encrypted requests.
1318
+ */
1319
+ configureCce(config) {
1320
+ this.ccePipelineConfig = config;
1321
+ this.logger.log("CCE pipeline configured");
1322
+ }
1323
+ /**
1324
+ * Register a CCE-encrypted intent handler.
1325
+ * CCE handlers receive decrypted payloads and execution context.
1326
+ */
1327
+ registerCceHandler(intent, handler) {
1328
+ this.cceHandlers.set(intent, handler);
1329
+ this.logger.debug(`CCE handler registered: ${intent}`);
1330
+ }
1331
+ /**
1332
+ * Check if a CCE handler exists for the given intent.
1333
+ */
1334
+ hasCceHandler(intent) {
1335
+ return this.cceHandlers.has(intent);
1336
+ }
1337
+ /**
1338
+ * Route a CCE-encrypted request through the full pipeline.
1339
+ *
1340
+ * Steps:
1341
+ * 1. Sensor chain (envelope validation → capsule verification → replay → decrypt)
1342
+ * 2. Execution context derivation
1343
+ * 3. Handler execution
1344
+ * 4. Response encryption
1345
+ * 5. Witness recording
1346
+ */
1347
+ async routeCce(envelope) {
1348
+ if (!this.ccePipelineConfig) {
1349
+ return {
1350
+ ok: false,
1351
+ error: {
1352
+ code: "CCE_NOT_CONFIGURED",
1353
+ message: "CCE pipeline not configured. Call configureCce() first."
1354
+ },
1355
+ status: "ERROR"
1356
+ };
1357
+ }
1358
+ const config = {
1359
+ ...this.ccePipelineConfig,
1360
+ handlers: this.cceHandlers
1361
+ };
1362
+ return executeCcePipeline(envelope, config);
1363
+ }
688
1364
  storeSchema(meta) {
689
1365
  if (meta.dto) {
690
1366
  if (meta.tlv && meta.tlv.length > 0) {
@@ -1039,7 +1715,7 @@ function verifyResponse(ctx, response) {
1039
1715
  import { encodeVarint, decodeVarint, varintLength } from "@nextera.one/axis-protocol";
1040
1716
 
1041
1717
  // src/core/signature.ts
1042
- import * as crypto from "crypto";
1718
+ import * as crypto2 from "crypto";
1043
1719
 
1044
1720
  // src/core/axis-bin.ts
1045
1721
  import * as z from "zod";
@@ -1169,19 +1845,19 @@ function signFrame(frame, privateKey) {
1169
1845
  32
1170
1846
  ]);
1171
1847
  const pkcs8Key = Buffer.concat([pkcs8Prefix, privateKey]);
1172
- keyObject = crypto.createPrivateKey({
1848
+ keyObject = crypto2.createPrivateKey({
1173
1849
  key: pkcs8Key,
1174
1850
  format: "der",
1175
1851
  type: "pkcs8"
1176
1852
  });
1177
1853
  } else {
1178
- keyObject = crypto.createPrivateKey({
1854
+ keyObject = crypto2.createPrivateKey({
1179
1855
  key: privateKey,
1180
1856
  format: "der",
1181
1857
  type: "pkcs8"
1182
1858
  });
1183
1859
  }
1184
- const signature = crypto.sign(null, payload, keyObject);
1860
+ const signature = crypto2.sign(null, payload, keyObject);
1185
1861
  if (signature.length !== 64) {
1186
1862
  throw new Error("Ed25519 signature must be 64 bytes");
1187
1863
  }
@@ -1213,19 +1889,19 @@ function verifyFrameSignature(frame, publicKey) {
1213
1889
  0
1214
1890
  ]);
1215
1891
  const spkiKey = Buffer.concat([spkiPrefix, publicKey]);
1216
- keyObject = crypto.createPublicKey({
1892
+ keyObject = crypto2.createPublicKey({
1217
1893
  key: spkiKey,
1218
1894
  format: "der",
1219
1895
  type: "spki"
1220
1896
  });
1221
1897
  } else {
1222
- keyObject = crypto.createPublicKey({
1898
+ keyObject = crypto2.createPublicKey({
1223
1899
  key: publicKey,
1224
1900
  format: "der",
1225
1901
  type: "spki"
1226
1902
  });
1227
1903
  }
1228
- const valid = crypto.verify(
1904
+ const valid = crypto2.verify(
1229
1905
  null,
1230
1906
  payload,
1231
1907
  keyObject,
@@ -1237,17 +1913,17 @@ function verifyFrameSignature(frame, publicKey) {
1237
1913
  }
1238
1914
  }
1239
1915
  function generateEd25519KeyPair() {
1240
- const { privateKey, publicKey } = crypto.generateKeyPairSync("ed25519");
1916
+ const { privateKey, publicKey } = crypto2.generateKeyPairSync("ed25519");
1241
1917
  return {
1242
1918
  privateKey: privateKey.export({ type: "pkcs8", format: "der" }),
1243
1919
  publicKey: publicKey.export({ type: "spki", format: "der" })
1244
1920
  };
1245
1921
  }
1246
- function sha256(data) {
1247
- return crypto.createHash("sha256").update(data).digest();
1922
+ function sha2564(data) {
1923
+ return crypto2.createHash("sha256").update(data).digest();
1248
1924
  }
1249
1925
  function computeReceiptHash(receiptBytes, prevHash) {
1250
- const hasher = crypto.createHash("sha256");
1926
+ const hasher = crypto2.createHash("sha256");
1251
1927
  hasher.update(receiptBytes);
1252
1928
  if (prevHash && prevHash.length > 0) {
1253
1929
  hasher.update(prevHash);
@@ -1305,7 +1981,7 @@ __export(ats1_exports, {
1305
1981
  encodeU64BE: () => encodeU64BE,
1306
1982
  encodeUVarint: () => encodeUVarint,
1307
1983
  logicalBodyToTLVs: () => logicalBodyToTLVs,
1308
- sha256: () => sha2562,
1984
+ sha256: () => sha2565,
1309
1985
  tlvsToLogicalBody: () => tlvsToLogicalBody,
1310
1986
  tlvsToMap: () => tlvsToMap,
1311
1987
  validateTLVsAgainstSchema: () => validateTLVsAgainstSchema
@@ -1359,7 +2035,7 @@ function decodeU64BE(buf) {
1359
2035
  if (buf.length !== 8) throw new Error("decodeU64BE: length must be 8");
1360
2036
  return buf.readBigUInt64BE(0);
1361
2037
  }
1362
- function sha2562(data) {
2038
+ function sha2565(data) {
1363
2039
  return createHash3("sha256").update(data).digest();
1364
2040
  }
1365
2041
  function encodeTLV(tag, value) {
@@ -1676,7 +2352,7 @@ function decodeAxisHeaderFromTLVs(hdrTlvs, limits = DEFAULT_LIMITS) {
1676
2352
  function encodeAxisRequestBinary(schema, req, limits = DEFAULT_LIMITS) {
1677
2353
  const bodyTlvs = logicalBodyToTLVs(schema, req.body, limits);
1678
2354
  const bodyBytes = encodeTLVStreamCanonical(bodyTlvs);
1679
- const bodyHash = sha2562(bodyBytes);
2355
+ const bodyHash = sha2565(bodyBytes);
1680
2356
  const hdr = {
1681
2357
  ...req.hdr,
1682
2358
  schemaId: schema.schemaId,
@@ -1692,7 +2368,7 @@ function decodeAxisRequestBinary(schema, hdrBytes, bodyBytes, limits = DEFAULT_L
1692
2368
  const hdr = decodeAxisHeaderFromTLVs(hdrTlvs, limits);
1693
2369
  if (hdr.schemaId !== schema.schemaId)
1694
2370
  throw new Error("decodeAxisRequestBinary: schemaId mismatch");
1695
- const bh = sha2562(bodyBytes);
2371
+ const bh = sha2565(bodyBytes);
1696
2372
  if (!Buffer.from(hdr.bodyHash).equals(bh))
1697
2373
  throw new Error("decodeAxisRequestBinary: body_hash mismatch");
1698
2374
  const body = tlvsToLogicalBody(schema, bodyTlvs, limits);
@@ -1765,7 +2441,7 @@ function packPasskeyLoginOptionsReq(params) {
1765
2441
  }
1766
2442
  );
1767
2443
  const body = encodeTLVStreamCanonical(bodyTlvs);
1768
- const bodyHash = sha2562(body);
2444
+ const bodyHash = sha2565(body);
1769
2445
  const hdr = buildAts1Hdr({
1770
2446
  intentId: params.intentId,
1771
2447
  schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_OPTIONS_REQ,
@@ -1834,7 +2510,7 @@ function packPasskeyRegisterOptionsReq(params) {
1834
2510
  }
1835
2511
  );
1836
2512
  const body = encodeTLVStreamCanonical(bodyTlvs);
1837
- const bodyHash = sha2562(body);
2513
+ const bodyHash = sha2565(body);
1838
2514
  const hdr = buildAts1Hdr({
1839
2515
  intentId: params.intentId,
1840
2516
  schemaId: ATS1_SCHEMA.PASSKEY_REGISTER_OPTIONS_REQ,
@@ -1865,7 +2541,7 @@ function packPasskeyLoginVerifyReq(params) {
1865
2541
  }
1866
2542
  });
1867
2543
  const body = encodeTLVStreamCanonical(bodyTlvs);
1868
- const bodyHash = sha2562(body);
2544
+ const bodyHash = sha2565(body);
1869
2545
  const hdr = buildAts1Hdr({
1870
2546
  intentId: params.intentId,
1871
2547
  schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_VERIFY_REQ,
@@ -1949,7 +2625,7 @@ function packPasskeyLoginVerifyRes(params) {
1949
2625
  }
1950
2626
 
1951
2627
  // src/codec/tlv.encode.ts
1952
- import { randomBytes as randomBytes2 } from "crypto";
2628
+ import { randomBytes as randomBytes4 } from "crypto";
1953
2629
  function encVarint(x) {
1954
2630
  if (x < 0n) throw new Error("VARINT_NEG");
1955
2631
  const out = [];
@@ -1977,7 +2653,7 @@ function bytes(b) {
1977
2653
  return Buffer.isBuffer(b) ? b : Buffer.from(b);
1978
2654
  }
1979
2655
  function nonce16() {
1980
- return randomBytes2(16);
2656
+ return randomBytes4(16);
1981
2657
  }
1982
2658
  function tlv(type, value) {
1983
2659
  if (!Number.isSafeInteger(type) || type < 0) throw new Error("TLV_BAD_TYPE");
@@ -2705,7 +3381,7 @@ function isTimestampValid(ts, skewSeconds = 120) {
2705
3381
 
2706
3382
  // src/upload/axis-files.handlers.ts
2707
3383
  import { Inject, Injectable as Injectable3, Logger as Logger2, Optional as Optional2 } from "@nestjs/common";
2708
- import * as crypto2 from "crypto";
3384
+ import * as crypto3 from "crypto";
2709
3385
 
2710
3386
  // src/upload/upload.tokens.ts
2711
3387
  var AXIS_UPLOAD_SESSION_STORE = "AXIS_UPLOAD_SESSION_STORE";
@@ -2806,7 +3482,7 @@ var AxisFilesFinalizeHandler = class {
2806
3482
  if (!await this.files.hasTemp(fileId)) {
2807
3483
  throw new Error("CHUNKS_NOT_FOUND");
2808
3484
  }
2809
- const hash = crypto2.createHash("sha256");
3485
+ const hash = crypto3.createHash("sha256");
2810
3486
  const rs = this.files.createTempReadStream(fileId);
2811
3487
  for await (const chunk of rs) {
2812
3488
  hash.update(chunk);
@@ -3226,10 +3902,10 @@ SensorRegistry = __decorateClass([
3226
3902
  ], SensorRegistry);
3227
3903
 
3228
3904
  // src/engine/axis-observation.ts
3229
- import { randomBytes as randomBytes3 } from "crypto";
3905
+ import { randomBytes as randomBytes5 } from "crypto";
3230
3906
  function createObservation(transport, ip) {
3231
3907
  return {
3232
- id: randomBytes3(16).toString("hex"),
3908
+ id: randomBytes5(16).toString("hex"),
3233
3909
  startMs: Date.now(),
3234
3910
  transport,
3235
3911
  ip,
@@ -3387,100 +4063,869 @@ AxisSensorChainService = __decorateClass([
3387
4063
  Injectable7()
3388
4064
  ], AxisSensorChainService);
3389
4065
 
3390
- // src/core/index.ts
3391
- var core_exports = {};
3392
- __export(core_exports, {
3393
- AXIS_MAGIC: () => AXIS_MAGIC,
3394
- AXIS_VERSION: () => AXIS_VERSION,
3395
- AxisError: () => AxisError,
3396
- AxisFrameZ: () => AxisFrameZ,
3397
- BodyProfile: () => BodyProfile,
3398
- ERR_BAD_SIGNATURE: () => ERR_BAD_SIGNATURE,
3399
- ERR_CONTRACT_VIOLATION: () => ERR_CONTRACT_VIOLATION,
3400
- ERR_INVALID_PACKET: () => ERR_INVALID_PACKET,
3401
- ERR_REPLAY_DETECTED: () => ERR_REPLAY_DETECTED,
3402
- FLAG_BODY_TLV: () => FLAG_BODY_TLV,
3403
- FLAG_CHAIN_REQ: () => FLAG_CHAIN_REQ,
3404
- FLAG_HAS_WITNESS: () => FLAG_HAS_WITNESS,
3405
- MAX_BODY_LEN: () => MAX_BODY_LEN,
3406
- MAX_FRAME_LEN: () => MAX_FRAME_LEN,
3407
- MAX_HDR_LEN: () => MAX_HDR_LEN,
3408
- MAX_SIG_LEN: () => MAX_SIG_LEN,
3409
- NCERT_ALG: () => NCERT_ALG,
3410
- NCERT_EXP: () => NCERT_EXP,
3411
- NCERT_ISSUER_KID: () => NCERT_ISSUER_KID,
3412
- NCERT_KID: () => NCERT_KID,
3413
- NCERT_NBF: () => NCERT_NBF,
3414
- NCERT_NODE_ID: () => NCERT_NODE_ID,
3415
- NCERT_PAYLOAD: () => NCERT_PAYLOAD,
3416
- NCERT_PUB: () => NCERT_PUB,
3417
- NCERT_SCOPE: () => NCERT_SCOPE,
3418
- NCERT_SIG: () => NCERT_SIG,
3419
- PROOF_CAPSULE: () => PROOF_CAPSULE,
3420
- PROOF_JWT: () => PROOF_JWT,
3421
- PROOF_LOOM: () => PROOF_LOOM,
3422
- PROOF_MTLS: () => PROOF_MTLS,
3423
- PROOF_NONE: () => PROOF_NONE,
3424
- PROOF_WITNESS: () => PROOF_WITNESS,
3425
- ProofType: () => ProofType,
3426
- TLV: () => TLV,
3427
- TLV_ACTOR_ID: () => TLV_ACTOR_ID,
3428
- TLV_AUD: () => TLV_AUD,
3429
- TLV_BODY_ARR: () => TLV_BODY_ARR,
3430
- TLV_BODY_OBJ: () => TLV_BODY_OBJ,
3431
- TLV_CAPSULE: () => TLV_CAPSULE,
3432
- TLV_EFFECT: () => TLV_EFFECT,
3433
- TLV_ERROR_CODE: () => TLV_ERROR_CODE,
3434
- TLV_ERROR_MSG: () => TLV_ERROR_MSG,
3435
- TLV_INDEX: () => TLV_INDEX,
3436
- TLV_INTENT: () => TLV_INTENT,
3437
- TLV_KID: () => TLV_KID,
3438
- TLV_LOOM_PRESENCE_ID: () => TLV_LOOM_PRESENCE_ID,
3439
- TLV_LOOM_THREAD_HASH: () => TLV_LOOM_THREAD_HASH,
3440
- TLV_LOOM_WRIT: () => TLV_LOOM_WRIT,
3441
- TLV_NODE: () => TLV_NODE,
3442
- TLV_NODE_CERT_HASH: () => TLV_NODE_CERT_HASH,
3443
- TLV_NODE_KID: () => TLV_NODE_KID,
3444
- TLV_NONCE: () => TLV_NONCE,
3445
- TLV_OFFSET: () => TLV_OFFSET,
3446
- TLV_OK: () => TLV_OK,
3447
- TLV_PID: () => TLV_PID,
3448
- TLV_PREV_HASH: () => TLV_PREV_HASH,
3449
- TLV_PROOF_REF: () => TLV_PROOF_REF,
3450
- TLV_PROOF_TYPE: () => TLV_PROOF_TYPE,
3451
- TLV_REALM: () => TLV_REALM,
3452
- TLV_RECEIPT_HASH: () => TLV_RECEIPT_HASH,
3453
- TLV_RID: () => TLV_RID,
3454
- TLV_SHA256_CHUNK: () => TLV_SHA256_CHUNK,
3455
- TLV_TRACE_ID: () => TLV_TRACE_ID,
3456
- TLV_TS: () => TLV_TS,
3457
- TLV_UPLOAD_ID: () => TLV_UPLOAD_ID,
3458
- computeReceiptHash: () => computeReceiptHash,
3459
- computeSignaturePayload: () => computeSignaturePayload,
3460
- decodeArray: () => decodeArray,
3461
- decodeFrame: () => decodeFrame,
3462
- decodeObject: () => decodeObject,
3463
- decodeTLVs: () => decodeTLVs,
3464
- decodeTLVsList: () => decodeTLVsList,
3465
- decodeVarint: () => decodeVarint,
3466
- encodeFrame: () => encodeFrame,
3467
- encodeTLVs: () => encodeTLVs,
3468
- encodeVarint: () => encodeVarint,
3469
- generateEd25519KeyPair: () => generateEd25519KeyPair,
3470
- getSignTarget: () => getSignTarget,
3471
- sha256: () => sha256,
3472
- signFrame: () => signFrame,
3473
- varintLength: () => varintLength,
3474
- verifyFrameSignature: () => verifyFrameSignature
3475
- });
3476
-
3477
- // src/crypto/index.ts
3478
- var crypto_exports = {};
3479
- __export(crypto_exports, {
3480
- ProofVerificationService: () => ProofVerificationService,
3481
- b64urlDecode: () => b64urlDecode,
3482
- b64urlDecodeString: () => b64urlDecodeString,
3483
- b64urlEncode: () => b64urlEncode,
4066
+ // src/utils/axis-tlv-codec.ts
4067
+ function encodeAxisTlvDto(dtoClass, data) {
4068
+ const schema = extractDtoSchema(dtoClass);
4069
+ const items = schema.fields.flatMap((field) => {
4070
+ const value = data[field.name];
4071
+ if (value === void 0 || value === null) {
4072
+ if (field.required) {
4073
+ throw new Error(`Missing required TLV response field: ${field.name}`);
4074
+ }
4075
+ return [];
4076
+ }
4077
+ return [{ type: field.tag, value: encodeField(field, value) }];
4078
+ });
4079
+ return buildTLVs(items);
4080
+ }
4081
+ function encodeField(field, value) {
4082
+ switch (field.kind) {
4083
+ case "utf8":
4084
+ return Buffer.from(String(value), "utf8");
4085
+ case "u64":
4086
+ return encodeU64(value);
4087
+ case "bytes":
4088
+ case "bytes16":
4089
+ return toBuffer(value);
4090
+ case "bool":
4091
+ return Buffer.from([value ? 1 : 0]);
4092
+ case "obj":
4093
+ case "arr":
4094
+ return Buffer.from(JSON.stringify(value), "utf8");
4095
+ default:
4096
+ return toBuffer(value);
4097
+ }
4098
+ }
4099
+ function encodeU64(value) {
4100
+ const encoded = Buffer.alloc(8);
4101
+ encoded.writeBigUInt64BE(
4102
+ typeof value === "bigint" ? value : BigInt(value)
4103
+ );
4104
+ return encoded;
4105
+ }
4106
+ function toBuffer(value) {
4107
+ if (Buffer.isBuffer(value)) {
4108
+ return value;
4109
+ }
4110
+ if (value instanceof Uint8Array) {
4111
+ return Buffer.from(value);
4112
+ }
4113
+ if (typeof value === "string") {
4114
+ return Buffer.from(value, "utf8");
4115
+ }
4116
+ throw new Error(`Unsupported TLV bytes value: ${typeof value}`);
4117
+ }
4118
+
4119
+ // src/loom/loom.types.ts
4120
+ function deriveAnchorReflection(softid, context = "openlogs", scope = "loom") {
4121
+ return `ar:${context}:${scope}:${softid}`;
4122
+ }
4123
+ function canonicalizeWrit(writ) {
4124
+ const ordered = {
4125
+ head: { tid: writ.head.tid, seq: writ.head.seq },
4126
+ body: {
4127
+ who: writ.body.who,
4128
+ act: writ.body.act,
4129
+ res: writ.body.res,
4130
+ law: writ.body.law
4131
+ },
4132
+ meta: { iat: writ.meta.iat, exp: writ.meta.exp, prev: writ.meta.prev }
4133
+ };
4134
+ return JSON.stringify(ordered);
4135
+ }
4136
+ function canonicalizeGrant(grant) {
4137
+ const ordered = {
4138
+ grant_id: grant.grant_id,
4139
+ issuer: grant.issuer,
4140
+ subject: grant.subject,
4141
+ grant_type: grant.grant_type,
4142
+ caps: grant.caps,
4143
+ meta: grant.meta
4144
+ };
4145
+ return JSON.stringify(ordered);
4146
+ }
4147
+
4148
+ // src/cce/index.ts
4149
+ var cce_exports = {};
4150
+ __export(cce_exports, {
4151
+ CCE_AES_KEY_BYTES: () => CCE_AES_KEY_BYTES,
4152
+ CCE_DERIVATION: () => CCE_DERIVATION,
4153
+ CCE_ERROR: () => CCE_ERROR,
4154
+ CCE_IV_BYTES: () => CCE_IV_BYTES,
4155
+ CCE_NONCE_BYTES: () => CCE_NONCE_BYTES,
4156
+ CCE_PROTOCOL_VERSION: () => CCE_PROTOCOL_VERSION,
4157
+ CCE_TAG_BYTES: () => CCE_TAG_BYTES,
4158
+ CceAudienceIntentBindingSensor: () => CceAudienceIntentBindingSensor,
4159
+ CceCapsuleVerificationSensor: () => CceCapsuleVerificationSensor,
4160
+ CceClientSignatureSensor: () => CceClientSignatureSensor,
4161
+ CceEnvelopeValidationSensor: () => CceEnvelopeValidationSensor,
4162
+ CceError: () => CceError,
4163
+ CcePayloadDecryptionSensor: () => CcePayloadDecryptionSensor,
4164
+ CceReplayProtectionSensor: () => CceReplayProtectionSensor,
4165
+ CceTpsWindowSensor: () => CceTpsWindowSensor,
4166
+ InMemoryCceReplayStore: () => InMemoryCceReplayStore,
4167
+ InMemoryCceWitnessStore: () => InMemoryCceWitnessStore,
4168
+ aesGcmDecrypt: () => aesGcmDecrypt,
4169
+ aesGcmEncrypt: () => aesGcmEncrypt,
4170
+ base64UrlDecode: () => base64UrlDecode,
4171
+ base64UrlEncode: () => base64UrlEncode,
4172
+ buildCceErrorResponse: () => buildCceErrorResponse,
4173
+ buildCceResponse: () => buildCceResponse,
4174
+ buildExecutionContext: () => buildExecutionContext,
4175
+ buildWitnessRecord: () => buildWitnessRecord,
4176
+ deriveRequestExecutionKey: () => deriveRequestExecutionKey,
4177
+ deriveResponseExecutionKey: () => deriveResponseExecutionKey,
4178
+ deriveWitnessKey: () => deriveWitnessKey,
4179
+ executeCcePipeline: () => executeCcePipeline,
4180
+ extractVerificationState: () => extractVerificationState,
4181
+ generateAesKey: () => generateAesKey,
4182
+ generateCceNonce: () => generateCceNonce,
4183
+ generateIv: () => generateIv,
4184
+ hashPayload: () => hashPayload,
4185
+ nodeAesGcmProvider: () => nodeAesGcmProvider
4186
+ });
4187
+
4188
+ // src/cce/sensors/cce-envelope-validation.sensor.ts
4189
+ var REQUIRED_FIELDS = [
4190
+ "ver",
4191
+ "request_id",
4192
+ "correlation_id",
4193
+ "client_kid",
4194
+ "capsule",
4195
+ "encrypted_key",
4196
+ "encrypted_payload",
4197
+ "request_nonce",
4198
+ "client_sig",
4199
+ "algorithms"
4200
+ ];
4201
+ var CceEnvelopeValidationSensor = class {
4202
+ constructor() {
4203
+ this.name = "cce.envelope.validation";
4204
+ this.order = 5;
4205
+ this.phase = "PRE_DECODE";
4206
+ }
4207
+ supports(input) {
4208
+ return input.metadata?.cce === true || input.metadata?.contentType === "application/axis-cce";
4209
+ }
4210
+ async run(input) {
4211
+ const envelope = input.metadata?.cceEnvelope;
4212
+ if (!envelope) {
4213
+ return {
4214
+ allow: false,
4215
+ riskScore: 100,
4216
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
4217
+ code: CCE_ERROR.INVALID_ENVELOPE
4218
+ };
4219
+ }
4220
+ for (const field of REQUIRED_FIELDS) {
4221
+ if (envelope[field] === void 0 || envelope[field] === null) {
4222
+ return {
4223
+ allow: false,
4224
+ riskScore: 100,
4225
+ reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: missing ${field}`],
4226
+ code: CCE_ERROR.INVALID_ENVELOPE
4227
+ };
4228
+ }
4229
+ }
4230
+ if (envelope.ver !== CCE_PROTOCOL_VERSION) {
4231
+ return {
4232
+ allow: false,
4233
+ riskScore: 100,
4234
+ reasons: [`${CCE_ERROR.UNSUPPORTED_VERSION}: ${envelope.ver}`],
4235
+ code: CCE_ERROR.UNSUPPORTED_VERSION
4236
+ };
4237
+ }
4238
+ if (!/^[0-9a-f]+$/i.test(envelope.request_nonce)) {
4239
+ return {
4240
+ allow: false,
4241
+ riskScore: 100,
4242
+ reasons: [
4243
+ `${CCE_ERROR.INVALID_ENVELOPE}: invalid request_nonce format`
4244
+ ],
4245
+ code: CCE_ERROR.INVALID_ENVELOPE
4246
+ };
4247
+ }
4248
+ if (envelope.request_nonce.length !== CCE_NONCE_BYTES * 2) {
4249
+ return {
4250
+ allow: false,
4251
+ riskScore: 100,
4252
+ reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: request_nonce wrong length`],
4253
+ code: CCE_ERROR.INVALID_ENVELOPE
4254
+ };
4255
+ }
4256
+ const capsule = envelope.capsule;
4257
+ if (!capsule.capsule_id || !capsule.ver || !capsule.sub || !capsule.kid || !capsule.intent || !capsule.aud || !capsule.issuer_sig) {
4258
+ return {
4259
+ allow: false,
4260
+ riskScore: 100,
4261
+ reasons: [`${CCE_ERROR.MISSING_CAPSULE}: incomplete capsule claims`],
4262
+ code: CCE_ERROR.MISSING_CAPSULE
4263
+ };
4264
+ }
4265
+ if (!envelope.encrypted_key.ciphertext || !envelope.encrypted_key.alg) {
4266
+ return {
4267
+ allow: false,
4268
+ riskScore: 100,
4269
+ reasons: [
4270
+ `${CCE_ERROR.MISSING_ENCRYPTED_KEY}: incomplete encrypted_key`
4271
+ ],
4272
+ code: CCE_ERROR.MISSING_ENCRYPTED_KEY
4273
+ };
4274
+ }
4275
+ input.metadata = input.metadata ?? {};
4276
+ input.metadata.cceEnvelopeValid = true;
4277
+ return {
4278
+ decision: "ALLOW" /* ALLOW */,
4279
+ allow: true,
4280
+ riskScore: 0,
4281
+ reasons: []
4282
+ };
4283
+ }
4284
+ };
4285
+
4286
+ // src/cce/sensors/cce-client-signature.sensor.ts
4287
+ var CceClientSignatureSensor = class {
4288
+ constructor(keyResolver, signatureVerifier) {
4289
+ this.keyResolver = keyResolver;
4290
+ this.signatureVerifier = signatureVerifier;
4291
+ this.name = "cce.client.signature";
4292
+ this.order = 45;
4293
+ this.phase = "POST_DECODE";
4294
+ }
4295
+ supports(input) {
4296
+ return input.metadata?.cceEnvelopeValid === true;
4297
+ }
4298
+ async run(input) {
4299
+ const envelope = input.metadata?.cceEnvelope;
4300
+ if (!envelope) {
4301
+ return {
4302
+ allow: false,
4303
+ riskScore: 100,
4304
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
4305
+ code: CCE_ERROR.INVALID_ENVELOPE
4306
+ };
4307
+ }
4308
+ const keyRecord = await this.keyResolver.resolve(envelope.client_kid);
4309
+ if (!keyRecord) {
4310
+ return {
4311
+ allow: false,
4312
+ riskScore: 100,
4313
+ reasons: [
4314
+ `${CCE_ERROR.CLIENT_KEY_NOT_FOUND}: kid=${envelope.client_kid}`
4315
+ ],
4316
+ code: CCE_ERROR.CLIENT_KEY_NOT_FOUND
4317
+ };
4318
+ }
4319
+ const { client_sig, ...signable } = envelope;
4320
+ const canonical = canonicalize2(signable);
4321
+ const message = new TextEncoder().encode(canonical);
4322
+ const valid = await this.signatureVerifier.verify(
4323
+ message,
4324
+ client_sig.value,
4325
+ keyRecord.publicKeyHex,
4326
+ keyRecord.alg
4327
+ );
4328
+ if (!valid) {
4329
+ return {
4330
+ allow: false,
4331
+ riskScore: 100,
4332
+ reasons: [CCE_ERROR.CLIENT_SIG_INVALID],
4333
+ code: CCE_ERROR.CLIENT_SIG_INVALID
4334
+ };
4335
+ }
4336
+ input.metadata = input.metadata ?? {};
4337
+ input.metadata.cceClientKey = keyRecord;
4338
+ input.metadata.cceClientSigVerified = true;
4339
+ return {
4340
+ decision: "ALLOW" /* ALLOW */,
4341
+ allow: true,
4342
+ riskScore: 0,
4343
+ reasons: [],
4344
+ meta: { kid: envelope.client_kid }
4345
+ };
4346
+ }
4347
+ };
4348
+ function canonicalize2(obj) {
4349
+ if (Array.isArray(obj)) {
4350
+ return "[" + obj.map(canonicalize2).join(",") + "]";
4351
+ }
4352
+ if (obj !== null && typeof obj === "object") {
4353
+ const sorted = Object.keys(obj).sort().map(
4354
+ (k) => JSON.stringify(k) + ":" + canonicalize2(obj[k])
4355
+ );
4356
+ return "{" + sorted.join(",") + "}";
4357
+ }
4358
+ return JSON.stringify(obj);
4359
+ }
4360
+
4361
+ // src/cce/sensors/cce-capsule-verification.sensor.ts
4362
+ import { blake3 } from "@noble/hashes/blake3.js";
4363
+ import { bytesToHex as bytesToHex5 } from "@noble/hashes/utils.js";
4364
+ var CceCapsuleVerificationSensor = class {
4365
+ constructor(issuerKeyResolver, capsuleVerifier) {
4366
+ this.issuerKeyResolver = issuerKeyResolver;
4367
+ this.capsuleVerifier = capsuleVerifier;
4368
+ this.name = "cce.capsule.verification";
4369
+ this.order = 50;
4370
+ this.phase = "POST_DECODE";
4371
+ }
4372
+ supports(input) {
4373
+ return input.metadata?.cceEnvelopeValid === true;
4374
+ }
4375
+ async run(input) {
4376
+ const capsule = input.metadata?.cceEnvelope?.capsule;
4377
+ if (!capsule) {
4378
+ return {
4379
+ allow: false,
4380
+ riskScore: 100,
4381
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
4382
+ code: CCE_ERROR.MISSING_CAPSULE
4383
+ };
4384
+ }
4385
+ if (capsule.ver !== CCE_PROTOCOL_VERSION) {
4386
+ return {
4387
+ allow: false,
4388
+ riskScore: 100,
4389
+ reasons: [
4390
+ `${CCE_ERROR.CAPSULE_SIG_INVALID}: wrong version ${capsule.ver}`
4391
+ ],
4392
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
4393
+ };
4394
+ }
4395
+ const { capsule_id, issuer_sig, ...claimsBody } = capsule;
4396
+ const expectedId = computeCceCapsuleId(claimsBody);
4397
+ if (capsule_id !== expectedId) {
4398
+ return {
4399
+ allow: false,
4400
+ riskScore: 100,
4401
+ reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: content hash mismatch`],
4402
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
4403
+ };
4404
+ }
4405
+ const issuerKey = await this.issuerKeyResolver.resolve(
4406
+ capsule.issuer_sig.kid
4407
+ );
4408
+ if (!issuerKey) {
4409
+ return {
4410
+ allow: false,
4411
+ riskScore: 100,
4412
+ reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: issuer key not found`],
4413
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
4414
+ };
4415
+ }
4416
+ const { issuer_sig: sig, ...rest } = capsule;
4417
+ const sigValid = await this.capsuleVerifier.verify(
4418
+ rest,
4419
+ sig,
4420
+ issuerKey.publicKeyHex
4421
+ );
4422
+ if (!sigValid) {
4423
+ return {
4424
+ allow: false,
4425
+ riskScore: 100,
4426
+ reasons: [CCE_ERROR.CAPSULE_SIG_INVALID],
4427
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
4428
+ };
4429
+ }
4430
+ const nowSeconds = Math.floor(Date.now() / 1e3);
4431
+ if (capsule.exp < nowSeconds) {
4432
+ return {
4433
+ allow: false,
4434
+ riskScore: 100,
4435
+ reasons: [`${CCE_ERROR.CAPSULE_EXPIRED}: exp=${capsule.exp}`],
4436
+ code: CCE_ERROR.CAPSULE_EXPIRED
4437
+ };
4438
+ }
4439
+ if (capsule.iat > nowSeconds + 5) {
4440
+ return {
4441
+ allow: false,
4442
+ riskScore: 100,
4443
+ reasons: [`${CCE_ERROR.CAPSULE_NOT_YET_VALID}: iat=${capsule.iat}`],
4444
+ code: CCE_ERROR.CAPSULE_NOT_YET_VALID
4445
+ };
4446
+ }
4447
+ input.metadata = input.metadata ?? {};
4448
+ input.metadata.cceCapsuleVerified = true;
4449
+ input.metadata.cceCapsule = capsule;
4450
+ return {
4451
+ decision: "ALLOW" /* ALLOW */,
4452
+ allow: true,
4453
+ riskScore: 0,
4454
+ reasons: [],
4455
+ meta: { capsule_id: capsule.capsule_id }
4456
+ };
4457
+ }
4458
+ };
4459
+ function canonicalize3(obj) {
4460
+ if (Array.isArray(obj)) {
4461
+ return "[" + obj.map(canonicalize3).join(",") + "]";
4462
+ }
4463
+ if (obj !== null && typeof obj === "object") {
4464
+ const sorted = Object.keys(obj).sort().map(
4465
+ (k) => JSON.stringify(k) + ":" + canonicalize3(obj[k])
4466
+ );
4467
+ return "{" + sorted.join(",") + "}";
4468
+ }
4469
+ return JSON.stringify(obj);
4470
+ }
4471
+ function computeCceCapsuleId(claims) {
4472
+ const canonical = canonicalize3(claims);
4473
+ const hash = blake3(new TextEncoder().encode(canonical));
4474
+ return "cce_b3_" + bytesToHex5(hash).slice(0, 32);
4475
+ }
4476
+
4477
+ // src/cce/sensors/cce-tps-window.sensor.ts
4478
+ var DEFAULT_SKEW_MS = 5e3;
4479
+ var CceTpsWindowSensor = class {
4480
+ constructor(skewMs = DEFAULT_SKEW_MS) {
4481
+ this.skewMs = skewMs;
4482
+ this.name = "cce.tps.window";
4483
+ this.order = 92;
4484
+ this.phase = "POST_DECODE";
4485
+ }
4486
+ supports(input) {
4487
+ return input.metadata?.cceCapsuleVerified === true;
4488
+ }
4489
+ async run(input) {
4490
+ const capsule = input.metadata?.cceCapsule;
4491
+ if (!capsule) {
4492
+ return {
4493
+ allow: false,
4494
+ riskScore: 100,
4495
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
4496
+ code: CCE_ERROR.MISSING_CAPSULE
4497
+ };
4498
+ }
4499
+ const nowMs = Date.now();
4500
+ if (nowMs > capsule.tps_to + this.skewMs) {
4501
+ return {
4502
+ allow: false,
4503
+ riskScore: 100,
4504
+ reasons: [
4505
+ `${CCE_ERROR.TPS_WINDOW_EXPIRED}: window ended at ${capsule.tps_to}, now=${nowMs}`
4506
+ ],
4507
+ code: CCE_ERROR.TPS_WINDOW_EXPIRED
4508
+ };
4509
+ }
4510
+ if (nowMs < capsule.tps_from - this.skewMs) {
4511
+ return {
4512
+ allow: false,
4513
+ riskScore: 100,
4514
+ reasons: [
4515
+ `${CCE_ERROR.TPS_WINDOW_FUTURE}: window starts at ${capsule.tps_from}, now=${nowMs}`
4516
+ ],
4517
+ code: CCE_ERROR.TPS_WINDOW_FUTURE
4518
+ };
4519
+ }
4520
+ input.metadata = input.metadata ?? {};
4521
+ input.metadata.cceTpsValid = true;
4522
+ return {
4523
+ decision: "ALLOW" /* ALLOW */,
4524
+ allow: true,
4525
+ riskScore: 0,
4526
+ reasons: []
4527
+ };
4528
+ }
4529
+ };
4530
+
4531
+ // src/cce/sensors/cce-audience-intent-binding.sensor.ts
4532
+ var CceAudienceIntentBindingSensor = class {
4533
+ constructor(axisAudience) {
4534
+ this.axisAudience = axisAudience;
4535
+ this.name = "cce.audience.intent.binding";
4536
+ this.order = 95;
4537
+ this.phase = "POST_DECODE";
4538
+ }
4539
+ supports(input) {
4540
+ return input.metadata?.cceCapsuleVerified === true;
4541
+ }
4542
+ async run(input) {
4543
+ const capsule = input.metadata?.cceCapsule;
4544
+ const envelope = input.metadata?.cceEnvelope;
4545
+ if (!capsule || !envelope) {
4546
+ return {
4547
+ allow: false,
4548
+ riskScore: 100,
4549
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
4550
+ code: CCE_ERROR.MISSING_CAPSULE
4551
+ };
4552
+ }
4553
+ if (capsule.aud !== this.axisAudience) {
4554
+ return {
4555
+ allow: false,
4556
+ riskScore: 100,
4557
+ reasons: [
4558
+ `${CCE_ERROR.AUDIENCE_MISMATCH}: capsule.aud=${capsule.aud}, expected=${this.axisAudience}`
4559
+ ],
4560
+ code: CCE_ERROR.AUDIENCE_MISMATCH
4561
+ };
4562
+ }
4563
+ const requestIntent = input.intent ?? input.metadata?.cceRequestIntent;
4564
+ if (requestIntent && capsule.intent !== requestIntent) {
4565
+ return {
4566
+ allow: false,
4567
+ riskScore: 100,
4568
+ reasons: [
4569
+ `${CCE_ERROR.INTENT_MISMATCH}: capsule.intent=${capsule.intent}, request=${requestIntent}`
4570
+ ],
4571
+ code: CCE_ERROR.INTENT_MISMATCH
4572
+ };
4573
+ }
4574
+ if (envelope.client_kid !== capsule.kid) {
4575
+ return {
4576
+ allow: false,
4577
+ riskScore: 100,
4578
+ reasons: [
4579
+ `${CCE_ERROR.INTENT_MISMATCH}: envelope.kid=${envelope.client_kid}, capsule.kid=${capsule.kid}`
4580
+ ],
4581
+ code: CCE_ERROR.INTENT_MISMATCH
4582
+ };
4583
+ }
4584
+ input.metadata = input.metadata ?? {};
4585
+ input.metadata.cceBindingVerified = true;
4586
+ return {
4587
+ decision: "ALLOW" /* ALLOW */,
4588
+ allow: true,
4589
+ riskScore: 0,
4590
+ reasons: []
4591
+ };
4592
+ }
4593
+ };
4594
+
4595
+ // src/cce/sensors/cce-replay-protection.sensor.ts
4596
+ var InMemoryCceReplayStore = class {
4597
+ constructor() {
4598
+ this.nonces = /* @__PURE__ */ new Map();
4599
+ this.consumed = /* @__PURE__ */ new Set();
4600
+ this.revoked = /* @__PURE__ */ new Set();
4601
+ }
4602
+ async checkAndMark(key, ttlMs) {
4603
+ this.cleanup();
4604
+ if (this.nonces.has(key)) return false;
4605
+ this.nonces.set(key, Date.now() + ttlMs);
4606
+ return true;
4607
+ }
4608
+ async isCapsuleConsumed(capsuleId) {
4609
+ return this.consumed.has(capsuleId);
4610
+ }
4611
+ async markCapsuleConsumed(capsuleId, _ttlMs) {
4612
+ this.consumed.add(capsuleId);
4613
+ }
4614
+ async isCapsuleRevoked(capsuleId) {
4615
+ return this.revoked.has(capsuleId);
4616
+ }
4617
+ /** Revoke a capsule (for testing/admin) */
4618
+ revoke(capsuleId) {
4619
+ this.revoked.add(capsuleId);
4620
+ }
4621
+ cleanup() {
4622
+ const now = Date.now();
4623
+ for (const [key, expiresAt] of this.nonces) {
4624
+ if (expiresAt < now) this.nonces.delete(key);
4625
+ }
4626
+ }
4627
+ };
4628
+ var CceReplayProtectionSensor = class {
4629
+ constructor(replayStore, options) {
4630
+ this.replayStore = replayStore;
4631
+ this.name = "cce.replay.protection";
4632
+ this.order = 98;
4633
+ this.phase = "POST_DECODE";
4634
+ this.nonceTtlMs = options?.nonceTtlMs ?? 5 * 60 * 1e3;
4635
+ }
4636
+ supports(input) {
4637
+ return input.metadata?.cceCapsuleVerified === true;
4638
+ }
4639
+ async run(input) {
4640
+ const capsule = input.metadata?.cceCapsule;
4641
+ const envelope = input.metadata?.cceEnvelope;
4642
+ if (!capsule || !envelope) {
4643
+ return {
4644
+ allow: false,
4645
+ riskScore: 100,
4646
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
4647
+ code: CCE_ERROR.MISSING_CAPSULE
4648
+ };
4649
+ }
4650
+ const revoked = await this.replayStore.isCapsuleRevoked(capsule.capsule_id);
4651
+ if (revoked) {
4652
+ return {
4653
+ allow: false,
4654
+ riskScore: 100,
4655
+ reasons: [`${CCE_ERROR.CAPSULE_REVOKED}: ${capsule.capsule_id}`],
4656
+ code: CCE_ERROR.CAPSULE_REVOKED
4657
+ };
4658
+ }
4659
+ if (capsule.mode === "SINGLE_USE") {
4660
+ const consumed = await this.replayStore.isCapsuleConsumed(
4661
+ capsule.capsule_id
4662
+ );
4663
+ if (consumed) {
4664
+ return {
4665
+ allow: false,
4666
+ riskScore: 100,
4667
+ reasons: [`${CCE_ERROR.CAPSULE_CONSUMED}: ${capsule.capsule_id}`],
4668
+ code: CCE_ERROR.CAPSULE_CONSUMED
4669
+ };
4670
+ }
4671
+ }
4672
+ const nonceKey = `cce:nonce:${capsule.sub}:${capsule.aud}:${capsule.intent}:${envelope.request_nonce}`;
4673
+ const nonceValid = await this.replayStore.checkAndMark(
4674
+ nonceKey,
4675
+ this.nonceTtlMs
4676
+ );
4677
+ if (!nonceValid) {
4678
+ return {
4679
+ allow: false,
4680
+ riskScore: 100,
4681
+ reasons: [
4682
+ `${CCE_ERROR.NONCE_REUSED}: ${envelope.request_nonce.slice(0, 16)}...`
4683
+ ],
4684
+ code: CCE_ERROR.NONCE_REUSED
4685
+ };
4686
+ }
4687
+ if (capsule.mode === "SINGLE_USE") {
4688
+ const capsuleTtl = (capsule.exp - capsule.iat) * 1e3 + 6e4;
4689
+ await this.replayStore.markCapsuleConsumed(
4690
+ capsule.capsule_id,
4691
+ capsuleTtl
4692
+ );
4693
+ }
4694
+ input.metadata = input.metadata ?? {};
4695
+ input.metadata.cceReplayClean = true;
4696
+ return {
4697
+ decision: "ALLOW" /* ALLOW */,
4698
+ allow: true,
4699
+ riskScore: 0,
4700
+ reasons: []
4701
+ };
4702
+ }
4703
+ };
4704
+
4705
+ // src/cce/sensors/cce-payload-decryption.sensor.ts
4706
+ var CcePayloadDecryptionSensor = class {
4707
+ constructor(keyProvider, aesProvider, maxPayloadBytes = 64 * 1024) {
4708
+ this.keyProvider = keyProvider;
4709
+ this.aesProvider = aesProvider;
4710
+ this.maxPayloadBytes = maxPayloadBytes;
4711
+ this.name = "cce.payload.decryption";
4712
+ this.order = 145;
4713
+ this.phase = "POST_DECODE";
4714
+ }
4715
+ supports(input) {
4716
+ return input.metadata?.cceEnvelopeValid === true && input.metadata?.cceClientSigVerified === true && input.metadata?.cceCapsuleVerified === true && input.metadata?.cceReplayClean === true;
4717
+ }
4718
+ async run(input) {
4719
+ const envelope = input.metadata?.cceEnvelope;
4720
+ if (!envelope) {
4721
+ return {
4722
+ allow: false,
4723
+ riskScore: 100,
4724
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
4725
+ code: CCE_ERROR.INVALID_ENVELOPE
4726
+ };
4727
+ }
4728
+ let aesKey;
4729
+ try {
4730
+ aesKey = await this.keyProvider.unwrapKey(
4731
+ envelope.encrypted_key.ciphertext,
4732
+ envelope.encrypted_key.alg,
4733
+ envelope.encrypted_key.axis_kid,
4734
+ envelope.encrypted_key.ephemeral_pk
4735
+ );
4736
+ } catch {
4737
+ return {
4738
+ allow: false,
4739
+ riskScore: 100,
4740
+ reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
4741
+ code: CCE_ERROR.KEY_UNWRAP_FAILED
4742
+ };
4743
+ }
4744
+ if (!aesKey) {
4745
+ return {
4746
+ allow: false,
4747
+ riskScore: 100,
4748
+ reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
4749
+ code: CCE_ERROR.KEY_UNWRAP_FAILED
4750
+ };
4751
+ }
4752
+ let iv;
4753
+ let ciphertext;
4754
+ let tag;
4755
+ try {
4756
+ iv = base64UrlDecode2(envelope.encrypted_payload.iv);
4757
+ ciphertext = base64UrlDecode2(envelope.encrypted_payload.ciphertext);
4758
+ tag = base64UrlDecode2(envelope.encrypted_payload.tag);
4759
+ } catch {
4760
+ return {
4761
+ allow: false,
4762
+ riskScore: 100,
4763
+ reasons: [`${CCE_ERROR.DECRYPTION_FAILED}: invalid base64url encoding`],
4764
+ code: CCE_ERROR.DECRYPTION_FAILED
4765
+ };
4766
+ }
4767
+ if (ciphertext.length > this.maxPayloadBytes) {
4768
+ return {
4769
+ allow: false,
4770
+ riskScore: 100,
4771
+ reasons: [
4772
+ `${CCE_ERROR.PAYLOAD_TOO_LARGE}: ${ciphertext.length} > ${this.maxPayloadBytes}`
4773
+ ],
4774
+ code: CCE_ERROR.PAYLOAD_TOO_LARGE
4775
+ };
4776
+ }
4777
+ const aad = buildAad(envelope);
4778
+ let plaintext;
4779
+ try {
4780
+ plaintext = await this.aesProvider.decrypt(
4781
+ aesKey,
4782
+ iv,
4783
+ ciphertext,
4784
+ tag,
4785
+ aad
4786
+ );
4787
+ } catch {
4788
+ plaintext = null;
4789
+ } finally {
4790
+ aesKey.fill(0);
4791
+ }
4792
+ if (!plaintext) {
4793
+ return {
4794
+ allow: false,
4795
+ riskScore: 100,
4796
+ reasons: [CCE_ERROR.AEAD_TAG_MISMATCH],
4797
+ code: CCE_ERROR.AEAD_TAG_MISMATCH
4798
+ };
4799
+ }
4800
+ input.metadata = input.metadata ?? {};
4801
+ input.metadata.cceDecryptedPayload = plaintext;
4802
+ input.metadata.cceDecryptionOk = true;
4803
+ return {
4804
+ decision: "ALLOW" /* ALLOW */,
4805
+ allow: true,
4806
+ riskScore: 0,
4807
+ reasons: []
4808
+ };
4809
+ }
4810
+ };
4811
+ function buildAad(envelope) {
4812
+ const parts = [
4813
+ envelope.ver,
4814
+ envelope.request_id,
4815
+ envelope.correlation_id,
4816
+ envelope.client_kid,
4817
+ envelope.capsule.capsule_id,
4818
+ envelope.capsule.intent,
4819
+ envelope.capsule.aud,
4820
+ envelope.request_nonce
4821
+ ];
4822
+ return new TextEncoder().encode(parts.join("|"));
4823
+ }
4824
+ function base64UrlDecode2(input) {
4825
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
4826
+ const padding = "=".repeat((4 - base64.length % 4) % 4);
4827
+ const binary = atob(base64 + padding);
4828
+ const bytes2 = new Uint8Array(binary.length);
4829
+ for (let i = 0; i < binary.length; i++) {
4830
+ bytes2[i] = binary.charCodeAt(i);
4831
+ }
4832
+ return bytes2;
4833
+ }
4834
+
4835
+ // src/core/index.ts
4836
+ var core_exports = {};
4837
+ __export(core_exports, {
4838
+ AXIS_MAGIC: () => AXIS_MAGIC,
4839
+ AXIS_VERSION: () => AXIS_VERSION,
4840
+ AxisError: () => AxisError,
4841
+ AxisFrameZ: () => AxisFrameZ,
4842
+ BodyProfile: () => BodyProfile,
4843
+ ERR_BAD_SIGNATURE: () => ERR_BAD_SIGNATURE,
4844
+ ERR_CONTRACT_VIOLATION: () => ERR_CONTRACT_VIOLATION,
4845
+ ERR_INVALID_PACKET: () => ERR_INVALID_PACKET,
4846
+ ERR_REPLAY_DETECTED: () => ERR_REPLAY_DETECTED,
4847
+ FLAG_BODY_TLV: () => FLAG_BODY_TLV,
4848
+ FLAG_CHAIN_REQ: () => FLAG_CHAIN_REQ,
4849
+ FLAG_HAS_WITNESS: () => FLAG_HAS_WITNESS,
4850
+ MAX_BODY_LEN: () => MAX_BODY_LEN,
4851
+ MAX_FRAME_LEN: () => MAX_FRAME_LEN,
4852
+ MAX_HDR_LEN: () => MAX_HDR_LEN,
4853
+ MAX_SIG_LEN: () => MAX_SIG_LEN,
4854
+ NCERT_ALG: () => NCERT_ALG,
4855
+ NCERT_EXP: () => NCERT_EXP,
4856
+ NCERT_ISSUER_KID: () => NCERT_ISSUER_KID,
4857
+ NCERT_KID: () => NCERT_KID,
4858
+ NCERT_NBF: () => NCERT_NBF,
4859
+ NCERT_NODE_ID: () => NCERT_NODE_ID,
4860
+ NCERT_PAYLOAD: () => NCERT_PAYLOAD,
4861
+ NCERT_PUB: () => NCERT_PUB,
4862
+ NCERT_SCOPE: () => NCERT_SCOPE,
4863
+ NCERT_SIG: () => NCERT_SIG,
4864
+ PROOF_CAPSULE: () => PROOF_CAPSULE,
4865
+ PROOF_JWT: () => PROOF_JWT,
4866
+ PROOF_LOOM: () => PROOF_LOOM,
4867
+ PROOF_MTLS: () => PROOF_MTLS,
4868
+ PROOF_NONE: () => PROOF_NONE,
4869
+ PROOF_WITNESS: () => PROOF_WITNESS,
4870
+ ProofType: () => ProofType,
4871
+ TLV: () => TLV,
4872
+ TLV_ACTOR_ID: () => TLV_ACTOR_ID,
4873
+ TLV_AUD: () => TLV_AUD,
4874
+ TLV_BODY_ARR: () => TLV_BODY_ARR,
4875
+ TLV_BODY_OBJ: () => TLV_BODY_OBJ,
4876
+ TLV_CAPSULE: () => TLV_CAPSULE,
4877
+ TLV_EFFECT: () => TLV_EFFECT,
4878
+ TLV_ERROR_CODE: () => TLV_ERROR_CODE,
4879
+ TLV_ERROR_MSG: () => TLV_ERROR_MSG,
4880
+ TLV_INDEX: () => TLV_INDEX,
4881
+ TLV_INTENT: () => TLV_INTENT,
4882
+ TLV_KID: () => TLV_KID,
4883
+ TLV_LOOM_PRESENCE_ID: () => TLV_LOOM_PRESENCE_ID,
4884
+ TLV_LOOM_THREAD_HASH: () => TLV_LOOM_THREAD_HASH,
4885
+ TLV_LOOM_WRIT: () => TLV_LOOM_WRIT,
4886
+ TLV_NODE: () => TLV_NODE,
4887
+ TLV_NODE_CERT_HASH: () => TLV_NODE_CERT_HASH,
4888
+ TLV_NODE_KID: () => TLV_NODE_KID,
4889
+ TLV_NONCE: () => TLV_NONCE,
4890
+ TLV_OFFSET: () => TLV_OFFSET,
4891
+ TLV_OK: () => TLV_OK,
4892
+ TLV_PID: () => TLV_PID,
4893
+ TLV_PREV_HASH: () => TLV_PREV_HASH,
4894
+ TLV_PROOF_REF: () => TLV_PROOF_REF,
4895
+ TLV_PROOF_TYPE: () => TLV_PROOF_TYPE,
4896
+ TLV_REALM: () => TLV_REALM,
4897
+ TLV_RECEIPT_HASH: () => TLV_RECEIPT_HASH,
4898
+ TLV_RID: () => TLV_RID,
4899
+ TLV_SHA256_CHUNK: () => TLV_SHA256_CHUNK,
4900
+ TLV_TRACE_ID: () => TLV_TRACE_ID,
4901
+ TLV_TS: () => TLV_TS,
4902
+ TLV_UPLOAD_ID: () => TLV_UPLOAD_ID,
4903
+ computeReceiptHash: () => computeReceiptHash,
4904
+ computeSignaturePayload: () => computeSignaturePayload,
4905
+ decodeArray: () => decodeArray,
4906
+ decodeFrame: () => decodeFrame,
4907
+ decodeObject: () => decodeObject,
4908
+ decodeTLVs: () => decodeTLVs,
4909
+ decodeTLVsList: () => decodeTLVsList,
4910
+ decodeVarint: () => decodeVarint,
4911
+ encodeFrame: () => encodeFrame,
4912
+ encodeTLVs: () => encodeTLVs,
4913
+ encodeVarint: () => encodeVarint,
4914
+ generateEd25519KeyPair: () => generateEd25519KeyPair,
4915
+ getSignTarget: () => getSignTarget,
4916
+ sha256: () => sha2564,
4917
+ signFrame: () => signFrame,
4918
+ varintLength: () => varintLength,
4919
+ verifyFrameSignature: () => verifyFrameSignature
4920
+ });
4921
+
4922
+ // src/crypto/index.ts
4923
+ var crypto_exports = {};
4924
+ __export(crypto_exports, {
4925
+ ProofVerificationService: () => ProofVerificationService,
4926
+ b64urlDecode: () => b64urlDecode,
4927
+ b64urlDecodeString: () => b64urlDecodeString,
4928
+ b64urlEncode: () => b64urlEncode,
3484
4929
  b64urlEncodeString: () => b64urlEncodeString,
3485
4930
  canonicalJson: () => canonicalJson,
3486
4931
  canonicalJsonExcluding: () => canonicalJsonExcluding
@@ -3488,7 +4933,7 @@ __export(crypto_exports, {
3488
4933
 
3489
4934
  // src/crypto/proof-verification.service.ts
3490
4935
  import { Injectable as Injectable8, Logger as Logger7 } from "@nestjs/common";
3491
- import * as crypto3 from "crypto";
4936
+ import * as crypto4 from "crypto";
3492
4937
  import * as nacl from "tweetnacl";
3493
4938
  var ProofVerificationService = class {
3494
4939
  constructor() {
@@ -3700,7 +5145,7 @@ var ProofVerificationService = class {
3700
5145
  certPem.replace(/-----BEGIN CERTIFICATE-----/, "").replace(/-----END CERTIFICATE-----/, "").replace(/\s/g, ""),
3701
5146
  "base64"
3702
5147
  );
3703
- return crypto3.createHash("sha256").update(der).digest("hex");
5148
+ return crypto4.createHash("sha256").update(der).digest("hex");
3704
5149
  }
3705
5150
  };
3706
5151
  ProofVerificationService = __decorateClass([
@@ -3747,12 +5192,22 @@ __export(engine_exports, {
3747
5192
  PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
3748
5193
  SensorDiscoveryService: () => SensorDiscoveryService,
3749
5194
  SensorRegistry: () => SensorRegistry,
5195
+ buildQueueMessage: () => buildQueueMessage,
5196
+ buildUnsignedWitness: () => buildUnsignedWitness,
5197
+ canonicalizeObservation: () => canonicalizeObservation,
3750
5198
  createObservation: () => createObservation,
5199
+ decodeQueueMessage: () => decodeQueueMessage,
5200
+ encodeQueueMessage: () => encodeQueueMessage,
3751
5201
  endStage: () => endStage,
3752
5202
  finalizeObservation: () => finalizeObservation,
5203
+ hashObservation: () => hashObservation,
3753
5204
  observation: () => observation_exports,
5205
+ parseAutoClaimEntries: () => parseAutoClaimEntries,
5206
+ parseStreamEntries: () => parseStreamEntries,
3754
5207
  recordSensor: () => recordSensor,
3755
- startStage: () => startStage
5208
+ stableJsonStringify: () => stableJsonStringify,
5209
+ startStage: () => startStage,
5210
+ verifyResponse: () => verifyResponse
3756
5211
  });
3757
5212
 
3758
5213
  // src/engine/observation/index.ts
@@ -3782,35 +5237,6 @@ __export(loom_exports, {
3782
5237
  deriveAnchorReflection: () => deriveAnchorReflection
3783
5238
  });
3784
5239
 
3785
- // src/loom/loom.types.ts
3786
- function deriveAnchorReflection(softid, context = "openlogs", scope = "loom") {
3787
- return `ar:${context}:${scope}:${softid}`;
3788
- }
3789
- function canonicalizeWrit(writ) {
3790
- const ordered = {
3791
- head: { tid: writ.head.tid, seq: writ.head.seq },
3792
- body: {
3793
- who: writ.body.who,
3794
- act: writ.body.act,
3795
- res: writ.body.res,
3796
- law: writ.body.law
3797
- },
3798
- meta: { iat: writ.meta.iat, exp: writ.meta.exp, prev: writ.meta.prev }
3799
- };
3800
- return JSON.stringify(ordered);
3801
- }
3802
- function canonicalizeGrant(grant) {
3803
- const ordered = {
3804
- grant_id: grant.grant_id,
3805
- issuer: grant.issuer,
3806
- subject: grant.subject,
3807
- grant_type: grant.grant_type,
3808
- caps: grant.caps,
3809
- meta: grant.meta
3810
- };
3811
- return JSON.stringify(ordered);
3812
- }
3813
-
3814
5240
  // src/schemas/index.ts
3815
5241
  var schemas_exports = {};
3816
5242
  __export(schemas_exports, {
@@ -4590,7 +6016,7 @@ ChunkHashSensor = __decorateClass([
4590
6016
 
4591
6017
  // src/sensors/entropy.sensor.ts
4592
6018
  import { Injectable as Injectable14, Logger as Logger10 } from "@nestjs/common";
4593
- import * as crypto4 from "crypto";
6019
+ import * as crypto5 from "crypto";
4594
6020
  var EntropySensor = class {
4595
6021
  constructor() {
4596
6022
  this.logger = new Logger10(EntropySensor.name);
@@ -4758,7 +6184,7 @@ var EntropySensor = class {
4758
6184
  * @returns {Uint8Array} Cryptographically secure random bytes
4759
6185
  */
4760
6186
  static generateSecureRandom(length) {
4761
- return new Uint8Array(crypto4.randomBytes(length));
6187
+ return new Uint8Array(crypto5.randomBytes(length));
4762
6188
  }
4763
6189
  };
4764
6190
  EntropySensor = __decorateClass([
@@ -5821,59 +7247,6 @@ var utils_exports = {};
5821
7247
  __export(utils_exports, {
5822
7248
  encodeAxisTlvDto: () => encodeAxisTlvDto
5823
7249
  });
5824
-
5825
- // src/utils/axis-tlv-codec.ts
5826
- function encodeAxisTlvDto(dtoClass, data) {
5827
- const schema = extractDtoSchema(dtoClass);
5828
- const items = schema.fields.flatMap((field) => {
5829
- const value = data[field.name];
5830
- if (value === void 0 || value === null) {
5831
- if (field.required) {
5832
- throw new Error(`Missing required TLV response field: ${field.name}`);
5833
- }
5834
- return [];
5835
- }
5836
- return [{ type: field.tag, value: encodeField(field, value) }];
5837
- });
5838
- return buildTLVs(items);
5839
- }
5840
- function encodeField(field, value) {
5841
- switch (field.kind) {
5842
- case "utf8":
5843
- return Buffer.from(String(value), "utf8");
5844
- case "u64":
5845
- return encodeU64(value);
5846
- case "bytes":
5847
- case "bytes16":
5848
- return toBuffer(value);
5849
- case "bool":
5850
- return Buffer.from([value ? 1 : 0]);
5851
- case "obj":
5852
- case "arr":
5853
- return Buffer.from(JSON.stringify(value), "utf8");
5854
- default:
5855
- return toBuffer(value);
5856
- }
5857
- }
5858
- function encodeU64(value) {
5859
- const encoded = Buffer.alloc(8);
5860
- encoded.writeBigUInt64BE(
5861
- typeof value === "bigint" ? value : BigInt(value)
5862
- );
5863
- return encoded;
5864
- }
5865
- function toBuffer(value) {
5866
- if (Buffer.isBuffer(value)) {
5867
- return value;
5868
- }
5869
- if (value instanceof Uint8Array) {
5870
- return Buffer.from(value);
5871
- }
5872
- if (typeof value === "string") {
5873
- return Buffer.from(value, "utf8");
5874
- }
5875
- throw new Error(`Unsupported TLV bytes value: ${typeof value}`);
5876
- }
5877
7250
  export {
5878
7251
  ATS1_HDR,
5879
7252
  ATS1_SCHEMA,
@@ -5901,6 +7274,9 @@ export {
5901
7274
  BAND,
5902
7275
  BodyProfile,
5903
7276
  CAPABILITIES,
7277
+ CCE_ERROR,
7278
+ CCE_PROTOCOL_VERSION,
7279
+ CceError,
5904
7280
  ContractViolationError,
5905
7281
  DEFAULT_CONTRACTS,
5906
7282
  DEFAULT_TIMEOUT,
@@ -5960,6 +7336,7 @@ export {
5960
7336
  RESPONSE_TAG_ID,
5961
7337
  RESPONSE_TAG_UPDATED_AT,
5962
7338
  RESPONSE_TAG_UPDATED_BY,
7339
+ verifyResponse as ResponseObserver,
5963
7340
  RiskDecision,
5964
7341
  SENSOR_METADATA_KEY,
5965
7342
  Schema2002_PasskeyLoginOptionsRes,
@@ -5993,6 +7370,7 @@ export {
5993
7370
  TLV_OFFSET,
5994
7371
  TLV_OK,
5995
7372
  TLV_PID,
7373
+ TLV_LOOM_PRESENCE_ID as TLV_PRESENCE_ID,
5996
7374
  TLV_PREV_HASH,
5997
7375
  TLV_PROOF_REF,
5998
7376
  TLV_PROOF_TYPE,
@@ -6000,10 +7378,12 @@ export {
6000
7378
  TLV_RECEIPT_HASH,
6001
7379
  TLV_RID,
6002
7380
  TLV_SHA256_CHUNK,
7381
+ TLV_LOOM_THREAD_HASH as TLV_THREAD_HASH,
6003
7382
  TLV_TRACE_ID,
6004
7383
  TLV_TS,
6005
7384
  TLV_UPLOAD_ID,
6006
7385
  TLV_VALIDATORS_KEY,
7386
+ TLV_LOOM_WRIT as TLV_WRIT,
6007
7387
  TlvEnum,
6008
7388
  TlvField,
6009
7389
  TlvMinLen,
@@ -6026,7 +7406,10 @@ export {
6026
7406
  canAccessResource,
6027
7407
  canonicalJson,
6028
7408
  canonicalJsonExcluding,
7409
+ canonicalizeGrant,
6029
7410
  canonicalizeObservation,
7411
+ canonicalizeWrit,
7412
+ cce_exports as cce,
6030
7413
  classifyIntent,
6031
7414
  computeReceiptHash,
6032
7415
  computeSignaturePayload,
@@ -6042,14 +7425,17 @@ export {
6042
7425
  decodeTLVsList,
6043
7426
  decodeVarint,
6044
7427
  decorators_exports as decorators,
7428
+ deriveAnchorReflection,
6045
7429
  encVarint,
6046
7430
  encodeAxis1Frame,
7431
+ encodeAxisTlvDto,
6047
7432
  encodeFrame,
6048
7433
  encodeQueueMessage,
6049
7434
  encodeTLVs,
6050
7435
  encodeVarint,
6051
7436
  endStage,
6052
7437
  engine_exports as engine,
7438
+ executeCcePipeline,
6053
7439
  extractDtoSchema,
6054
7440
  finalizeObservation,
6055
7441
  generateEd25519KeyPair,
@@ -6076,7 +7462,7 @@ export {
6076
7462
  security_exports as security,
6077
7463
  sensitivityName,
6078
7464
  sensors_exports as sensors,
6079
- sha256,
7465
+ sha2564 as sha256,
6080
7466
  signFrame,
6081
7467
  stableJsonStringify,
6082
7468
  startStage,