@nextera.one/axis-server-sdk 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -64,6 +64,9 @@ __export(index_exports, {
64
64
  BAND: () => BAND,
65
65
  BodyProfile: () => import_axis_protocol2.BodyProfile,
66
66
  CAPABILITIES: () => CAPABILITIES,
67
+ CCE_ERROR: () => CCE_ERROR,
68
+ CCE_PROTOCOL_VERSION: () => CCE_PROTOCOL_VERSION,
69
+ CceError: () => CceError,
67
70
  ContractViolationError: () => ContractViolationError,
68
71
  DEFAULT_CONTRACTS: () => DEFAULT_CONTRACTS,
69
72
  DEFAULT_TIMEOUT: () => DEFAULT_TIMEOUT,
@@ -190,6 +193,7 @@ __export(index_exports, {
190
193
  canonicalJson: () => canonicalJson,
191
194
  canonicalJsonExcluding: () => canonicalJsonExcluding,
192
195
  canonicalizeObservation: () => canonicalizeObservation,
196
+ cce: () => cce_exports,
193
197
  classifyIntent: () => classifyIntent,
194
198
  computeReceiptHash: () => computeReceiptHash,
195
199
  computeSignaturePayload: () => computeSignaturePayload,
@@ -213,6 +217,7 @@ __export(index_exports, {
213
217
  encodeVarint: () => import_axis_protocol3.encodeVarint,
214
218
  endStage: () => endStage,
215
219
  engine: () => engine_exports,
220
+ executeCcePipeline: () => executeCcePipeline,
216
221
  extractDtoSchema: () => extractDtoSchema,
217
222
  finalizeObservation: () => finalizeObservation,
218
223
  generateEd25519KeyPair: () => generateEd25519KeyPair,
@@ -239,7 +244,7 @@ __export(index_exports, {
239
244
  security: () => security_exports,
240
245
  sensitivityName: () => sensitivityName,
241
246
  sensors: () => sensors_exports,
242
- sha256: () => sha256,
247
+ sha256: () => sha2564,
243
248
  signFrame: () => signFrame,
244
249
  stableJsonStringify: () => stableJsonStringify,
245
250
  startStage: () => startStage,
@@ -636,6 +641,626 @@ var SensorDecisions = {
636
641
  }
637
642
  };
638
643
 
644
+ // src/cce/cce-derivation.service.ts
645
+ var import_utils = require("@noble/hashes/utils.js");
646
+ var import_hkdf = require("@noble/hashes/hkdf.js");
647
+ var import_sha2 = require("@noble/hashes/sha2.js");
648
+
649
+ // src/cce/cce.types.ts
650
+ var CCE_PROTOCOL_VERSION = "cce-v1";
651
+ var CCE_DERIVATION = {
652
+ /** Request execution context */
653
+ REQUEST: "axis:cce:req:v1",
654
+ /** Response execution context */
655
+ RESPONSE: "axis:cce:resp:v1",
656
+ /** Witness binding context */
657
+ WITNESS: "axis:cce:witness:v1"
658
+ };
659
+ var CCE_AES_KEY_BYTES = 32;
660
+ var CCE_IV_BYTES = 12;
661
+ var CCE_TAG_BYTES = 16;
662
+ var CCE_NONCE_BYTES = 32;
663
+ var CCE_ERROR = {
664
+ // Envelope errors
665
+ INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
666
+ UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
667
+ MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
668
+ MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
669
+ // Signature errors
670
+ CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
671
+ CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
672
+ // Capsule errors
673
+ CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
674
+ CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
675
+ CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
676
+ CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
677
+ CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
678
+ // Binding errors
679
+ AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
680
+ INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
681
+ TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
682
+ TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
683
+ // Replay / nonce errors
684
+ REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
685
+ NONCE_REUSED: "CCE_NONCE_REUSED",
686
+ // Decryption errors
687
+ DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
688
+ KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
689
+ AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
690
+ PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
691
+ // Schema / validation errors
692
+ PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
693
+ INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
694
+ // Policy errors
695
+ POLICY_DENIED: "CCE_POLICY_DENIED",
696
+ CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
697
+ // Handler errors
698
+ HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
699
+ HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
700
+ HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
701
+ // Response errors
702
+ RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
703
+ };
704
+ var CceError = class extends Error {
705
+ constructor(code, message, metadata) {
706
+ super(`[${code}] ${message}`);
707
+ this.code = code;
708
+ this.metadata = metadata;
709
+ this.name = "CceError";
710
+ }
711
+ /** Whether this error is safe to expose to the client */
712
+ get clientSafe() {
713
+ const internal = [
714
+ CCE_ERROR.DECRYPTION_FAILED,
715
+ CCE_ERROR.KEY_UNWRAP_FAILED,
716
+ CCE_ERROR.AEAD_TAG_MISMATCH,
717
+ CCE_ERROR.HANDLER_EXECUTION_FAILED,
718
+ CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
719
+ ];
720
+ return !internal.includes(this.code);
721
+ }
722
+ /** Get client-safe representation */
723
+ toClientError() {
724
+ if (this.clientSafe) {
725
+ return { code: this.code, message: this.message };
726
+ }
727
+ return {
728
+ code: CCE_ERROR.DECRYPTION_FAILED,
729
+ message: "Request processing failed"
730
+ };
731
+ }
732
+ };
733
+
734
+ // src/cce/cce-derivation.service.ts
735
+ function buildSalt(capsuleId, capsuleNonce, requestNonce) {
736
+ const encoder = new TextEncoder();
737
+ const data = encoder.encode(
738
+ capsuleId + "|" + capsuleNonce + "|" + requestNonce
739
+ );
740
+ return (0, import_sha2.sha256)(data);
741
+ }
742
+ function buildInfo(contextPrefix, capsule, extraNonce) {
743
+ const encoder = new TextEncoder();
744
+ const parts = [
745
+ contextPrefix,
746
+ capsule.sub,
747
+ capsule.kid,
748
+ capsule.intent,
749
+ capsule.aud,
750
+ String(capsule.tps_from),
751
+ String(capsule.tps_to),
752
+ capsule.policy_hash ?? "",
753
+ capsule.ver
754
+ ];
755
+ if (extraNonce) {
756
+ parts.push(extraNonce);
757
+ }
758
+ return encoder.encode(parts.join("|"));
759
+ }
760
+ function deriveRequestExecutionKey(input) {
761
+ const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
762
+ const salt = buildSalt(
763
+ input.capsule.capsule_id,
764
+ input.capsule.capsule_nonce,
765
+ input.requestNonce
766
+ );
767
+ const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
768
+ return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
769
+ }
770
+ function deriveResponseExecutionKey(input) {
771
+ const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
772
+ const encoder = new TextEncoder();
773
+ const saltData = encoder.encode(
774
+ input.capsule.capsule_id + "|" + input.capsule.capsule_nonce + "|" + input.requestNonce + "|" + input.responseNonce
775
+ );
776
+ const salt = (0, import_sha2.sha256)(saltData);
777
+ const info = buildInfo(
778
+ CCE_DERIVATION.RESPONSE,
779
+ input.capsule,
780
+ input.responseNonce
781
+ );
782
+ return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
783
+ }
784
+ function deriveWitnessKey(input) {
785
+ const ikm = (0, import_utils.hexToBytes)(input.axisLocalSecret);
786
+ const salt = buildSalt(
787
+ input.capsule.capsule_id,
788
+ input.capsule.capsule_nonce,
789
+ input.requestNonce
790
+ );
791
+ const info = buildInfo(CCE_DERIVATION.WITNESS, input.capsule);
792
+ return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
793
+ }
794
+ function buildExecutionContext(input, requestId) {
795
+ const executionKey = deriveRequestExecutionKey(input);
796
+ const keyHash = (0, import_utils.bytesToHex)((0, import_sha2.sha256)(executionKey));
797
+ executionKey.fill(0);
798
+ return {
799
+ execution_key_hash: keyHash,
800
+ request_id: requestId,
801
+ capsule_id: input.capsule.capsule_id,
802
+ sub: input.capsule.sub,
803
+ kid: input.capsule.kid,
804
+ intent: input.capsule.intent,
805
+ aud: input.capsule.aud,
806
+ tps_from: input.capsule.tps_from,
807
+ tps_to: input.capsule.tps_to,
808
+ policy_hash: input.capsule.policy_hash,
809
+ derived_at: Math.floor(Date.now() / 1e3),
810
+ valid: true
811
+ };
812
+ }
813
+ function generateCceNonce() {
814
+ const bytes2 = new Uint8Array(CCE_NONCE_BYTES);
815
+ crypto.getRandomValues(bytes2);
816
+ return (0, import_utils.bytesToHex)(bytes2);
817
+ }
818
+
819
+ // src/cce/cce-response.service.ts
820
+ var import_utils3 = require("@noble/hashes/utils.js");
821
+ var import_crypto2 = require("crypto");
822
+
823
+ // src/cce/cce-crypto.ts
824
+ var import_utils2 = require("@noble/hashes/utils.js");
825
+ var import_sha22 = require("@noble/hashes/sha2.js");
826
+ var import_crypto = require("crypto");
827
+ function aesGcmEncrypt(key, plaintext, aad) {
828
+ if (key.length !== CCE_AES_KEY_BYTES) {
829
+ throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
830
+ }
831
+ const iv = (0, import_crypto.randomBytes)(CCE_IV_BYTES);
832
+ const cipher = (0, import_crypto.createCipheriv)("aes-256-gcm", key, iv);
833
+ if (aad) {
834
+ cipher.setAAD(aad);
835
+ }
836
+ const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
837
+ const tag = cipher.getAuthTag();
838
+ return {
839
+ iv: new Uint8Array(iv),
840
+ ciphertext: new Uint8Array(encrypted),
841
+ tag: new Uint8Array(tag)
842
+ };
843
+ }
844
+ function aesGcmDecrypt(key, iv, ciphertext, tag, aad) {
845
+ if (key.length !== CCE_AES_KEY_BYTES) {
846
+ throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
847
+ }
848
+ if (iv.length !== CCE_IV_BYTES) {
849
+ throw new Error(`IV must be ${CCE_IV_BYTES} bytes`);
850
+ }
851
+ if (tag.length !== CCE_TAG_BYTES) {
852
+ throw new Error(`Tag must be ${CCE_TAG_BYTES} bytes`);
853
+ }
854
+ try {
855
+ const decipher = (0, import_crypto.createDecipheriv)("aes-256-gcm", key, iv);
856
+ decipher.setAuthTag(tag);
857
+ if (aad) {
858
+ decipher.setAAD(aad);
859
+ }
860
+ const decrypted = Buffer.concat([
861
+ decipher.update(ciphertext),
862
+ decipher.final()
863
+ ]);
864
+ return new Uint8Array(decrypted);
865
+ } catch {
866
+ return null;
867
+ }
868
+ }
869
+ function generateAesKey() {
870
+ return new Uint8Array((0, import_crypto.randomBytes)(CCE_AES_KEY_BYTES));
871
+ }
872
+ function generateIv() {
873
+ return new Uint8Array((0, import_crypto.randomBytes)(CCE_IV_BYTES));
874
+ }
875
+ function base64UrlEncode(bytes2) {
876
+ return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
877
+ }
878
+ function base64UrlDecode(input) {
879
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
880
+ const padding = "=".repeat((4 - base64.length % 4) % 4);
881
+ return new Uint8Array(Buffer.from(base64 + padding, "base64"));
882
+ }
883
+ function hashPayload(payload) {
884
+ return (0, import_utils2.bytesToHex)((0, import_sha22.sha256)(payload));
885
+ }
886
+ var nodeAesGcmProvider = {
887
+ async decrypt(key, iv, ciphertext, tag, aad) {
888
+ return aesGcmDecrypt(key, iv, ciphertext, tag, aad);
889
+ }
890
+ };
891
+
892
+ // src/cce/cce-response.service.ts
893
+ async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
894
+ const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
895
+ const responseNonce = (0, import_utils3.bytesToHex)(
896
+ new Uint8Array((0, import_crypto2.randomBytes)(CCE_NONCE_BYTES))
897
+ );
898
+ const responseId = generateResponseId();
899
+ const aesKey = generateAesKey();
900
+ const aad = buildResponseAad(
901
+ request.request_id,
902
+ responseId,
903
+ request.correlation_id,
904
+ capsule.capsule_id,
905
+ responseNonce
906
+ );
907
+ const { iv, ciphertext, tag } = aesGcmEncrypt(aesKey, body, aad);
908
+ const encryptedKey = await clientKeyEncryptor.wrapKey(
909
+ aesKey,
910
+ request.client_kid,
911
+ clientPublicKeyHex
912
+ );
913
+ aesKey.fill(0);
914
+ const encryptedPayload = {
915
+ alg: "AES-256-GCM",
916
+ iv: base64UrlEncode(iv),
917
+ ciphertext: base64UrlEncode(ciphertext),
918
+ tag: base64UrlEncode(tag)
919
+ };
920
+ const algorithms = {
921
+ kem: encryptedKey.alg,
922
+ enc: "AES-256-GCM",
923
+ kdf: "HKDF-SHA256",
924
+ sig: "EdDSA"
925
+ };
926
+ const unsignedResponse = {
927
+ ver: CCE_PROTOCOL_VERSION,
928
+ response_id: responseId,
929
+ request_id: request.request_id,
930
+ correlation_id: request.correlation_id,
931
+ encrypted_key: encryptedKey,
932
+ encrypted_payload: encryptedPayload,
933
+ response_nonce: responseNonce,
934
+ algorithms,
935
+ status,
936
+ ...witnessRef ? { witness_ref: witnessRef } : {}
937
+ };
938
+ const signPayload = new TextEncoder().encode(canonicalize(unsignedResponse));
939
+ const axisSig = await axisSigner.sign(signPayload);
940
+ const envelope = {
941
+ ...unsignedResponse,
942
+ axis_sig: axisSig
943
+ };
944
+ return {
945
+ envelope,
946
+ responsePayloadHash: hashPayload(body)
947
+ };
948
+ }
949
+ function buildCceErrorResponse(requestId, correlationId, status, errorCode, message) {
950
+ return {
951
+ ver: CCE_PROTOCOL_VERSION,
952
+ request_id: requestId,
953
+ correlation_id: correlationId,
954
+ status,
955
+ error: { code: errorCode, message }
956
+ };
957
+ }
958
+ function generateResponseId() {
959
+ const bytes2 = (0, import_crypto2.randomBytes)(16);
960
+ return "resp_" + (0, import_utils3.bytesToHex)(new Uint8Array(bytes2)).slice(0, 24);
961
+ }
962
+ function buildResponseAad(requestId, responseId, correlationId, capsuleId, responseNonce) {
963
+ const parts = [
964
+ requestId,
965
+ responseId,
966
+ correlationId,
967
+ capsuleId,
968
+ responseNonce
969
+ ];
970
+ return new TextEncoder().encode(parts.join("|"));
971
+ }
972
+ function canonicalize(obj) {
973
+ if (Array.isArray(obj)) {
974
+ return "[" + obj.map(canonicalize).join(",") + "]";
975
+ }
976
+ if (obj !== null && typeof obj === "object") {
977
+ const sorted = Object.keys(obj).sort().map(
978
+ (k) => JSON.stringify(k) + ":" + canonicalize(obj[k])
979
+ );
980
+ return "{" + sorted.join(",") + "}";
981
+ }
982
+ return JSON.stringify(obj);
983
+ }
984
+
985
+ // src/cce/cce-witness.observer.ts
986
+ var import_utils4 = require("@noble/hashes/utils.js");
987
+ var import_hkdf2 = require("@noble/hashes/hkdf.js");
988
+ var import_sha23 = require("@noble/hashes/sha2.js");
989
+ var InMemoryCceWitnessStore = class {
990
+ constructor() {
991
+ this.records = [];
992
+ }
993
+ async record(witness) {
994
+ this.records.push(witness);
995
+ }
996
+ getByRequestId(requestId) {
997
+ return this.records.find((w) => w.request_id === requestId);
998
+ }
999
+ getByCapsuleId(capsuleId) {
1000
+ return this.records.filter((w) => w.capsule_id === capsuleId);
1001
+ }
1002
+ };
1003
+ function buildWitnessRecord(envelope, capsule, verification, execution, options) {
1004
+ const witnessId = generateWitnessId(envelope.request_id, capsule.capsule_id);
1005
+ const executionContextHash = computeExecutionContextHash(
1006
+ options.axisLocalSecret,
1007
+ capsule,
1008
+ envelope.request_nonce
1009
+ );
1010
+ return {
1011
+ witness_id: witnessId,
1012
+ request_id: envelope.request_id,
1013
+ capsule_id: capsule.capsule_id,
1014
+ sub: capsule.sub,
1015
+ intent: capsule.intent,
1016
+ aud: capsule.aud,
1017
+ tps_from: capsule.tps_from,
1018
+ tps_to: capsule.tps_to,
1019
+ timestamp: Math.floor(Date.now() / 1e3),
1020
+ verification: {
1021
+ client_sig: verification.clientSigVerified,
1022
+ capsule_sig: verification.capsuleSigVerified,
1023
+ tps_valid: verification.tpsValid,
1024
+ audience_match: verification.audienceMatch,
1025
+ intent_match: verification.intentMatch,
1026
+ replay_clean: verification.replayClean,
1027
+ nonce_unique: verification.nonceUnique,
1028
+ decryption_ok: verification.decryptionOk
1029
+ },
1030
+ execution: {
1031
+ status: execution.status,
1032
+ handler_duration_ms: execution.handlerDurationMs,
1033
+ ...execution.effect ? { effect: execution.effect } : {}
1034
+ },
1035
+ response_encrypted: options.responseEncrypted,
1036
+ execution_context_hash: executionContextHash,
1037
+ ...options.requestPayload ? { request_payload_hash: hashPayload(options.requestPayload) } : {},
1038
+ ...options.responsePayload ? { response_payload_hash: hashPayload(options.responsePayload) } : {}
1039
+ };
1040
+ }
1041
+ function extractVerificationState(metadata) {
1042
+ return {
1043
+ clientSigVerified: metadata.cceClientSigVerified === true,
1044
+ capsuleSigVerified: metadata.cceCapsuleVerified === true,
1045
+ tpsValid: metadata.cceTpsValid === true,
1046
+ audienceMatch: metadata.cceBindingVerified === true,
1047
+ intentMatch: metadata.cceBindingVerified === true,
1048
+ replayClean: metadata.cceReplayClean === true,
1049
+ nonceUnique: metadata.cceReplayClean === true,
1050
+ decryptionOk: metadata.cceDecryptionOk === true
1051
+ };
1052
+ }
1053
+ function generateWitnessId(requestId, capsuleId) {
1054
+ const input = `witness:${requestId}:${capsuleId}:${Date.now()}`;
1055
+ const hash = (0, import_sha23.sha256)(new TextEncoder().encode(input));
1056
+ return "wit_" + (0, import_utils4.bytesToHex)(hash).slice(0, 24);
1057
+ }
1058
+ function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
1059
+ const encoder = new TextEncoder();
1060
+ const ikm = hexToBytes2(axisLocalSecret);
1061
+ const salt = (0, import_sha23.sha256)(
1062
+ encoder.encode(
1063
+ capsule.capsule_id + "|" + capsule.capsule_nonce + "|" + requestNonce
1064
+ )
1065
+ );
1066
+ const info = encoder.encode(
1067
+ [
1068
+ CCE_DERIVATION.WITNESS,
1069
+ capsule.sub,
1070
+ capsule.kid,
1071
+ capsule.intent,
1072
+ capsule.aud,
1073
+ String(capsule.tps_from),
1074
+ String(capsule.tps_to),
1075
+ capsule.policy_hash ?? "",
1076
+ capsule.ver
1077
+ ].join("|")
1078
+ );
1079
+ const witnessKey = (0, import_hkdf2.hkdf)(import_sha23.sha256, ikm, salt, info, 32);
1080
+ const hash = (0, import_utils4.bytesToHex)((0, import_sha23.sha256)(witnessKey));
1081
+ witnessKey.fill(0);
1082
+ return hash;
1083
+ }
1084
+ function hexToBytes2(hex) {
1085
+ const bytes2 = new Uint8Array(hex.length / 2);
1086
+ for (let i = 0; i < bytes2.length; i++) {
1087
+ bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
1088
+ }
1089
+ return bytes2;
1090
+ }
1091
+
1092
+ // src/cce/cce-pipeline.ts
1093
+ async function executeCcePipeline(envelope, config) {
1094
+ const startTime = Date.now();
1095
+ if (envelope.ver !== CCE_PROTOCOL_VERSION) {
1096
+ return {
1097
+ ok: false,
1098
+ error: {
1099
+ code: CCE_ERROR.UNSUPPORTED_VERSION,
1100
+ message: `Unsupported version: ${envelope.ver}`
1101
+ },
1102
+ status: "ERROR"
1103
+ };
1104
+ }
1105
+ const sensorInput = {
1106
+ intent: envelope.capsule.intent,
1107
+ metadata: {
1108
+ cce: true,
1109
+ cceEnvelope: envelope,
1110
+ contentType: "application/axis-cce"
1111
+ }
1112
+ };
1113
+ const sortedSensors = [...config.sensors].sort(
1114
+ (a, b) => (a.order ?? 999) - (b.order ?? 999)
1115
+ );
1116
+ for (const sensor of sortedSensors) {
1117
+ if (sensor.supports && !sensor.supports(sensorInput)) {
1118
+ continue;
1119
+ }
1120
+ let decision;
1121
+ try {
1122
+ decision = await sensor.run(sensorInput);
1123
+ } catch (err) {
1124
+ return {
1125
+ ok: false,
1126
+ error: {
1127
+ code: CCE_ERROR.DECRYPTION_FAILED,
1128
+ message: `Sensor ${sensor.name} failed`
1129
+ },
1130
+ status: "ERROR"
1131
+ };
1132
+ }
1133
+ const normalized = normalizeSensorDecision(decision);
1134
+ if (!normalized.allow) {
1135
+ const code = normalized.reasons[0]?.split(":")[0] ?? CCE_ERROR.DECRYPTION_FAILED;
1136
+ return {
1137
+ ok: false,
1138
+ error: { code, message: normalized.reasons.join("; ") },
1139
+ status: "DENIED"
1140
+ };
1141
+ }
1142
+ }
1143
+ const capsule = sensorInput.metadata?.cceCapsule;
1144
+ const decryptedPayload = sensorInput.metadata?.cceDecryptedPayload;
1145
+ const clientKey = sensorInput.metadata?.cceClientKey;
1146
+ if (!capsule || !decryptedPayload || !clientKey) {
1147
+ return {
1148
+ ok: false,
1149
+ error: {
1150
+ code: CCE_ERROR.DECRYPTION_FAILED,
1151
+ message: "Sensor chain did not produce required outputs"
1152
+ },
1153
+ status: "ERROR"
1154
+ };
1155
+ }
1156
+ const derivationInput = {
1157
+ axisLocalSecret: config.axisLocalSecret,
1158
+ capsule,
1159
+ requestNonce: envelope.request_nonce
1160
+ };
1161
+ const executionContext = buildExecutionContext(
1162
+ derivationInput,
1163
+ envelope.request_id
1164
+ );
1165
+ const handler = config.handlers.get(capsule.intent);
1166
+ if (!handler) {
1167
+ return {
1168
+ ok: false,
1169
+ error: {
1170
+ code: CCE_ERROR.HANDLER_NOT_FOUND,
1171
+ message: `No handler for intent: ${capsule.intent}`
1172
+ },
1173
+ status: "ERROR"
1174
+ };
1175
+ }
1176
+ const handlerContext = {
1177
+ capsule,
1178
+ executionContext,
1179
+ envelope,
1180
+ clientPublicKeyHex: clientKey.publicKeyHex,
1181
+ intent: capsule.intent,
1182
+ sub: capsule.sub
1183
+ };
1184
+ let result;
1185
+ const handlerStart = Date.now();
1186
+ try {
1187
+ result = await handler(decryptedPayload, handlerContext);
1188
+ } catch (err) {
1189
+ const handlerDuration2 = Date.now() - handlerStart;
1190
+ const verification2 = extractVerificationState(sensorInput.metadata ?? {});
1191
+ const witness2 = buildWitnessRecord(
1192
+ envelope,
1193
+ capsule,
1194
+ verification2,
1195
+ { status: "FAILED", handlerDurationMs: handlerDuration2 },
1196
+ {
1197
+ axisLocalSecret: config.axisLocalSecret,
1198
+ requestPayload: decryptedPayload,
1199
+ responseEncrypted: false
1200
+ }
1201
+ );
1202
+ await config.witnessStore.record(witness2);
1203
+ return {
1204
+ ok: false,
1205
+ error: {
1206
+ code: CCE_ERROR.HANDLER_EXECUTION_FAILED,
1207
+ message: "Handler execution failed"
1208
+ },
1209
+ status: "FAILED"
1210
+ };
1211
+ }
1212
+ const handlerDuration = Date.now() - handlerStart;
1213
+ let responseEnvelope;
1214
+ let responsePayloadHash;
1215
+ try {
1216
+ const responseResult = await buildCceResponse(
1217
+ {
1218
+ request: envelope,
1219
+ capsule,
1220
+ status: result.status,
1221
+ body: result.body,
1222
+ clientPublicKeyHex: clientKey.publicKeyHex
1223
+ },
1224
+ config.clientKeyEncryptor,
1225
+ config.axisSigner
1226
+ );
1227
+ responseEnvelope = responseResult.envelope;
1228
+ responsePayloadHash = responseResult.responsePayloadHash;
1229
+ } catch (err) {
1230
+ return {
1231
+ ok: false,
1232
+ error: {
1233
+ code: CCE_ERROR.RESPONSE_ENCRYPTION_FAILED,
1234
+ message: "Response encryption failed"
1235
+ },
1236
+ status: "ERROR"
1237
+ };
1238
+ }
1239
+ const verification = extractVerificationState(sensorInput.metadata ?? {});
1240
+ const witness = buildWitnessRecord(
1241
+ envelope,
1242
+ capsule,
1243
+ verification,
1244
+ {
1245
+ status: result.status,
1246
+ handlerDurationMs: handlerDuration,
1247
+ effect: result.effect
1248
+ },
1249
+ {
1250
+ axisLocalSecret: config.axisLocalSecret,
1251
+ requestPayload: decryptedPayload,
1252
+ responsePayload: result.body,
1253
+ responseEncrypted: true
1254
+ }
1255
+ );
1256
+ await config.witnessStore.record(witness);
1257
+ return {
1258
+ ok: true,
1259
+ response: responseEnvelope,
1260
+ witnessId: witness.witness_id
1261
+ };
1262
+ }
1263
+
639
1264
  // src/engine/intent.router.ts
640
1265
  var IntentRouter = class {
641
1266
  constructor(moduleRef) {
@@ -653,6 +1278,10 @@ var IntentRouter = class {
653
1278
  this.intentValidators = /* @__PURE__ */ new Map();
654
1279
  /** Per-intent operation kind */
655
1280
  this.intentKinds = /* @__PURE__ */ new Map();
1281
+ /** CCE handler registry */
1282
+ this.cceHandlers = /* @__PURE__ */ new Map();
1283
+ /** CCE pipeline configuration (set via configureCce) */
1284
+ this.ccePipelineConfig = null;
656
1285
  }
657
1286
  getSchema(intent) {
658
1287
  return this.intentSchemas.get(intent);
@@ -916,6 +1545,58 @@ var IntentRouter = class {
916
1545
  }
917
1546
  }
918
1547
  }
1548
+ // ===========================================================================
1549
+ // CCE — Capsule-Carried Encryption Support
1550
+ // ===========================================================================
1551
+ /**
1552
+ * Configure the CCE pipeline.
1553
+ * Must be called before routeCce() can process encrypted requests.
1554
+ */
1555
+ configureCce(config) {
1556
+ this.ccePipelineConfig = config;
1557
+ this.logger.log("CCE pipeline configured");
1558
+ }
1559
+ /**
1560
+ * Register a CCE-encrypted intent handler.
1561
+ * CCE handlers receive decrypted payloads and execution context.
1562
+ */
1563
+ registerCceHandler(intent, handler) {
1564
+ this.cceHandlers.set(intent, handler);
1565
+ this.logger.debug(`CCE handler registered: ${intent}`);
1566
+ }
1567
+ /**
1568
+ * Check if a CCE handler exists for the given intent.
1569
+ */
1570
+ hasCceHandler(intent) {
1571
+ return this.cceHandlers.has(intent);
1572
+ }
1573
+ /**
1574
+ * Route a CCE-encrypted request through the full pipeline.
1575
+ *
1576
+ * Steps:
1577
+ * 1. Sensor chain (envelope validation → capsule verification → replay → decrypt)
1578
+ * 2. Execution context derivation
1579
+ * 3. Handler execution
1580
+ * 4. Response encryption
1581
+ * 5. Witness recording
1582
+ */
1583
+ async routeCce(envelope) {
1584
+ if (!this.ccePipelineConfig) {
1585
+ return {
1586
+ ok: false,
1587
+ error: {
1588
+ code: "CCE_NOT_CONFIGURED",
1589
+ message: "CCE pipeline not configured. Call configureCce() first."
1590
+ },
1591
+ status: "ERROR"
1592
+ };
1593
+ }
1594
+ const config = {
1595
+ ...this.ccePipelineConfig,
1596
+ handlers: this.cceHandlers
1597
+ };
1598
+ return executeCcePipeline(envelope, config);
1599
+ }
919
1600
  storeSchema(meta) {
920
1601
  if (meta.dto) {
921
1602
  if (meta.tlv && meta.tlv.length > 0) {
@@ -1095,7 +1776,7 @@ function fieldsToMap(fields) {
1095
1776
  }
1096
1777
 
1097
1778
  // src/engine/observation/observation-hash.ts
1098
- var import_crypto = require("crypto");
1779
+ var import_crypto3 = require("crypto");
1099
1780
  function canonicalizeObservation(obs) {
1100
1781
  const obj = {
1101
1782
  id: obs.id,
@@ -1132,7 +1813,7 @@ function canonicalizeObservation(obs) {
1132
1813
  }
1133
1814
  function hashObservation(obs) {
1134
1815
  const canonical = canonicalizeObservation(obs);
1135
- return (0, import_crypto.createHash)("sha256").update(canonical).digest("hex");
1816
+ return (0, import_crypto3.createHash)("sha256").update(canonical).digest("hex");
1136
1817
  }
1137
1818
  function buildUnsignedWitness(obs) {
1138
1819
  if (!obs.decision || !obs.endMs) {
@@ -1207,7 +1888,7 @@ function verifyResponse(ctx, response) {
1207
1888
  var import_axis_protocol3 = require("@nextera.one/axis-protocol");
1208
1889
 
1209
1890
  // src/core/signature.ts
1210
- var crypto = __toESM(require("crypto"));
1891
+ var crypto2 = __toESM(require("crypto"));
1211
1892
 
1212
1893
  // src/core/axis-bin.ts
1213
1894
  var z = __toESM(require("zod"));
@@ -1337,19 +2018,19 @@ function signFrame(frame, privateKey) {
1337
2018
  32
1338
2019
  ]);
1339
2020
  const pkcs8Key = Buffer.concat([pkcs8Prefix, privateKey]);
1340
- keyObject = crypto.createPrivateKey({
2021
+ keyObject = crypto2.createPrivateKey({
1341
2022
  key: pkcs8Key,
1342
2023
  format: "der",
1343
2024
  type: "pkcs8"
1344
2025
  });
1345
2026
  } else {
1346
- keyObject = crypto.createPrivateKey({
2027
+ keyObject = crypto2.createPrivateKey({
1347
2028
  key: privateKey,
1348
2029
  format: "der",
1349
2030
  type: "pkcs8"
1350
2031
  });
1351
2032
  }
1352
- const signature = crypto.sign(null, payload, keyObject);
2033
+ const signature = crypto2.sign(null, payload, keyObject);
1353
2034
  if (signature.length !== 64) {
1354
2035
  throw new Error("Ed25519 signature must be 64 bytes");
1355
2036
  }
@@ -1381,19 +2062,19 @@ function verifyFrameSignature(frame, publicKey) {
1381
2062
  0
1382
2063
  ]);
1383
2064
  const spkiKey = Buffer.concat([spkiPrefix, publicKey]);
1384
- keyObject = crypto.createPublicKey({
2065
+ keyObject = crypto2.createPublicKey({
1385
2066
  key: spkiKey,
1386
2067
  format: "der",
1387
2068
  type: "spki"
1388
2069
  });
1389
2070
  } else {
1390
- keyObject = crypto.createPublicKey({
2071
+ keyObject = crypto2.createPublicKey({
1391
2072
  key: publicKey,
1392
2073
  format: "der",
1393
2074
  type: "spki"
1394
2075
  });
1395
2076
  }
1396
- const valid = crypto.verify(
2077
+ const valid = crypto2.verify(
1397
2078
  null,
1398
2079
  payload,
1399
2080
  keyObject,
@@ -1405,17 +2086,17 @@ function verifyFrameSignature(frame, publicKey) {
1405
2086
  }
1406
2087
  }
1407
2088
  function generateEd25519KeyPair() {
1408
- const { privateKey, publicKey } = crypto.generateKeyPairSync("ed25519");
2089
+ const { privateKey, publicKey } = crypto2.generateKeyPairSync("ed25519");
1409
2090
  return {
1410
2091
  privateKey: privateKey.export({ type: "pkcs8", format: "der" }),
1411
2092
  publicKey: publicKey.export({ type: "spki", format: "der" })
1412
2093
  };
1413
2094
  }
1414
- function sha256(data) {
1415
- return crypto.createHash("sha256").update(data).digest();
2095
+ function sha2564(data) {
2096
+ return crypto2.createHash("sha256").update(data).digest();
1416
2097
  }
1417
2098
  function computeReceiptHash(receiptBytes, prevHash) {
1418
- const hasher = crypto.createHash("sha256");
2099
+ const hasher = crypto2.createHash("sha256");
1419
2100
  hasher.update(receiptBytes);
1420
2101
  if (prevHash && prevHash.length > 0) {
1421
2102
  hasher.update(prevHash);
@@ -1473,12 +2154,12 @@ __export(ats1_exports, {
1473
2154
  encodeU64BE: () => encodeU64BE,
1474
2155
  encodeUVarint: () => encodeUVarint,
1475
2156
  logicalBodyToTLVs: () => logicalBodyToTLVs,
1476
- sha256: () => sha2562,
2157
+ sha256: () => sha2565,
1477
2158
  tlvsToLogicalBody: () => tlvsToLogicalBody,
1478
2159
  tlvsToMap: () => tlvsToMap,
1479
2160
  validateTLVsAgainstSchema: () => validateTLVsAgainstSchema
1480
2161
  });
1481
- var import_crypto2 = require("crypto");
2162
+ var import_crypto4 = require("crypto");
1482
2163
  var DEFAULT_LIMITS = {
1483
2164
  maxVarintBytes: 10,
1484
2165
  maxTlvCount: 512,
@@ -1527,8 +2208,8 @@ function decodeU64BE(buf) {
1527
2208
  if (buf.length !== 8) throw new Error("decodeU64BE: length must be 8");
1528
2209
  return buf.readBigUInt64BE(0);
1529
2210
  }
1530
- function sha2562(data) {
1531
- return (0, import_crypto2.createHash)("sha256").update(data).digest();
2211
+ function sha2565(data) {
2212
+ return (0, import_crypto4.createHash)("sha256").update(data).digest();
1532
2213
  }
1533
2214
  function encodeTLV(tag, value) {
1534
2215
  if (!Number.isInteger(tag) || tag <= 0)
@@ -1844,7 +2525,7 @@ function decodeAxisHeaderFromTLVs(hdrTlvs, limits = DEFAULT_LIMITS) {
1844
2525
  function encodeAxisRequestBinary(schema, req, limits = DEFAULT_LIMITS) {
1845
2526
  const bodyTlvs = logicalBodyToTLVs(schema, req.body, limits);
1846
2527
  const bodyBytes = encodeTLVStreamCanonical(bodyTlvs);
1847
- const bodyHash = sha2562(bodyBytes);
2528
+ const bodyHash = sha2565(bodyBytes);
1848
2529
  const hdr = {
1849
2530
  ...req.hdr,
1850
2531
  schemaId: schema.schemaId,
@@ -1860,7 +2541,7 @@ function decodeAxisRequestBinary(schema, hdrBytes, bodyBytes, limits = DEFAULT_L
1860
2541
  const hdr = decodeAxisHeaderFromTLVs(hdrTlvs, limits);
1861
2542
  if (hdr.schemaId !== schema.schemaId)
1862
2543
  throw new Error("decodeAxisRequestBinary: schemaId mismatch");
1863
- const bh = sha2562(bodyBytes);
2544
+ const bh = sha2565(bodyBytes);
1864
2545
  if (!Buffer.from(hdr.bodyHash).equals(bh))
1865
2546
  throw new Error("decodeAxisRequestBinary: body_hash mismatch");
1866
2547
  const body = tlvsToLogicalBody(schema, bodyTlvs, limits);
@@ -1933,7 +2614,7 @@ function packPasskeyLoginOptionsReq(params) {
1933
2614
  }
1934
2615
  );
1935
2616
  const body = encodeTLVStreamCanonical(bodyTlvs);
1936
- const bodyHash = sha2562(body);
2617
+ const bodyHash = sha2565(body);
1937
2618
  const hdr = buildAts1Hdr({
1938
2619
  intentId: params.intentId,
1939
2620
  schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_OPTIONS_REQ,
@@ -2002,7 +2683,7 @@ function packPasskeyRegisterOptionsReq(params) {
2002
2683
  }
2003
2684
  );
2004
2685
  const body = encodeTLVStreamCanonical(bodyTlvs);
2005
- const bodyHash = sha2562(body);
2686
+ const bodyHash = sha2565(body);
2006
2687
  const hdr = buildAts1Hdr({
2007
2688
  intentId: params.intentId,
2008
2689
  schemaId: ATS1_SCHEMA.PASSKEY_REGISTER_OPTIONS_REQ,
@@ -2033,7 +2714,7 @@ function packPasskeyLoginVerifyReq(params) {
2033
2714
  }
2034
2715
  });
2035
2716
  const body = encodeTLVStreamCanonical(bodyTlvs);
2036
- const bodyHash = sha2562(body);
2717
+ const bodyHash = sha2565(body);
2037
2718
  const hdr = buildAts1Hdr({
2038
2719
  intentId: params.intentId,
2039
2720
  schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_VERIFY_REQ,
@@ -2117,7 +2798,7 @@ function packPasskeyLoginVerifyRes(params) {
2117
2798
  }
2118
2799
 
2119
2800
  // src/codec/tlv.encode.ts
2120
- var import_crypto3 = require("crypto");
2801
+ var import_crypto5 = require("crypto");
2121
2802
  function encVarint(x) {
2122
2803
  if (x < 0n) throw new Error("VARINT_NEG");
2123
2804
  const out = [];
@@ -2145,7 +2826,7 @@ function bytes(b) {
2145
2826
  return Buffer.isBuffer(b) ? b : Buffer.from(b);
2146
2827
  }
2147
2828
  function nonce16() {
2148
- return (0, import_crypto3.randomBytes)(16);
2829
+ return (0, import_crypto5.randomBytes)(16);
2149
2830
  }
2150
2831
  function tlv(type, value) {
2151
2832
  if (!Number.isSafeInteger(type) || type < 0) throw new Error("TLV_BAD_TYPE");
@@ -2691,9 +3372,9 @@ function isAdminOpcode(op) {
2691
3372
  }
2692
3373
 
2693
3374
  // src/core/receipt.ts
2694
- var import_crypto4 = require("crypto");
3375
+ var import_crypto6 = require("crypto");
2695
3376
  function buildReceiptHash(prevHash, pid, actorId, intent, effect, ts) {
2696
- const h = (0, import_crypto4.createHash)("sha256");
3377
+ const h = (0, import_crypto6.createHash)("sha256");
2697
3378
  if (prevHash) h.update(prevHash);
2698
3379
  h.update(pid);
2699
3380
  h.update(Buffer.from(actorId, "utf8"));
@@ -2873,7 +3554,7 @@ function isTimestampValid(ts, skewSeconds = 120) {
2873
3554
 
2874
3555
  // src/upload/axis-files.handlers.ts
2875
3556
  var import_common4 = require("@nestjs/common");
2876
- var crypto2 = __toESM(require("crypto"));
3557
+ var crypto3 = __toESM(require("crypto"));
2877
3558
 
2878
3559
  // src/upload/upload.tokens.ts
2879
3560
  var AXIS_UPLOAD_SESSION_STORE = "AXIS_UPLOAD_SESSION_STORE";
@@ -2974,7 +3655,7 @@ var AxisFilesFinalizeHandler = class {
2974
3655
  if (!await this.files.hasTemp(fileId)) {
2975
3656
  throw new Error("CHUNKS_NOT_FOUND");
2976
3657
  }
2977
- const hash = crypto2.createHash("sha256");
3658
+ const hash = crypto3.createHash("sha256");
2978
3659
  const rs = this.files.createTempReadStream(fileId);
2979
3660
  for await (const chunk of rs) {
2980
3661
  hash.update(chunk);
@@ -3394,10 +4075,10 @@ SensorRegistry = __decorateClass([
3394
4075
  ], SensorRegistry);
3395
4076
 
3396
4077
  // src/engine/axis-observation.ts
3397
- var import_crypto5 = require("crypto");
4078
+ var import_crypto7 = require("crypto");
3398
4079
  function createObservation(transport, ip) {
3399
4080
  return {
3400
- id: (0, import_crypto5.randomBytes)(16).toString("hex"),
4081
+ id: (0, import_crypto7.randomBytes)(16).toString("hex"),
3401
4082
  startMs: Date.now(),
3402
4083
  transport,
3403
4084
  ip,
@@ -3555,6 +4236,693 @@ AxisSensorChainService = __decorateClass([
3555
4236
  (0, import_common9.Injectable)()
3556
4237
  ], AxisSensorChainService);
3557
4238
 
4239
+ // src/cce/index.ts
4240
+ var cce_exports = {};
4241
+ __export(cce_exports, {
4242
+ CCE_AES_KEY_BYTES: () => CCE_AES_KEY_BYTES,
4243
+ CCE_DERIVATION: () => CCE_DERIVATION,
4244
+ CCE_ERROR: () => CCE_ERROR,
4245
+ CCE_IV_BYTES: () => CCE_IV_BYTES,
4246
+ CCE_NONCE_BYTES: () => CCE_NONCE_BYTES,
4247
+ CCE_PROTOCOL_VERSION: () => CCE_PROTOCOL_VERSION,
4248
+ CCE_TAG_BYTES: () => CCE_TAG_BYTES,
4249
+ CceAudienceIntentBindingSensor: () => CceAudienceIntentBindingSensor,
4250
+ CceCapsuleVerificationSensor: () => CceCapsuleVerificationSensor,
4251
+ CceClientSignatureSensor: () => CceClientSignatureSensor,
4252
+ CceEnvelopeValidationSensor: () => CceEnvelopeValidationSensor,
4253
+ CceError: () => CceError,
4254
+ CcePayloadDecryptionSensor: () => CcePayloadDecryptionSensor,
4255
+ CceReplayProtectionSensor: () => CceReplayProtectionSensor,
4256
+ CceTpsWindowSensor: () => CceTpsWindowSensor,
4257
+ InMemoryCceReplayStore: () => InMemoryCceReplayStore,
4258
+ InMemoryCceWitnessStore: () => InMemoryCceWitnessStore,
4259
+ aesGcmDecrypt: () => aesGcmDecrypt,
4260
+ aesGcmEncrypt: () => aesGcmEncrypt,
4261
+ base64UrlDecode: () => base64UrlDecode,
4262
+ base64UrlEncode: () => base64UrlEncode,
4263
+ buildCceErrorResponse: () => buildCceErrorResponse,
4264
+ buildCceResponse: () => buildCceResponse,
4265
+ buildExecutionContext: () => buildExecutionContext,
4266
+ buildWitnessRecord: () => buildWitnessRecord,
4267
+ deriveRequestExecutionKey: () => deriveRequestExecutionKey,
4268
+ deriveResponseExecutionKey: () => deriveResponseExecutionKey,
4269
+ deriveWitnessKey: () => deriveWitnessKey,
4270
+ executeCcePipeline: () => executeCcePipeline,
4271
+ extractVerificationState: () => extractVerificationState,
4272
+ generateAesKey: () => generateAesKey,
4273
+ generateCceNonce: () => generateCceNonce,
4274
+ generateIv: () => generateIv,
4275
+ hashPayload: () => hashPayload,
4276
+ nodeAesGcmProvider: () => nodeAesGcmProvider
4277
+ });
4278
+
4279
+ // src/cce/sensors/cce-envelope-validation.sensor.ts
4280
+ var REQUIRED_FIELDS = [
4281
+ "ver",
4282
+ "request_id",
4283
+ "correlation_id",
4284
+ "client_kid",
4285
+ "capsule",
4286
+ "encrypted_key",
4287
+ "encrypted_payload",
4288
+ "request_nonce",
4289
+ "client_sig",
4290
+ "algorithms"
4291
+ ];
4292
+ var CceEnvelopeValidationSensor = class {
4293
+ constructor() {
4294
+ this.name = "cce.envelope.validation";
4295
+ this.order = 5;
4296
+ this.phase = "PRE_DECODE";
4297
+ }
4298
+ supports(input) {
4299
+ return input.metadata?.cce === true || input.metadata?.contentType === "application/axis-cce";
4300
+ }
4301
+ async run(input) {
4302
+ const envelope = input.metadata?.cceEnvelope;
4303
+ if (!envelope) {
4304
+ return {
4305
+ allow: false,
4306
+ riskScore: 100,
4307
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
4308
+ code: CCE_ERROR.INVALID_ENVELOPE
4309
+ };
4310
+ }
4311
+ for (const field of REQUIRED_FIELDS) {
4312
+ if (envelope[field] === void 0 || envelope[field] === null) {
4313
+ return {
4314
+ allow: false,
4315
+ riskScore: 100,
4316
+ reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: missing ${field}`],
4317
+ code: CCE_ERROR.INVALID_ENVELOPE
4318
+ };
4319
+ }
4320
+ }
4321
+ if (envelope.ver !== CCE_PROTOCOL_VERSION) {
4322
+ return {
4323
+ allow: false,
4324
+ riskScore: 100,
4325
+ reasons: [`${CCE_ERROR.UNSUPPORTED_VERSION}: ${envelope.ver}`],
4326
+ code: CCE_ERROR.UNSUPPORTED_VERSION
4327
+ };
4328
+ }
4329
+ if (!/^[0-9a-f]+$/i.test(envelope.request_nonce)) {
4330
+ return {
4331
+ allow: false,
4332
+ riskScore: 100,
4333
+ reasons: [
4334
+ `${CCE_ERROR.INVALID_ENVELOPE}: invalid request_nonce format`
4335
+ ],
4336
+ code: CCE_ERROR.INVALID_ENVELOPE
4337
+ };
4338
+ }
4339
+ if (envelope.request_nonce.length !== CCE_NONCE_BYTES * 2) {
4340
+ return {
4341
+ allow: false,
4342
+ riskScore: 100,
4343
+ reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: request_nonce wrong length`],
4344
+ code: CCE_ERROR.INVALID_ENVELOPE
4345
+ };
4346
+ }
4347
+ const capsule = envelope.capsule;
4348
+ if (!capsule.capsule_id || !capsule.ver || !capsule.sub || !capsule.kid || !capsule.intent || !capsule.aud || !capsule.issuer_sig) {
4349
+ return {
4350
+ allow: false,
4351
+ riskScore: 100,
4352
+ reasons: [`${CCE_ERROR.MISSING_CAPSULE}: incomplete capsule claims`],
4353
+ code: CCE_ERROR.MISSING_CAPSULE
4354
+ };
4355
+ }
4356
+ if (!envelope.encrypted_key.ciphertext || !envelope.encrypted_key.alg) {
4357
+ return {
4358
+ allow: false,
4359
+ riskScore: 100,
4360
+ reasons: [
4361
+ `${CCE_ERROR.MISSING_ENCRYPTED_KEY}: incomplete encrypted_key`
4362
+ ],
4363
+ code: CCE_ERROR.MISSING_ENCRYPTED_KEY
4364
+ };
4365
+ }
4366
+ input.metadata = input.metadata ?? {};
4367
+ input.metadata.cceEnvelopeValid = true;
4368
+ return {
4369
+ decision: "ALLOW" /* ALLOW */,
4370
+ allow: true,
4371
+ riskScore: 0,
4372
+ reasons: []
4373
+ };
4374
+ }
4375
+ };
4376
+
4377
+ // src/cce/sensors/cce-client-signature.sensor.ts
4378
+ var CceClientSignatureSensor = class {
4379
+ constructor(keyResolver, signatureVerifier) {
4380
+ this.keyResolver = keyResolver;
4381
+ this.signatureVerifier = signatureVerifier;
4382
+ this.name = "cce.client.signature";
4383
+ this.order = 45;
4384
+ this.phase = "POST_DECODE";
4385
+ }
4386
+ supports(input) {
4387
+ return input.metadata?.cceEnvelopeValid === true;
4388
+ }
4389
+ async run(input) {
4390
+ const envelope = input.metadata?.cceEnvelope;
4391
+ if (!envelope) {
4392
+ return {
4393
+ allow: false,
4394
+ riskScore: 100,
4395
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
4396
+ code: CCE_ERROR.INVALID_ENVELOPE
4397
+ };
4398
+ }
4399
+ const keyRecord = await this.keyResolver.resolve(envelope.client_kid);
4400
+ if (!keyRecord) {
4401
+ return {
4402
+ allow: false,
4403
+ riskScore: 100,
4404
+ reasons: [
4405
+ `${CCE_ERROR.CLIENT_KEY_NOT_FOUND}: kid=${envelope.client_kid}`
4406
+ ],
4407
+ code: CCE_ERROR.CLIENT_KEY_NOT_FOUND
4408
+ };
4409
+ }
4410
+ const { client_sig, ...signable } = envelope;
4411
+ const canonical = canonicalize2(signable);
4412
+ const message = new TextEncoder().encode(canonical);
4413
+ const valid = await this.signatureVerifier.verify(
4414
+ message,
4415
+ client_sig.value,
4416
+ keyRecord.publicKeyHex,
4417
+ keyRecord.alg
4418
+ );
4419
+ if (!valid) {
4420
+ return {
4421
+ allow: false,
4422
+ riskScore: 100,
4423
+ reasons: [CCE_ERROR.CLIENT_SIG_INVALID],
4424
+ code: CCE_ERROR.CLIENT_SIG_INVALID
4425
+ };
4426
+ }
4427
+ input.metadata = input.metadata ?? {};
4428
+ input.metadata.cceClientKey = keyRecord;
4429
+ input.metadata.cceClientSigVerified = true;
4430
+ return {
4431
+ decision: "ALLOW" /* ALLOW */,
4432
+ allow: true,
4433
+ riskScore: 0,
4434
+ reasons: [],
4435
+ meta: { kid: envelope.client_kid }
4436
+ };
4437
+ }
4438
+ };
4439
+ function canonicalize2(obj) {
4440
+ if (Array.isArray(obj)) {
4441
+ return "[" + obj.map(canonicalize2).join(",") + "]";
4442
+ }
4443
+ if (obj !== null && typeof obj === "object") {
4444
+ const sorted = Object.keys(obj).sort().map(
4445
+ (k) => JSON.stringify(k) + ":" + canonicalize2(obj[k])
4446
+ );
4447
+ return "{" + sorted.join(",") + "}";
4448
+ }
4449
+ return JSON.stringify(obj);
4450
+ }
4451
+
4452
+ // src/cce/sensors/cce-capsule-verification.sensor.ts
4453
+ var import_blake3 = require("@noble/hashes/blake3.js");
4454
+ var import_utils5 = require("@noble/hashes/utils.js");
4455
+ var CceCapsuleVerificationSensor = class {
4456
+ constructor(issuerKeyResolver, capsuleVerifier) {
4457
+ this.issuerKeyResolver = issuerKeyResolver;
4458
+ this.capsuleVerifier = capsuleVerifier;
4459
+ this.name = "cce.capsule.verification";
4460
+ this.order = 50;
4461
+ this.phase = "POST_DECODE";
4462
+ }
4463
+ supports(input) {
4464
+ return input.metadata?.cceEnvelopeValid === true;
4465
+ }
4466
+ async run(input) {
4467
+ const capsule = input.metadata?.cceEnvelope?.capsule;
4468
+ if (!capsule) {
4469
+ return {
4470
+ allow: false,
4471
+ riskScore: 100,
4472
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
4473
+ code: CCE_ERROR.MISSING_CAPSULE
4474
+ };
4475
+ }
4476
+ if (capsule.ver !== CCE_PROTOCOL_VERSION) {
4477
+ return {
4478
+ allow: false,
4479
+ riskScore: 100,
4480
+ reasons: [
4481
+ `${CCE_ERROR.CAPSULE_SIG_INVALID}: wrong version ${capsule.ver}`
4482
+ ],
4483
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
4484
+ };
4485
+ }
4486
+ const { capsule_id, issuer_sig, ...claimsBody } = capsule;
4487
+ const expectedId = computeCceCapsuleId(claimsBody);
4488
+ if (capsule_id !== expectedId) {
4489
+ return {
4490
+ allow: false,
4491
+ riskScore: 100,
4492
+ reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: content hash mismatch`],
4493
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
4494
+ };
4495
+ }
4496
+ const issuerKey = await this.issuerKeyResolver.resolve(
4497
+ capsule.issuer_sig.kid
4498
+ );
4499
+ if (!issuerKey) {
4500
+ return {
4501
+ allow: false,
4502
+ riskScore: 100,
4503
+ reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: issuer key not found`],
4504
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
4505
+ };
4506
+ }
4507
+ const { issuer_sig: sig, ...rest } = capsule;
4508
+ const sigValid = await this.capsuleVerifier.verify(
4509
+ rest,
4510
+ sig,
4511
+ issuerKey.publicKeyHex
4512
+ );
4513
+ if (!sigValid) {
4514
+ return {
4515
+ allow: false,
4516
+ riskScore: 100,
4517
+ reasons: [CCE_ERROR.CAPSULE_SIG_INVALID],
4518
+ code: CCE_ERROR.CAPSULE_SIG_INVALID
4519
+ };
4520
+ }
4521
+ const nowSeconds = Math.floor(Date.now() / 1e3);
4522
+ if (capsule.exp < nowSeconds) {
4523
+ return {
4524
+ allow: false,
4525
+ riskScore: 100,
4526
+ reasons: [`${CCE_ERROR.CAPSULE_EXPIRED}: exp=${capsule.exp}`],
4527
+ code: CCE_ERROR.CAPSULE_EXPIRED
4528
+ };
4529
+ }
4530
+ if (capsule.iat > nowSeconds + 5) {
4531
+ return {
4532
+ allow: false,
4533
+ riskScore: 100,
4534
+ reasons: [`${CCE_ERROR.CAPSULE_NOT_YET_VALID}: iat=${capsule.iat}`],
4535
+ code: CCE_ERROR.CAPSULE_NOT_YET_VALID
4536
+ };
4537
+ }
4538
+ input.metadata = input.metadata ?? {};
4539
+ input.metadata.cceCapsuleVerified = true;
4540
+ input.metadata.cceCapsule = capsule;
4541
+ return {
4542
+ decision: "ALLOW" /* ALLOW */,
4543
+ allow: true,
4544
+ riskScore: 0,
4545
+ reasons: [],
4546
+ meta: { capsule_id: capsule.capsule_id }
4547
+ };
4548
+ }
4549
+ };
4550
+ function canonicalize3(obj) {
4551
+ if (Array.isArray(obj)) {
4552
+ return "[" + obj.map(canonicalize3).join(",") + "]";
4553
+ }
4554
+ if (obj !== null && typeof obj === "object") {
4555
+ const sorted = Object.keys(obj).sort().map(
4556
+ (k) => JSON.stringify(k) + ":" + canonicalize3(obj[k])
4557
+ );
4558
+ return "{" + sorted.join(",") + "}";
4559
+ }
4560
+ return JSON.stringify(obj);
4561
+ }
4562
+ function computeCceCapsuleId(claims) {
4563
+ const canonical = canonicalize3(claims);
4564
+ const hash = (0, import_blake3.blake3)(new TextEncoder().encode(canonical));
4565
+ return "cce_b3_" + (0, import_utils5.bytesToHex)(hash).slice(0, 32);
4566
+ }
4567
+
4568
+ // src/cce/sensors/cce-tps-window.sensor.ts
4569
+ var DEFAULT_SKEW_MS = 5e3;
4570
+ var CceTpsWindowSensor = class {
4571
+ constructor(skewMs = DEFAULT_SKEW_MS) {
4572
+ this.skewMs = skewMs;
4573
+ this.name = "cce.tps.window";
4574
+ this.order = 92;
4575
+ this.phase = "POST_DECODE";
4576
+ }
4577
+ supports(input) {
4578
+ return input.metadata?.cceCapsuleVerified === true;
4579
+ }
4580
+ async run(input) {
4581
+ const capsule = input.metadata?.cceCapsule;
4582
+ if (!capsule) {
4583
+ return {
4584
+ allow: false,
4585
+ riskScore: 100,
4586
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
4587
+ code: CCE_ERROR.MISSING_CAPSULE
4588
+ };
4589
+ }
4590
+ const nowMs = Date.now();
4591
+ if (nowMs > capsule.tps_to + this.skewMs) {
4592
+ return {
4593
+ allow: false,
4594
+ riskScore: 100,
4595
+ reasons: [
4596
+ `${CCE_ERROR.TPS_WINDOW_EXPIRED}: window ended at ${capsule.tps_to}, now=${nowMs}`
4597
+ ],
4598
+ code: CCE_ERROR.TPS_WINDOW_EXPIRED
4599
+ };
4600
+ }
4601
+ if (nowMs < capsule.tps_from - this.skewMs) {
4602
+ return {
4603
+ allow: false,
4604
+ riskScore: 100,
4605
+ reasons: [
4606
+ `${CCE_ERROR.TPS_WINDOW_FUTURE}: window starts at ${capsule.tps_from}, now=${nowMs}`
4607
+ ],
4608
+ code: CCE_ERROR.TPS_WINDOW_FUTURE
4609
+ };
4610
+ }
4611
+ input.metadata = input.metadata ?? {};
4612
+ input.metadata.cceTpsValid = true;
4613
+ return {
4614
+ decision: "ALLOW" /* ALLOW */,
4615
+ allow: true,
4616
+ riskScore: 0,
4617
+ reasons: []
4618
+ };
4619
+ }
4620
+ };
4621
+
4622
+ // src/cce/sensors/cce-audience-intent-binding.sensor.ts
4623
+ var CceAudienceIntentBindingSensor = class {
4624
+ constructor(axisAudience) {
4625
+ this.axisAudience = axisAudience;
4626
+ this.name = "cce.audience.intent.binding";
4627
+ this.order = 95;
4628
+ this.phase = "POST_DECODE";
4629
+ }
4630
+ supports(input) {
4631
+ return input.metadata?.cceCapsuleVerified === true;
4632
+ }
4633
+ async run(input) {
4634
+ const capsule = input.metadata?.cceCapsule;
4635
+ const envelope = input.metadata?.cceEnvelope;
4636
+ if (!capsule || !envelope) {
4637
+ return {
4638
+ allow: false,
4639
+ riskScore: 100,
4640
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
4641
+ code: CCE_ERROR.MISSING_CAPSULE
4642
+ };
4643
+ }
4644
+ if (capsule.aud !== this.axisAudience) {
4645
+ return {
4646
+ allow: false,
4647
+ riskScore: 100,
4648
+ reasons: [
4649
+ `${CCE_ERROR.AUDIENCE_MISMATCH}: capsule.aud=${capsule.aud}, expected=${this.axisAudience}`
4650
+ ],
4651
+ code: CCE_ERROR.AUDIENCE_MISMATCH
4652
+ };
4653
+ }
4654
+ const requestIntent = input.intent ?? input.metadata?.cceRequestIntent;
4655
+ if (requestIntent && capsule.intent !== requestIntent) {
4656
+ return {
4657
+ allow: false,
4658
+ riskScore: 100,
4659
+ reasons: [
4660
+ `${CCE_ERROR.INTENT_MISMATCH}: capsule.intent=${capsule.intent}, request=${requestIntent}`
4661
+ ],
4662
+ code: CCE_ERROR.INTENT_MISMATCH
4663
+ };
4664
+ }
4665
+ if (envelope.client_kid !== capsule.kid) {
4666
+ return {
4667
+ allow: false,
4668
+ riskScore: 100,
4669
+ reasons: [
4670
+ `${CCE_ERROR.INTENT_MISMATCH}: envelope.kid=${envelope.client_kid}, capsule.kid=${capsule.kid}`
4671
+ ],
4672
+ code: CCE_ERROR.INTENT_MISMATCH
4673
+ };
4674
+ }
4675
+ input.metadata = input.metadata ?? {};
4676
+ input.metadata.cceBindingVerified = true;
4677
+ return {
4678
+ decision: "ALLOW" /* ALLOW */,
4679
+ allow: true,
4680
+ riskScore: 0,
4681
+ reasons: []
4682
+ };
4683
+ }
4684
+ };
4685
+
4686
+ // src/cce/sensors/cce-replay-protection.sensor.ts
4687
+ var InMemoryCceReplayStore = class {
4688
+ constructor() {
4689
+ this.nonces = /* @__PURE__ */ new Map();
4690
+ this.consumed = /* @__PURE__ */ new Set();
4691
+ this.revoked = /* @__PURE__ */ new Set();
4692
+ }
4693
+ async checkAndMark(key, ttlMs) {
4694
+ this.cleanup();
4695
+ if (this.nonces.has(key)) return false;
4696
+ this.nonces.set(key, Date.now() + ttlMs);
4697
+ return true;
4698
+ }
4699
+ async isCapsuleConsumed(capsuleId) {
4700
+ return this.consumed.has(capsuleId);
4701
+ }
4702
+ async markCapsuleConsumed(capsuleId, _ttlMs) {
4703
+ this.consumed.add(capsuleId);
4704
+ }
4705
+ async isCapsuleRevoked(capsuleId) {
4706
+ return this.revoked.has(capsuleId);
4707
+ }
4708
+ /** Revoke a capsule (for testing/admin) */
4709
+ revoke(capsuleId) {
4710
+ this.revoked.add(capsuleId);
4711
+ }
4712
+ cleanup() {
4713
+ const now = Date.now();
4714
+ for (const [key, expiresAt] of this.nonces) {
4715
+ if (expiresAt < now) this.nonces.delete(key);
4716
+ }
4717
+ }
4718
+ };
4719
+ var CceReplayProtectionSensor = class {
4720
+ constructor(replayStore, options) {
4721
+ this.replayStore = replayStore;
4722
+ this.name = "cce.replay.protection";
4723
+ this.order = 98;
4724
+ this.phase = "POST_DECODE";
4725
+ this.nonceTtlMs = options?.nonceTtlMs ?? 5 * 60 * 1e3;
4726
+ }
4727
+ supports(input) {
4728
+ return input.metadata?.cceCapsuleVerified === true;
4729
+ }
4730
+ async run(input) {
4731
+ const capsule = input.metadata?.cceCapsule;
4732
+ const envelope = input.metadata?.cceEnvelope;
4733
+ if (!capsule || !envelope) {
4734
+ return {
4735
+ allow: false,
4736
+ riskScore: 100,
4737
+ reasons: [CCE_ERROR.MISSING_CAPSULE],
4738
+ code: CCE_ERROR.MISSING_CAPSULE
4739
+ };
4740
+ }
4741
+ const revoked = await this.replayStore.isCapsuleRevoked(capsule.capsule_id);
4742
+ if (revoked) {
4743
+ return {
4744
+ allow: false,
4745
+ riskScore: 100,
4746
+ reasons: [`${CCE_ERROR.CAPSULE_REVOKED}: ${capsule.capsule_id}`],
4747
+ code: CCE_ERROR.CAPSULE_REVOKED
4748
+ };
4749
+ }
4750
+ if (capsule.mode === "SINGLE_USE") {
4751
+ const consumed = await this.replayStore.isCapsuleConsumed(
4752
+ capsule.capsule_id
4753
+ );
4754
+ if (consumed) {
4755
+ return {
4756
+ allow: false,
4757
+ riskScore: 100,
4758
+ reasons: [`${CCE_ERROR.CAPSULE_CONSUMED}: ${capsule.capsule_id}`],
4759
+ code: CCE_ERROR.CAPSULE_CONSUMED
4760
+ };
4761
+ }
4762
+ }
4763
+ const nonceKey = `cce:nonce:${capsule.sub}:${capsule.aud}:${capsule.intent}:${envelope.request_nonce}`;
4764
+ const nonceValid = await this.replayStore.checkAndMark(
4765
+ nonceKey,
4766
+ this.nonceTtlMs
4767
+ );
4768
+ if (!nonceValid) {
4769
+ return {
4770
+ allow: false,
4771
+ riskScore: 100,
4772
+ reasons: [
4773
+ `${CCE_ERROR.NONCE_REUSED}: ${envelope.request_nonce.slice(0, 16)}...`
4774
+ ],
4775
+ code: CCE_ERROR.NONCE_REUSED
4776
+ };
4777
+ }
4778
+ if (capsule.mode === "SINGLE_USE") {
4779
+ const capsuleTtl = (capsule.exp - capsule.iat) * 1e3 + 6e4;
4780
+ await this.replayStore.markCapsuleConsumed(
4781
+ capsule.capsule_id,
4782
+ capsuleTtl
4783
+ );
4784
+ }
4785
+ input.metadata = input.metadata ?? {};
4786
+ input.metadata.cceReplayClean = true;
4787
+ return {
4788
+ decision: "ALLOW" /* ALLOW */,
4789
+ allow: true,
4790
+ riskScore: 0,
4791
+ reasons: []
4792
+ };
4793
+ }
4794
+ };
4795
+
4796
+ // src/cce/sensors/cce-payload-decryption.sensor.ts
4797
+ var CcePayloadDecryptionSensor = class {
4798
+ constructor(keyProvider, aesProvider, maxPayloadBytes = 64 * 1024) {
4799
+ this.keyProvider = keyProvider;
4800
+ this.aesProvider = aesProvider;
4801
+ this.maxPayloadBytes = maxPayloadBytes;
4802
+ this.name = "cce.payload.decryption";
4803
+ this.order = 145;
4804
+ this.phase = "POST_DECODE";
4805
+ }
4806
+ supports(input) {
4807
+ return input.metadata?.cceEnvelopeValid === true && input.metadata?.cceClientSigVerified === true && input.metadata?.cceCapsuleVerified === true && input.metadata?.cceReplayClean === true;
4808
+ }
4809
+ async run(input) {
4810
+ const envelope = input.metadata?.cceEnvelope;
4811
+ if (!envelope) {
4812
+ return {
4813
+ allow: false,
4814
+ riskScore: 100,
4815
+ reasons: [CCE_ERROR.INVALID_ENVELOPE],
4816
+ code: CCE_ERROR.INVALID_ENVELOPE
4817
+ };
4818
+ }
4819
+ let aesKey;
4820
+ try {
4821
+ aesKey = await this.keyProvider.unwrapKey(
4822
+ envelope.encrypted_key.ciphertext,
4823
+ envelope.encrypted_key.alg,
4824
+ envelope.encrypted_key.axis_kid,
4825
+ envelope.encrypted_key.ephemeral_pk
4826
+ );
4827
+ } catch {
4828
+ return {
4829
+ allow: false,
4830
+ riskScore: 100,
4831
+ reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
4832
+ code: CCE_ERROR.KEY_UNWRAP_FAILED
4833
+ };
4834
+ }
4835
+ if (!aesKey) {
4836
+ return {
4837
+ allow: false,
4838
+ riskScore: 100,
4839
+ reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
4840
+ code: CCE_ERROR.KEY_UNWRAP_FAILED
4841
+ };
4842
+ }
4843
+ let iv;
4844
+ let ciphertext;
4845
+ let tag;
4846
+ try {
4847
+ iv = base64UrlDecode2(envelope.encrypted_payload.iv);
4848
+ ciphertext = base64UrlDecode2(envelope.encrypted_payload.ciphertext);
4849
+ tag = base64UrlDecode2(envelope.encrypted_payload.tag);
4850
+ } catch {
4851
+ return {
4852
+ allow: false,
4853
+ riskScore: 100,
4854
+ reasons: [`${CCE_ERROR.DECRYPTION_FAILED}: invalid base64url encoding`],
4855
+ code: CCE_ERROR.DECRYPTION_FAILED
4856
+ };
4857
+ }
4858
+ if (ciphertext.length > this.maxPayloadBytes) {
4859
+ return {
4860
+ allow: false,
4861
+ riskScore: 100,
4862
+ reasons: [
4863
+ `${CCE_ERROR.PAYLOAD_TOO_LARGE}: ${ciphertext.length} > ${this.maxPayloadBytes}`
4864
+ ],
4865
+ code: CCE_ERROR.PAYLOAD_TOO_LARGE
4866
+ };
4867
+ }
4868
+ const aad = buildAad(envelope);
4869
+ let plaintext;
4870
+ try {
4871
+ plaintext = await this.aesProvider.decrypt(
4872
+ aesKey,
4873
+ iv,
4874
+ ciphertext,
4875
+ tag,
4876
+ aad
4877
+ );
4878
+ } catch {
4879
+ plaintext = null;
4880
+ } finally {
4881
+ aesKey.fill(0);
4882
+ }
4883
+ if (!plaintext) {
4884
+ return {
4885
+ allow: false,
4886
+ riskScore: 100,
4887
+ reasons: [CCE_ERROR.AEAD_TAG_MISMATCH],
4888
+ code: CCE_ERROR.AEAD_TAG_MISMATCH
4889
+ };
4890
+ }
4891
+ input.metadata = input.metadata ?? {};
4892
+ input.metadata.cceDecryptedPayload = plaintext;
4893
+ input.metadata.cceDecryptionOk = true;
4894
+ return {
4895
+ decision: "ALLOW" /* ALLOW */,
4896
+ allow: true,
4897
+ riskScore: 0,
4898
+ reasons: []
4899
+ };
4900
+ }
4901
+ };
4902
+ function buildAad(envelope) {
4903
+ const parts = [
4904
+ envelope.ver,
4905
+ envelope.request_id,
4906
+ envelope.correlation_id,
4907
+ envelope.client_kid,
4908
+ envelope.capsule.capsule_id,
4909
+ envelope.capsule.intent,
4910
+ envelope.capsule.aud,
4911
+ envelope.request_nonce
4912
+ ];
4913
+ return new TextEncoder().encode(parts.join("|"));
4914
+ }
4915
+ function base64UrlDecode2(input) {
4916
+ const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
4917
+ const padding = "=".repeat((4 - base64.length % 4) % 4);
4918
+ const binary = atob(base64 + padding);
4919
+ const bytes2 = new Uint8Array(binary.length);
4920
+ for (let i = 0; i < binary.length; i++) {
4921
+ bytes2[i] = binary.charCodeAt(i);
4922
+ }
4923
+ return bytes2;
4924
+ }
4925
+
3558
4926
  // src/core/index.ts
3559
4927
  var core_exports = {};
3560
4928
  __export(core_exports, {
@@ -3636,7 +5004,7 @@ __export(core_exports, {
3636
5004
  encodeVarint: () => import_axis_protocol3.encodeVarint,
3637
5005
  generateEd25519KeyPair: () => generateEd25519KeyPair,
3638
5006
  getSignTarget: () => getSignTarget,
3639
- sha256: () => sha256,
5007
+ sha256: () => sha2564,
3640
5008
  signFrame: () => signFrame,
3641
5009
  varintLength: () => import_axis_protocol3.varintLength,
3642
5010
  verifyFrameSignature: () => verifyFrameSignature
@@ -3656,7 +5024,7 @@ __export(crypto_exports, {
3656
5024
 
3657
5025
  // src/crypto/proof-verification.service.ts
3658
5026
  var import_common10 = require("@nestjs/common");
3659
- var crypto3 = __toESM(require("crypto"));
5027
+ var crypto4 = __toESM(require("crypto"));
3660
5028
  var nacl = __toESM(require("tweetnacl"));
3661
5029
  var ProofVerificationService = class {
3662
5030
  constructor() {
@@ -3868,7 +5236,7 @@ var ProofVerificationService = class {
3868
5236
  certPem.replace(/-----BEGIN CERTIFICATE-----/, "").replace(/-----END CERTIFICATE-----/, "").replace(/\s/g, ""),
3869
5237
  "base64"
3870
5238
  );
3871
- return crypto3.createHash("sha256").update(der).digest("hex");
5239
+ return crypto4.createHash("sha256").update(der).digest("hex");
3872
5240
  }
3873
5241
  };
3874
5242
  ProofVerificationService = __decorateClass([
@@ -4681,7 +6049,7 @@ CapabilityEnforcementSensor = __decorateClass([
4681
6049
 
4682
6050
  // src/sensors/chunk-hash.sensor.ts
4683
6051
  var import_common15 = require("@nestjs/common");
4684
- var import_crypto6 = require("crypto");
6052
+ var import_crypto8 = require("crypto");
4685
6053
  var ChunkHashSensor = class {
4686
6054
  constructor() {
4687
6055
  /** Sensor identifier */
@@ -4740,7 +6108,7 @@ var ChunkHashSensor = class {
4740
6108
  reason: "Missing sha256Chunk TLV in header"
4741
6109
  };
4742
6110
  }
4743
- const actual = (0, import_crypto6.createHash)("sha256").update(bodyBytes).digest();
6111
+ const actual = (0, import_crypto8.createHash)("sha256").update(bodyBytes).digest();
4744
6112
  if (!Buffer.from(actual).equals(Buffer.from(expected))) {
4745
6113
  return {
4746
6114
  action: "DENY",
@@ -4758,7 +6126,7 @@ ChunkHashSensor = __decorateClass([
4758
6126
 
4759
6127
  // src/sensors/entropy.sensor.ts
4760
6128
  var import_common16 = require("@nestjs/common");
4761
- var crypto4 = __toESM(require("crypto"));
6129
+ var crypto5 = __toESM(require("crypto"));
4762
6130
  var EntropySensor = class {
4763
6131
  constructor() {
4764
6132
  this.logger = new import_common16.Logger(EntropySensor.name);
@@ -4926,7 +6294,7 @@ var EntropySensor = class {
4926
6294
  * @returns {Uint8Array} Cryptographically secure random bytes
4927
6295
  */
4928
6296
  static generateSecureRandom(length) {
4929
- return new Uint8Array(crypto4.randomBytes(length));
6297
+ return new Uint8Array(crypto5.randomBytes(length));
4930
6298
  }
4931
6299
  };
4932
6300
  EntropySensor = __decorateClass([
@@ -6070,6 +7438,9 @@ function toBuffer(value) {
6070
7438
  BAND,
6071
7439
  BodyProfile,
6072
7440
  CAPABILITIES,
7441
+ CCE_ERROR,
7442
+ CCE_PROTOCOL_VERSION,
7443
+ CceError,
6073
7444
  ContractViolationError,
6074
7445
  DEFAULT_CONTRACTS,
6075
7446
  DEFAULT_TIMEOUT,
@@ -6196,6 +7567,7 @@ function toBuffer(value) {
6196
7567
  canonicalJson,
6197
7568
  canonicalJsonExcluding,
6198
7569
  canonicalizeObservation,
7570
+ cce,
6199
7571
  classifyIntent,
6200
7572
  computeReceiptHash,
6201
7573
  computeSignaturePayload,
@@ -6219,6 +7591,7 @@ function toBuffer(value) {
6219
7591
  encodeVarint,
6220
7592
  endStage,
6221
7593
  engine,
7594
+ executeCcePipeline,
6222
7595
  extractDtoSchema,
6223
7596
  finalizeObservation,
6224
7597
  generateEd25519KeyPair,