@nextera.one/axis-server-sdk 1.4.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/core/index.d.mts +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/{index-B5xzROld.d.mts → index-1uEwnW-w.d.mts} +1 -1
- package/dist/{index-B5xzROld.d.ts → index-1uEwnW-w.d.ts} +1 -1
- package/dist/index.d.mts +1063 -532
- package/dist/index.d.ts +1063 -532
- package/dist/index.js +2257 -688
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2204 -660
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -47,16 +47,26 @@ __export(index_exports, {
|
|
|
47
47
|
AXIS_UPLOAD_SESSION_STORE: () => AXIS_UPLOAD_SESSION_STORE,
|
|
48
48
|
AXIS_VERSION: () => import_axis_protocol2.AXIS_VERSION,
|
|
49
49
|
Ats1Codec: () => ats1_exports,
|
|
50
|
+
AxisContext: () => AxisContext,
|
|
51
|
+
AxisDemoPubkey: () => AxisDemoPubkey,
|
|
52
|
+
AxisError: () => AxisError,
|
|
50
53
|
AxisFilesDownloadHandler: () => AxisFilesDownloadHandler,
|
|
51
54
|
AxisFilesFinalizeHandler: () => AxisFilesFinalizeHandler,
|
|
52
55
|
AxisFrameZ: () => AxisFrameZ,
|
|
53
56
|
AxisIdDto: () => AxisIdDto,
|
|
57
|
+
AxisIp: () => AxisIp,
|
|
54
58
|
AxisPacketTags: () => T,
|
|
55
59
|
AxisPartialType: () => AxisPartialType,
|
|
60
|
+
AxisRaw: () => AxisRaw,
|
|
56
61
|
AxisResponseDto: () => AxisResponseDto,
|
|
62
|
+
AxisSensorChainService: () => AxisSensorChainService,
|
|
57
63
|
AxisTlvDto: () => AxisTlvDto,
|
|
64
|
+
BAND: () => BAND,
|
|
58
65
|
BodyProfile: () => import_axis_protocol2.BodyProfile,
|
|
59
66
|
CAPABILITIES: () => CAPABILITIES,
|
|
67
|
+
CCE_ERROR: () => CCE_ERROR,
|
|
68
|
+
CCE_PROTOCOL_VERSION: () => CCE_PROTOCOL_VERSION,
|
|
69
|
+
CceError: () => CceError,
|
|
60
70
|
ContractViolationError: () => ContractViolationError,
|
|
61
71
|
DEFAULT_CONTRACTS: () => DEFAULT_CONTRACTS,
|
|
62
72
|
DEFAULT_TIMEOUT: () => DEFAULT_TIMEOUT,
|
|
@@ -72,7 +82,10 @@ __export(index_exports, {
|
|
|
72
82
|
FLAG_CHAIN_REQ: () => import_axis_protocol2.FLAG_CHAIN_REQ,
|
|
73
83
|
FLAG_HAS_WITNESS: () => import_axis_protocol2.FLAG_HAS_WITNESS,
|
|
74
84
|
HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
|
|
85
|
+
HANDLER_SENSORS_KEY: () => HANDLER_SENSORS_KEY,
|
|
75
86
|
Handler: () => Handler,
|
|
87
|
+
HandlerDiscoveryService: () => HandlerDiscoveryService,
|
|
88
|
+
HandlerSensors: () => HandlerSensors,
|
|
76
89
|
INTENT_BODY_KEY: () => INTENT_BODY_KEY,
|
|
77
90
|
INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
|
|
78
91
|
INTENT_REQUIREMENTS: () => INTENT_REQUIREMENTS,
|
|
@@ -99,6 +112,7 @@ __export(index_exports, {
|
|
|
99
112
|
NCERT_PUB: () => import_axis_protocol2.NCERT_PUB,
|
|
100
113
|
NCERT_SCOPE: () => import_axis_protocol2.NCERT_SCOPE,
|
|
101
114
|
NCERT_SIG: () => import_axis_protocol2.NCERT_SIG,
|
|
115
|
+
PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
|
|
102
116
|
PROOF_CAPABILITIES: () => PROOF_CAPABILITIES,
|
|
103
117
|
PROOF_CAPSULE: () => import_axis_protocol2.PROOF_CAPSULE,
|
|
104
118
|
PROOF_JWT: () => import_axis_protocol2.PROOF_JWT,
|
|
@@ -113,11 +127,15 @@ __export(index_exports, {
|
|
|
113
127
|
RESPONSE_TAG_UPDATED_AT: () => RESPONSE_TAG_UPDATED_AT,
|
|
114
128
|
RESPONSE_TAG_UPDATED_BY: () => RESPONSE_TAG_UPDATED_BY,
|
|
115
129
|
RiskDecision: () => RiskDecision,
|
|
130
|
+
SENSOR_METADATA_KEY: () => SENSOR_METADATA_KEY,
|
|
116
131
|
Schema2002_PasskeyLoginOptionsRes: () => Schema2002_PasskeyLoginOptionsRes,
|
|
117
132
|
Schema2011_PasskeyLoginVerifyReq: () => Schema2011_PasskeyLoginVerifyReq,
|
|
118
133
|
Schema2012_PasskeyLoginVerifyRes: () => Schema2012_PasskeyLoginVerifyRes,
|
|
119
134
|
Schema2021_PasskeyRegisterOptionsReq: () => Schema2021_PasskeyRegisterOptionsReq,
|
|
135
|
+
Sensor: () => Sensor,
|
|
120
136
|
SensorDecisions: () => SensorDecisions,
|
|
137
|
+
SensorDiscoveryService: () => SensorDiscoveryService,
|
|
138
|
+
SensorRegistry: () => SensorRegistry,
|
|
121
139
|
TLV: () => import_axis_protocol.TLV,
|
|
122
140
|
TLV_ACTOR_ID: () => import_axis_protocol2.TLV_ACTOR_ID,
|
|
123
141
|
TLV_AUD: () => import_axis_protocol2.TLV_AUD,
|
|
@@ -175,10 +193,12 @@ __export(index_exports, {
|
|
|
175
193
|
canonicalJson: () => canonicalJson,
|
|
176
194
|
canonicalJsonExcluding: () => canonicalJsonExcluding,
|
|
177
195
|
canonicalizeObservation: () => canonicalizeObservation,
|
|
196
|
+
cce: () => cce_exports,
|
|
178
197
|
classifyIntent: () => classifyIntent,
|
|
179
198
|
computeReceiptHash: () => computeReceiptHash,
|
|
180
199
|
computeSignaturePayload: () => computeSignaturePayload,
|
|
181
200
|
core: () => core_exports,
|
|
201
|
+
createObservation: () => createObservation,
|
|
182
202
|
crypto: () => crypto_exports,
|
|
183
203
|
decodeArray: () => import_axis_protocol.decodeArray,
|
|
184
204
|
decodeAxis1Frame: () => decodeAxis1Frame,
|
|
@@ -195,8 +215,11 @@ __export(index_exports, {
|
|
|
195
215
|
encodeQueueMessage: () => encodeQueueMessage,
|
|
196
216
|
encodeTLVs: () => import_axis_protocol.encodeTLVs,
|
|
197
217
|
encodeVarint: () => import_axis_protocol3.encodeVarint,
|
|
218
|
+
endStage: () => endStage,
|
|
198
219
|
engine: () => engine_exports,
|
|
220
|
+
executeCcePipeline: () => executeCcePipeline,
|
|
199
221
|
extractDtoSchema: () => extractDtoSchema,
|
|
222
|
+
finalizeObservation: () => finalizeObservation,
|
|
200
223
|
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
201
224
|
getSignTarget: () => getSignTarget,
|
|
202
225
|
hasScope: () => hasScope,
|
|
@@ -215,14 +238,16 @@ __export(index_exports, {
|
|
|
215
238
|
parseAutoClaimEntries: () => parseAutoClaimEntries,
|
|
216
239
|
parseScope: () => parseScope,
|
|
217
240
|
parseStreamEntries: () => parseStreamEntries,
|
|
241
|
+
recordSensor: () => recordSensor,
|
|
218
242
|
resolveTimeout: () => resolveTimeout,
|
|
219
243
|
schemas: () => schemas_exports,
|
|
220
244
|
security: () => security_exports,
|
|
221
245
|
sensitivityName: () => sensitivityName,
|
|
222
246
|
sensors: () => sensors_exports,
|
|
223
|
-
sha256: () =>
|
|
247
|
+
sha256: () => sha2564,
|
|
224
248
|
signFrame: () => signFrame,
|
|
225
249
|
stableJsonStringify: () => stableJsonStringify,
|
|
250
|
+
startStage: () => startStage,
|
|
226
251
|
tlv: () => tlv,
|
|
227
252
|
u64be: () => u64be,
|
|
228
253
|
unpackPasskeyLoginOptionsReq: () => unpackPasskeyLoginOptionsReq,
|
|
@@ -293,8 +318,24 @@ function IntentSensors(sensors) {
|
|
|
293
318
|
};
|
|
294
319
|
}
|
|
295
320
|
|
|
296
|
-
// src/decorators/
|
|
321
|
+
// src/decorators/handler-sensors.decorator.ts
|
|
297
322
|
var import_reflect_metadata4 = require("reflect-metadata");
|
|
323
|
+
var HANDLER_SENSORS_KEY = "axis:handler:sensors";
|
|
324
|
+
function HandlerSensors(sensors) {
|
|
325
|
+
return (target) => {
|
|
326
|
+
Reflect.defineMetadata(HANDLER_SENSORS_KEY, sensors, target);
|
|
327
|
+
};
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// src/decorators/sensor.decorator.ts
|
|
331
|
+
var import_common2 = require("@nestjs/common");
|
|
332
|
+
var SENSOR_METADATA_KEY = "axis:sensor";
|
|
333
|
+
function Sensor(options) {
|
|
334
|
+
return (0, import_common2.SetMetadata)(SENSOR_METADATA_KEY, options ?? true);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
// src/decorators/tlv-field.decorator.ts
|
|
338
|
+
var import_reflect_metadata5 = require("reflect-metadata");
|
|
298
339
|
var TLV_FIELDS_KEY = "axis:tlv:fields";
|
|
299
340
|
var TLV_VALIDATORS_KEY = "axis:tlv:validators";
|
|
300
341
|
function TlvField(tag, options) {
|
|
@@ -352,7 +393,7 @@ function TlvRange(min, max, message) {
|
|
|
352
393
|
}
|
|
353
394
|
|
|
354
395
|
// src/decorators/dto-schema.util.ts
|
|
355
|
-
var
|
|
396
|
+
var import_reflect_metadata6 = require("reflect-metadata");
|
|
356
397
|
|
|
357
398
|
// src/core/tlv.ts
|
|
358
399
|
var import_axis_protocol = require("@nextera.one/axis-protocol");
|
|
@@ -453,7 +494,7 @@ __decorateClass([
|
|
|
453
494
|
], AxisIdDto.prototype, "id", 2);
|
|
454
495
|
|
|
455
496
|
// src/base/axis-partial-type.ts
|
|
456
|
-
var
|
|
497
|
+
var import_reflect_metadata7 = require("reflect-metadata");
|
|
457
498
|
function AxisPartialType(BaseDto) {
|
|
458
499
|
class PartialDto extends BaseDto {
|
|
459
500
|
}
|
|
@@ -499,7 +540,7 @@ __decorateClass([
|
|
|
499
540
|
], AxisResponseDto.prototype, "updated_by", 2);
|
|
500
541
|
|
|
501
542
|
// src/engine/intent.router.ts
|
|
502
|
-
var
|
|
543
|
+
var import_common3 = require("@nestjs/common");
|
|
503
544
|
|
|
504
545
|
// src/sensor/axis-sensor.ts
|
|
505
546
|
var Decision = /* @__PURE__ */ ((Decision2) => {
|
|
@@ -600,11 +641,631 @@ var SensorDecisions = {
|
|
|
600
641
|
}
|
|
601
642
|
};
|
|
602
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
|
+
|
|
603
1264
|
// src/engine/intent.router.ts
|
|
604
1265
|
var IntentRouter = class {
|
|
605
1266
|
constructor(moduleRef) {
|
|
606
1267
|
this.moduleRef = moduleRef;
|
|
607
|
-
this.logger = new
|
|
1268
|
+
this.logger = new import_common3.Logger(IntentRouter.name);
|
|
608
1269
|
/** Internal registry of dynamic intent handlers */
|
|
609
1270
|
this.handlers = /* @__PURE__ */ new Map();
|
|
610
1271
|
/** Per-intent sensor classes (resolved at call time) */
|
|
@@ -617,6 +1278,10 @@ var IntentRouter = class {
|
|
|
617
1278
|
this.intentValidators = /* @__PURE__ */ new Map();
|
|
618
1279
|
/** Per-intent operation kind */
|
|
619
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;
|
|
620
1285
|
}
|
|
621
1286
|
getSchema(intent) {
|
|
622
1287
|
return this.intentSchemas.get(intent);
|
|
@@ -666,6 +1331,7 @@ var IntentRouter = class {
|
|
|
666
1331
|
);
|
|
667
1332
|
const prefix = handlerMeta?.intent || instance.name;
|
|
668
1333
|
const routes = Reflect.getMetadata(INTENT_ROUTES_KEY, instance.constructor) || [];
|
|
1334
|
+
const handlerSensors = Reflect.getMetadata(HANDLER_SENSORS_KEY, instance.constructor) || [];
|
|
669
1335
|
for (const route of routes) {
|
|
670
1336
|
const intentName = route.absolute ? route.action : `${prefix}.${route.action}`;
|
|
671
1337
|
const fn = instance[route.methodName].bind(instance);
|
|
@@ -674,7 +1340,12 @@ var IntentRouter = class {
|
|
|
674
1340
|
} else {
|
|
675
1341
|
this.register(intentName, fn);
|
|
676
1342
|
}
|
|
677
|
-
this.registerIntentMeta(
|
|
1343
|
+
this.registerIntentMeta(
|
|
1344
|
+
intentName,
|
|
1345
|
+
Object.getPrototypeOf(instance),
|
|
1346
|
+
String(route.methodName),
|
|
1347
|
+
handlerSensors
|
|
1348
|
+
);
|
|
678
1349
|
}
|
|
679
1350
|
const proto = Object.getPrototypeOf(instance);
|
|
680
1351
|
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
@@ -683,7 +1354,7 @@ var IntentRouter = class {
|
|
|
683
1354
|
if (!this.handlers.has(meta.intent)) {
|
|
684
1355
|
this.register(meta.intent, instance[key].bind(instance));
|
|
685
1356
|
}
|
|
686
|
-
this.registerIntentMeta(meta.intent, proto, key);
|
|
1357
|
+
this.registerIntentMeta(meta.intent, proto, key, handlerSensors);
|
|
687
1358
|
}
|
|
688
1359
|
}
|
|
689
1360
|
/**
|
|
@@ -819,14 +1490,22 @@ var IntentRouter = class {
|
|
|
819
1490
|
this.logger.warn(`${intent} failed in ${ms}ms - ${error}`);
|
|
820
1491
|
}
|
|
821
1492
|
}
|
|
822
|
-
registerIntentMeta(intent, proto, methodName) {
|
|
1493
|
+
registerIntentMeta(intent, proto, methodName, handlerSensors) {
|
|
823
1494
|
const decoder = Reflect.getMetadata(INTENT_BODY_KEY, proto, methodName);
|
|
824
1495
|
if (decoder) {
|
|
825
1496
|
this.intentDecoders.set(intent, decoder);
|
|
826
1497
|
}
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
1498
|
+
const intentSensors = Reflect.getMetadata(
|
|
1499
|
+
INTENT_SENSORS_KEY,
|
|
1500
|
+
proto,
|
|
1501
|
+
methodName
|
|
1502
|
+
);
|
|
1503
|
+
const combined = [
|
|
1504
|
+
...handlerSensors || [],
|
|
1505
|
+
...Array.isArray(intentSensors) ? intentSensors : []
|
|
1506
|
+
];
|
|
1507
|
+
if (combined.length > 0) {
|
|
1508
|
+
this.intentSensors.set(intent, combined);
|
|
830
1509
|
}
|
|
831
1510
|
const meta = Reflect.getMetadata(INTENT_METADATA_KEY, proto, methodName);
|
|
832
1511
|
if (meta) {
|
|
@@ -866,6 +1545,58 @@ var IntentRouter = class {
|
|
|
866
1545
|
}
|
|
867
1546
|
}
|
|
868
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
|
+
}
|
|
869
1600
|
storeSchema(meta) {
|
|
870
1601
|
if (meta.dto) {
|
|
871
1602
|
if (meta.tlv && meta.tlv.length > 0) {
|
|
@@ -925,10 +1656,27 @@ IntentRouter.BUILTIN_INTENTS = /* @__PURE__ */ new Set([
|
|
|
925
1656
|
"axis.intent.exec"
|
|
926
1657
|
]);
|
|
927
1658
|
IntentRouter = __decorateClass([
|
|
928
|
-
(0,
|
|
929
|
-
__decorateParam(0, (0,
|
|
1659
|
+
(0, import_common3.Injectable)(),
|
|
1660
|
+
__decorateParam(0, (0, import_common3.Optional)())
|
|
930
1661
|
], IntentRouter);
|
|
931
1662
|
|
|
1663
|
+
// src/engine/sensor-bands.ts
|
|
1664
|
+
var BAND = {
|
|
1665
|
+
/** Pre-decode: raw byte validation, geo, budget, magic */
|
|
1666
|
+
WIRE: 0,
|
|
1667
|
+
/** Post-decode: identity resolution, capsule, proof */
|
|
1668
|
+
IDENTITY: 40,
|
|
1669
|
+
/** Post-decode: authorization, signature, rate limiting */
|
|
1670
|
+
POLICY: 90,
|
|
1671
|
+
/** Post-decode: content validation, TLV, schema, files */
|
|
1672
|
+
CONTENT: 140,
|
|
1673
|
+
/** Post-decode: business logic sensors, streams, WS */
|
|
1674
|
+
BUSINESS: 200,
|
|
1675
|
+
/** Post-decode: audit, logging (always last) */
|
|
1676
|
+
AUDIT: 900
|
|
1677
|
+
};
|
|
1678
|
+
var PRE_DECODE_BOUNDARY = 40;
|
|
1679
|
+
|
|
932
1680
|
// src/engine/observation/stable-json.ts
|
|
933
1681
|
function normalize(value) {
|
|
934
1682
|
if (Array.isArray(value)) {
|
|
@@ -1028,7 +1776,7 @@ function fieldsToMap(fields) {
|
|
|
1028
1776
|
}
|
|
1029
1777
|
|
|
1030
1778
|
// src/engine/observation/observation-hash.ts
|
|
1031
|
-
var
|
|
1779
|
+
var import_crypto3 = require("crypto");
|
|
1032
1780
|
function canonicalizeObservation(obs) {
|
|
1033
1781
|
const obj = {
|
|
1034
1782
|
id: obs.id,
|
|
@@ -1065,7 +1813,7 @@ function canonicalizeObservation(obs) {
|
|
|
1065
1813
|
}
|
|
1066
1814
|
function hashObservation(obs) {
|
|
1067
1815
|
const canonical = canonicalizeObservation(obs);
|
|
1068
|
-
return (0,
|
|
1816
|
+
return (0, import_crypto3.createHash)("sha256").update(canonical).digest("hex");
|
|
1069
1817
|
}
|
|
1070
1818
|
function buildUnsignedWitness(obs) {
|
|
1071
1819
|
if (!obs.decision || !obs.endMs) {
|
|
@@ -1140,7 +1888,7 @@ function verifyResponse(ctx, response) {
|
|
|
1140
1888
|
var import_axis_protocol3 = require("@nextera.one/axis-protocol");
|
|
1141
1889
|
|
|
1142
1890
|
// src/core/signature.ts
|
|
1143
|
-
var
|
|
1891
|
+
var crypto2 = __toESM(require("crypto"));
|
|
1144
1892
|
|
|
1145
1893
|
// src/core/axis-bin.ts
|
|
1146
1894
|
var z = __toESM(require("zod"));
|
|
@@ -1270,19 +2018,19 @@ function signFrame(frame, privateKey) {
|
|
|
1270
2018
|
32
|
|
1271
2019
|
]);
|
|
1272
2020
|
const pkcs8Key = Buffer.concat([pkcs8Prefix, privateKey]);
|
|
1273
|
-
keyObject =
|
|
2021
|
+
keyObject = crypto2.createPrivateKey({
|
|
1274
2022
|
key: pkcs8Key,
|
|
1275
2023
|
format: "der",
|
|
1276
2024
|
type: "pkcs8"
|
|
1277
2025
|
});
|
|
1278
2026
|
} else {
|
|
1279
|
-
keyObject =
|
|
2027
|
+
keyObject = crypto2.createPrivateKey({
|
|
1280
2028
|
key: privateKey,
|
|
1281
2029
|
format: "der",
|
|
1282
2030
|
type: "pkcs8"
|
|
1283
2031
|
});
|
|
1284
2032
|
}
|
|
1285
|
-
const signature =
|
|
2033
|
+
const signature = crypto2.sign(null, payload, keyObject);
|
|
1286
2034
|
if (signature.length !== 64) {
|
|
1287
2035
|
throw new Error("Ed25519 signature must be 64 bytes");
|
|
1288
2036
|
}
|
|
@@ -1314,19 +2062,19 @@ function verifyFrameSignature(frame, publicKey) {
|
|
|
1314
2062
|
0
|
|
1315
2063
|
]);
|
|
1316
2064
|
const spkiKey = Buffer.concat([spkiPrefix, publicKey]);
|
|
1317
|
-
keyObject =
|
|
2065
|
+
keyObject = crypto2.createPublicKey({
|
|
1318
2066
|
key: spkiKey,
|
|
1319
2067
|
format: "der",
|
|
1320
2068
|
type: "spki"
|
|
1321
2069
|
});
|
|
1322
2070
|
} else {
|
|
1323
|
-
keyObject =
|
|
2071
|
+
keyObject = crypto2.createPublicKey({
|
|
1324
2072
|
key: publicKey,
|
|
1325
2073
|
format: "der",
|
|
1326
2074
|
type: "spki"
|
|
1327
2075
|
});
|
|
1328
2076
|
}
|
|
1329
|
-
const valid =
|
|
2077
|
+
const valid = crypto2.verify(
|
|
1330
2078
|
null,
|
|
1331
2079
|
payload,
|
|
1332
2080
|
keyObject,
|
|
@@ -1338,17 +2086,17 @@ function verifyFrameSignature(frame, publicKey) {
|
|
|
1338
2086
|
}
|
|
1339
2087
|
}
|
|
1340
2088
|
function generateEd25519KeyPair() {
|
|
1341
|
-
const { privateKey, publicKey } =
|
|
2089
|
+
const { privateKey, publicKey } = crypto2.generateKeyPairSync("ed25519");
|
|
1342
2090
|
return {
|
|
1343
2091
|
privateKey: privateKey.export({ type: "pkcs8", format: "der" }),
|
|
1344
2092
|
publicKey: publicKey.export({ type: "spki", format: "der" })
|
|
1345
2093
|
};
|
|
1346
2094
|
}
|
|
1347
|
-
function
|
|
1348
|
-
return
|
|
2095
|
+
function sha2564(data) {
|
|
2096
|
+
return crypto2.createHash("sha256").update(data).digest();
|
|
1349
2097
|
}
|
|
1350
2098
|
function computeReceiptHash(receiptBytes, prevHash) {
|
|
1351
|
-
const hasher =
|
|
2099
|
+
const hasher = crypto2.createHash("sha256");
|
|
1352
2100
|
hasher.update(receiptBytes);
|
|
1353
2101
|
if (prevHash && prevHash.length > 0) {
|
|
1354
2102
|
hasher.update(prevHash);
|
|
@@ -1406,12 +2154,12 @@ __export(ats1_exports, {
|
|
|
1406
2154
|
encodeU64BE: () => encodeU64BE,
|
|
1407
2155
|
encodeUVarint: () => encodeUVarint,
|
|
1408
2156
|
logicalBodyToTLVs: () => logicalBodyToTLVs,
|
|
1409
|
-
sha256: () =>
|
|
2157
|
+
sha256: () => sha2565,
|
|
1410
2158
|
tlvsToLogicalBody: () => tlvsToLogicalBody,
|
|
1411
2159
|
tlvsToMap: () => tlvsToMap,
|
|
1412
2160
|
validateTLVsAgainstSchema: () => validateTLVsAgainstSchema
|
|
1413
2161
|
});
|
|
1414
|
-
var
|
|
2162
|
+
var import_crypto4 = require("crypto");
|
|
1415
2163
|
var DEFAULT_LIMITS = {
|
|
1416
2164
|
maxVarintBytes: 10,
|
|
1417
2165
|
maxTlvCount: 512,
|
|
@@ -1460,8 +2208,8 @@ function decodeU64BE(buf) {
|
|
|
1460
2208
|
if (buf.length !== 8) throw new Error("decodeU64BE: length must be 8");
|
|
1461
2209
|
return buf.readBigUInt64BE(0);
|
|
1462
2210
|
}
|
|
1463
|
-
function
|
|
1464
|
-
return (0,
|
|
2211
|
+
function sha2565(data) {
|
|
2212
|
+
return (0, import_crypto4.createHash)("sha256").update(data).digest();
|
|
1465
2213
|
}
|
|
1466
2214
|
function encodeTLV(tag, value) {
|
|
1467
2215
|
if (!Number.isInteger(tag) || tag <= 0)
|
|
@@ -1777,7 +2525,7 @@ function decodeAxisHeaderFromTLVs(hdrTlvs, limits = DEFAULT_LIMITS) {
|
|
|
1777
2525
|
function encodeAxisRequestBinary(schema, req, limits = DEFAULT_LIMITS) {
|
|
1778
2526
|
const bodyTlvs = logicalBodyToTLVs(schema, req.body, limits);
|
|
1779
2527
|
const bodyBytes = encodeTLVStreamCanonical(bodyTlvs);
|
|
1780
|
-
const bodyHash =
|
|
2528
|
+
const bodyHash = sha2565(bodyBytes);
|
|
1781
2529
|
const hdr = {
|
|
1782
2530
|
...req.hdr,
|
|
1783
2531
|
schemaId: schema.schemaId,
|
|
@@ -1793,7 +2541,7 @@ function decodeAxisRequestBinary(schema, hdrBytes, bodyBytes, limits = DEFAULT_L
|
|
|
1793
2541
|
const hdr = decodeAxisHeaderFromTLVs(hdrTlvs, limits);
|
|
1794
2542
|
if (hdr.schemaId !== schema.schemaId)
|
|
1795
2543
|
throw new Error("decodeAxisRequestBinary: schemaId mismatch");
|
|
1796
|
-
const bh =
|
|
2544
|
+
const bh = sha2565(bodyBytes);
|
|
1797
2545
|
if (!Buffer.from(hdr.bodyHash).equals(bh))
|
|
1798
2546
|
throw new Error("decodeAxisRequestBinary: body_hash mismatch");
|
|
1799
2547
|
const body = tlvsToLogicalBody(schema, bodyTlvs, limits);
|
|
@@ -1866,7 +2614,7 @@ function packPasskeyLoginOptionsReq(params) {
|
|
|
1866
2614
|
}
|
|
1867
2615
|
);
|
|
1868
2616
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
1869
|
-
const bodyHash =
|
|
2617
|
+
const bodyHash = sha2565(body);
|
|
1870
2618
|
const hdr = buildAts1Hdr({
|
|
1871
2619
|
intentId: params.intentId,
|
|
1872
2620
|
schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_OPTIONS_REQ,
|
|
@@ -1935,7 +2683,7 @@ function packPasskeyRegisterOptionsReq(params) {
|
|
|
1935
2683
|
}
|
|
1936
2684
|
);
|
|
1937
2685
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
1938
|
-
const bodyHash =
|
|
2686
|
+
const bodyHash = sha2565(body);
|
|
1939
2687
|
const hdr = buildAts1Hdr({
|
|
1940
2688
|
intentId: params.intentId,
|
|
1941
2689
|
schemaId: ATS1_SCHEMA.PASSKEY_REGISTER_OPTIONS_REQ,
|
|
@@ -1966,7 +2714,7 @@ function packPasskeyLoginVerifyReq(params) {
|
|
|
1966
2714
|
}
|
|
1967
2715
|
});
|
|
1968
2716
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
1969
|
-
const bodyHash =
|
|
2717
|
+
const bodyHash = sha2565(body);
|
|
1970
2718
|
const hdr = buildAts1Hdr({
|
|
1971
2719
|
intentId: params.intentId,
|
|
1972
2720
|
schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_VERIFY_REQ,
|
|
@@ -2050,7 +2798,7 @@ function packPasskeyLoginVerifyRes(params) {
|
|
|
2050
2798
|
}
|
|
2051
2799
|
|
|
2052
2800
|
// src/codec/tlv.encode.ts
|
|
2053
|
-
var
|
|
2801
|
+
var import_crypto5 = require("crypto");
|
|
2054
2802
|
function encVarint(x) {
|
|
2055
2803
|
if (x < 0n) throw new Error("VARINT_NEG");
|
|
2056
2804
|
const out = [];
|
|
@@ -2078,7 +2826,7 @@ function bytes(b) {
|
|
|
2078
2826
|
return Buffer.isBuffer(b) ? b : Buffer.from(b);
|
|
2079
2827
|
}
|
|
2080
2828
|
function nonce16() {
|
|
2081
|
-
return (0,
|
|
2829
|
+
return (0, import_crypto5.randomBytes)(16);
|
|
2082
2830
|
}
|
|
2083
2831
|
function tlv(type, value) {
|
|
2084
2832
|
if (!Number.isSafeInteger(type) || type < 0) throw new Error("TLV_BAD_TYPE");
|
|
@@ -2624,9 +3372,9 @@ function isAdminOpcode(op) {
|
|
|
2624
3372
|
}
|
|
2625
3373
|
|
|
2626
3374
|
// src/core/receipt.ts
|
|
2627
|
-
var
|
|
3375
|
+
var import_crypto6 = require("crypto");
|
|
2628
3376
|
function buildReceiptHash(prevHash, pid, actorId, intent, effect, ts) {
|
|
2629
|
-
const h = (0,
|
|
3377
|
+
const h = (0, import_crypto6.createHash)("sha256");
|
|
2630
3378
|
if (prevHash) h.update(prevHash);
|
|
2631
3379
|
h.update(pid);
|
|
2632
3380
|
h.update(Buffer.from(actorId, "utf8"));
|
|
@@ -2805,8 +3553,8 @@ function isTimestampValid(ts, skewSeconds = 120) {
|
|
|
2805
3553
|
}
|
|
2806
3554
|
|
|
2807
3555
|
// src/upload/axis-files.handlers.ts
|
|
2808
|
-
var
|
|
2809
|
-
var
|
|
3556
|
+
var import_common4 = require("@nestjs/common");
|
|
3557
|
+
var crypto3 = __toESM(require("crypto"));
|
|
2810
3558
|
|
|
2811
3559
|
// src/upload/upload.tokens.ts
|
|
2812
3560
|
var AXIS_UPLOAD_SESSION_STORE = "AXIS_UPLOAD_SESSION_STORE";
|
|
@@ -2818,7 +3566,7 @@ var AxisFilesDownloadHandler = class {
|
|
|
2818
3566
|
constructor(sessions, files) {
|
|
2819
3567
|
this.sessions = sessions;
|
|
2820
3568
|
this.files = files;
|
|
2821
|
-
this.logger = new
|
|
3569
|
+
this.logger = new import_common4.Logger(AxisFilesDownloadHandler.name);
|
|
2822
3570
|
this.name = "axis.files.download";
|
|
2823
3571
|
this.open = true;
|
|
2824
3572
|
this.description = "File download handler";
|
|
@@ -2883,16 +3631,16 @@ __decorateClass([
|
|
|
2883
3631
|
], AxisFilesDownloadHandler.prototype, "execute", 1);
|
|
2884
3632
|
AxisFilesDownloadHandler = __decorateClass([
|
|
2885
3633
|
Handler("axis.files.download"),
|
|
2886
|
-
(0,
|
|
2887
|
-
__decorateParam(0, (0,
|
|
2888
|
-
__decorateParam(1, (0,
|
|
3634
|
+
(0, import_common4.Injectable)(),
|
|
3635
|
+
__decorateParam(0, (0, import_common4.Inject)(AXIS_UPLOAD_SESSION_STORE)),
|
|
3636
|
+
__decorateParam(1, (0, import_common4.Inject)(AXIS_UPLOAD_FILE_STORE))
|
|
2889
3637
|
], AxisFilesDownloadHandler);
|
|
2890
3638
|
var AxisFilesFinalizeHandler = class {
|
|
2891
3639
|
constructor(sessions, files, keyring) {
|
|
2892
3640
|
this.sessions = sessions;
|
|
2893
3641
|
this.files = files;
|
|
2894
3642
|
this.keyring = keyring;
|
|
2895
|
-
this.logger = new
|
|
3643
|
+
this.logger = new import_common4.Logger(AxisFilesFinalizeHandler.name);
|
|
2896
3644
|
this.name = "axis.files.finalize";
|
|
2897
3645
|
this.open = false;
|
|
2898
3646
|
this.description = "File upload finalization handler";
|
|
@@ -2907,7 +3655,7 @@ var AxisFilesFinalizeHandler = class {
|
|
|
2907
3655
|
if (!await this.files.hasTemp(fileId)) {
|
|
2908
3656
|
throw new Error("CHUNKS_NOT_FOUND");
|
|
2909
3657
|
}
|
|
2910
|
-
const hash =
|
|
3658
|
+
const hash = crypto3.createHash("sha256");
|
|
2911
3659
|
const rs = this.files.createTempReadStream(fileId);
|
|
2912
3660
|
for await (const chunk of rs) {
|
|
2913
3661
|
hash.update(chunk);
|
|
@@ -2968,11 +3716,11 @@ __decorateClass([
|
|
|
2968
3716
|
], AxisFilesFinalizeHandler.prototype, "execute", 1);
|
|
2969
3717
|
AxisFilesFinalizeHandler = __decorateClass([
|
|
2970
3718
|
Handler("axis.files.finalize"),
|
|
2971
|
-
(0,
|
|
2972
|
-
__decorateParam(0, (0,
|
|
2973
|
-
__decorateParam(1, (0,
|
|
2974
|
-
__decorateParam(2, (0,
|
|
2975
|
-
__decorateParam(2, (0,
|
|
3719
|
+
(0, import_common4.Injectable)(),
|
|
3720
|
+
__decorateParam(0, (0, import_common4.Inject)(AXIS_UPLOAD_SESSION_STORE)),
|
|
3721
|
+
__decorateParam(1, (0, import_common4.Inject)(AXIS_UPLOAD_FILE_STORE)),
|
|
3722
|
+
__decorateParam(2, (0, import_common4.Optional)()),
|
|
3723
|
+
__decorateParam(2, (0, import_common4.Inject)(AXIS_UPLOAD_RECEIPT_SIGNER))
|
|
2976
3724
|
], AxisFilesFinalizeHandler);
|
|
2977
3725
|
|
|
2978
3726
|
// src/upload/disk-upload-file.store.ts
|
|
@@ -3031,92 +3779,54 @@ var DiskUploadFileStore = class {
|
|
|
3031
3779
|
}
|
|
3032
3780
|
};
|
|
3033
3781
|
|
|
3034
|
-
// src/
|
|
3035
|
-
var
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
TLV_LOOM_PRESENCE_ID: () => import_axis_protocol2.TLV_LOOM_PRESENCE_ID,
|
|
3083
|
-
TLV_LOOM_THREAD_HASH: () => import_axis_protocol2.TLV_LOOM_THREAD_HASH,
|
|
3084
|
-
TLV_LOOM_WRIT: () => import_axis_protocol2.TLV_LOOM_WRIT,
|
|
3085
|
-
TLV_NODE: () => import_axis_protocol2.TLV_NODE,
|
|
3086
|
-
TLV_NODE_CERT_HASH: () => import_axis_protocol2.TLV_NODE_CERT_HASH,
|
|
3087
|
-
TLV_NODE_KID: () => import_axis_protocol2.TLV_NODE_KID,
|
|
3088
|
-
TLV_NONCE: () => import_axis_protocol2.TLV_NONCE,
|
|
3089
|
-
TLV_OFFSET: () => import_axis_protocol2.TLV_OFFSET,
|
|
3090
|
-
TLV_OK: () => import_axis_protocol2.TLV_OK,
|
|
3091
|
-
TLV_PID: () => import_axis_protocol2.TLV_PID,
|
|
3092
|
-
TLV_PREV_HASH: () => import_axis_protocol2.TLV_PREV_HASH,
|
|
3093
|
-
TLV_PROOF_REF: () => import_axis_protocol2.TLV_PROOF_REF,
|
|
3094
|
-
TLV_PROOF_TYPE: () => import_axis_protocol2.TLV_PROOF_TYPE,
|
|
3095
|
-
TLV_REALM: () => import_axis_protocol2.TLV_REALM,
|
|
3096
|
-
TLV_RECEIPT_HASH: () => import_axis_protocol2.TLV_RECEIPT_HASH,
|
|
3097
|
-
TLV_RID: () => import_axis_protocol2.TLV_RID,
|
|
3098
|
-
TLV_SHA256_CHUNK: () => import_axis_protocol2.TLV_SHA256_CHUNK,
|
|
3099
|
-
TLV_TRACE_ID: () => import_axis_protocol2.TLV_TRACE_ID,
|
|
3100
|
-
TLV_TS: () => import_axis_protocol2.TLV_TS,
|
|
3101
|
-
TLV_UPLOAD_ID: () => import_axis_protocol2.TLV_UPLOAD_ID,
|
|
3102
|
-
computeReceiptHash: () => computeReceiptHash,
|
|
3103
|
-
computeSignaturePayload: () => computeSignaturePayload,
|
|
3104
|
-
decodeArray: () => import_axis_protocol.decodeArray,
|
|
3105
|
-
decodeFrame: () => decodeFrame,
|
|
3106
|
-
decodeObject: () => import_axis_protocol.decodeObject,
|
|
3107
|
-
decodeTLVs: () => import_axis_protocol.decodeTLVs,
|
|
3108
|
-
decodeTLVsList: () => import_axis_protocol.decodeTLVsList,
|
|
3109
|
-
decodeVarint: () => import_axis_protocol3.decodeVarint,
|
|
3110
|
-
encodeFrame: () => encodeFrame,
|
|
3111
|
-
encodeTLVs: () => import_axis_protocol.encodeTLVs,
|
|
3112
|
-
encodeVarint: () => import_axis_protocol3.encodeVarint,
|
|
3113
|
-
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
3114
|
-
getSignTarget: () => getSignTarget,
|
|
3115
|
-
sha256: () => sha256,
|
|
3116
|
-
signFrame: () => signFrame,
|
|
3117
|
-
varintLength: () => import_axis_protocol3.varintLength,
|
|
3118
|
-
verifyFrameSignature: () => verifyFrameSignature
|
|
3119
|
-
});
|
|
3782
|
+
// src/decorators/axis-request.decorator.ts
|
|
3783
|
+
var import_common5 = require("@nestjs/common");
|
|
3784
|
+
function resolveIp(req) {
|
|
3785
|
+
return req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress || void 0;
|
|
3786
|
+
}
|
|
3787
|
+
var AxisRaw = (0, import_common5.createParamDecorator)(
|
|
3788
|
+
(_data, ctx) => {
|
|
3789
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3790
|
+
return req.body;
|
|
3791
|
+
}
|
|
3792
|
+
);
|
|
3793
|
+
var AxisIp = (0, import_common5.createParamDecorator)(
|
|
3794
|
+
(_data, ctx) => {
|
|
3795
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3796
|
+
return resolveIp(req);
|
|
3797
|
+
}
|
|
3798
|
+
);
|
|
3799
|
+
var AxisContext = (0, import_common5.createParamDecorator)(
|
|
3800
|
+
(_data, ctx) => {
|
|
3801
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3802
|
+
const axisData = req.axis || {};
|
|
3803
|
+
return {
|
|
3804
|
+
raw: req.body,
|
|
3805
|
+
ip: resolveIp(req),
|
|
3806
|
+
preDecodeInput: axisData.preDecodeInput,
|
|
3807
|
+
frameBytesCount: axisData.frameBytesCount || 0
|
|
3808
|
+
};
|
|
3809
|
+
}
|
|
3810
|
+
);
|
|
3811
|
+
var AxisDemoPubkey = (0, import_common5.createParamDecorator)(
|
|
3812
|
+
(_data, ctx) => {
|
|
3813
|
+
if (process.env.NODE_ENV !== "development") return void 0;
|
|
3814
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3815
|
+
return req.headers["x-demo-pubkey"];
|
|
3816
|
+
}
|
|
3817
|
+
);
|
|
3818
|
+
var AxisFrame3 = (0, import_common5.createParamDecorator)(
|
|
3819
|
+
(_data, ctx) => {
|
|
3820
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3821
|
+
const decoded = req.axisDecoded;
|
|
3822
|
+
if (!decoded) {
|
|
3823
|
+
throw new Error(
|
|
3824
|
+
"@AxisFrame() requires AxisDecodeInterceptor on the route. Add @UseInterceptors(AxisDecodeInterceptor) to use this decorator."
|
|
3825
|
+
);
|
|
3826
|
+
}
|
|
3827
|
+
return decoded;
|
|
3828
|
+
}
|
|
3829
|
+
);
|
|
3120
3830
|
|
|
3121
3831
|
// src/core/axis-error.ts
|
|
3122
3832
|
var AxisError = class extends Error {
|
|
@@ -3129,348 +3839,246 @@ var AxisError = class extends Error {
|
|
|
3129
3839
|
}
|
|
3130
3840
|
};
|
|
3131
3841
|
|
|
3132
|
-
// src/
|
|
3133
|
-
var
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
canonicalJson: () => canonicalJson,
|
|
3141
|
-
canonicalJsonExcluding: () => canonicalJsonExcluding
|
|
3142
|
-
});
|
|
3143
|
-
|
|
3144
|
-
// src/crypto/proof-verification.service.ts
|
|
3145
|
-
var import_common4 = require("@nestjs/common");
|
|
3146
|
-
var crypto3 = __toESM(require("crypto"));
|
|
3147
|
-
var nacl = __toESM(require("tweetnacl"));
|
|
3148
|
-
var ProofVerificationService = class {
|
|
3149
|
-
constructor() {
|
|
3150
|
-
this.logger = new import_common4.Logger(ProofVerificationService.name);
|
|
3151
|
-
// Cache of registered device public keys (deviceId -> pubKey)
|
|
3152
|
-
this.deviceKeys = /* @__PURE__ */ new Map();
|
|
3153
|
-
// Cache of trusted mTLS certificate fingerprints
|
|
3154
|
-
this.trustedCerts = /* @__PURE__ */ new Map();
|
|
3842
|
+
// src/engine/handler-discovery.service.ts
|
|
3843
|
+
var import_common6 = require("@nestjs/common");
|
|
3844
|
+
var HandlerDiscoveryService = class {
|
|
3845
|
+
constructor(discovery, scanner, router) {
|
|
3846
|
+
this.discovery = discovery;
|
|
3847
|
+
this.scanner = scanner;
|
|
3848
|
+
this.router = router;
|
|
3849
|
+
this.logger = new import_common6.Logger(HandlerDiscoveryService.name);
|
|
3155
3850
|
}
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3851
|
+
onModuleInit() {
|
|
3852
|
+
const providers = this.discovery.getProviders();
|
|
3853
|
+
let totalIntents = 0;
|
|
3854
|
+
for (const wrapper of providers) {
|
|
3855
|
+
const { instance, metatype } = wrapper;
|
|
3856
|
+
if (!instance || !metatype) continue;
|
|
3857
|
+
const handlerMeta = Reflect.getMetadata(HANDLER_METADATA_KEY, metatype);
|
|
3858
|
+
if (!handlerMeta) continue;
|
|
3859
|
+
const handlerName = handlerMeta.intent || metatype.name;
|
|
3860
|
+
const proto = Object.getPrototypeOf(instance);
|
|
3861
|
+
const methods = this.scanner.getAllMethodNames(proto);
|
|
3862
|
+
let registered = 0;
|
|
3863
|
+
const handlerSensors = Reflect.getMetadata(HANDLER_SENSORS_KEY, metatype) || [];
|
|
3864
|
+
for (const methodName of methods) {
|
|
3865
|
+
const meta = Reflect.getMetadata(
|
|
3866
|
+
INTENT_METADATA_KEY,
|
|
3867
|
+
proto,
|
|
3868
|
+
methodName
|
|
3869
|
+
);
|
|
3870
|
+
if (!meta?.intent) continue;
|
|
3871
|
+
if (!this.router.has(meta.intent)) {
|
|
3872
|
+
this.router.register(
|
|
3873
|
+
meta.intent,
|
|
3874
|
+
instance[methodName].bind(instance)
|
|
3875
|
+
);
|
|
3876
|
+
registered++;
|
|
3877
|
+
totalIntents++;
|
|
3878
|
+
}
|
|
3879
|
+
this.router.registerIntentMeta(
|
|
3880
|
+
meta.intent,
|
|
3881
|
+
proto,
|
|
3882
|
+
methodName,
|
|
3883
|
+
handlerSensors
|
|
3187
3884
|
);
|
|
3188
|
-
default:
|
|
3189
|
-
return { valid: false, error: `Unknown proof type: ${proofType}` };
|
|
3190
|
-
}
|
|
3191
|
-
}
|
|
3192
|
-
/**
|
|
3193
|
-
* Verify CAPSULE proof (delegated to CapsuleService)
|
|
3194
|
-
*/
|
|
3195
|
-
async verifyCapsuleProof(proofRef) {
|
|
3196
|
-
const capsuleId = new TextDecoder().decode(proofRef);
|
|
3197
|
-
return {
|
|
3198
|
-
valid: true,
|
|
3199
|
-
metadata: { capsuleId, requiresCapsuleValidation: true }
|
|
3200
|
-
};
|
|
3201
|
-
}
|
|
3202
|
-
/**
|
|
3203
|
-
* Verifies a JSON Web Token (JWT) proof.
|
|
3204
|
-
*
|
|
3205
|
-
* **Validation Logic:**
|
|
3206
|
-
* 1. Decodes the token string.
|
|
3207
|
-
* 2. Checks for valid 3-part JWT structure.
|
|
3208
|
-
* 3. Validates `exp` (expiration) and `nbf` (not before) claims.
|
|
3209
|
-
* 4. Extracts `actor_id` or `sub` as the identity.
|
|
3210
|
-
*
|
|
3211
|
-
* @param {Uint8Array} proofRef - Binary representation of the JWT string
|
|
3212
|
-
* @returns {Promise<ProofVerificationResult>} Result including the actor identifier
|
|
3213
|
-
*/
|
|
3214
|
-
async verifyJWTProof(proofRef) {
|
|
3215
|
-
try {
|
|
3216
|
-
const token = new TextDecoder().decode(proofRef);
|
|
3217
|
-
const parts = token.split(".");
|
|
3218
|
-
if (parts.length !== 3) {
|
|
3219
|
-
return { valid: false, error: "Invalid JWT format" };
|
|
3220
|
-
}
|
|
3221
|
-
const header = JSON.parse(Buffer.from(parts[0], "base64url").toString());
|
|
3222
|
-
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
3223
|
-
if (payload.exp && Date.now() / 1e3 > payload.exp) {
|
|
3224
|
-
return { valid: false, error: "JWT expired" };
|
|
3225
3885
|
}
|
|
3226
|
-
if (
|
|
3227
|
-
|
|
3886
|
+
if (registered > 0) {
|
|
3887
|
+
this.logger.log(
|
|
3888
|
+
`Auto-registered ${registered} intents from ${handlerName}`
|
|
3889
|
+
);
|
|
3228
3890
|
}
|
|
3229
|
-
return {
|
|
3230
|
-
valid: true,
|
|
3231
|
-
actorId: payload.sub || payload.actor_id,
|
|
3232
|
-
metadata: { iss: payload.iss, scope: payload.scope }
|
|
3233
|
-
};
|
|
3234
|
-
} catch (e) {
|
|
3235
|
-
const message = e instanceof Error ? e.message : "Unknown error";
|
|
3236
|
-
return { valid: false, error: `JWT parse error: ${message}` };
|
|
3237
3891
|
}
|
|
3892
|
+
this.logger.log(
|
|
3893
|
+
`Handler discovery complete: ${totalIntents} intents auto-registered`
|
|
3894
|
+
);
|
|
3238
3895
|
}
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3896
|
+
};
|
|
3897
|
+
HandlerDiscoveryService = __decorateClass([
|
|
3898
|
+
(0, import_common6.Injectable)()
|
|
3899
|
+
], HandlerDiscoveryService);
|
|
3900
|
+
|
|
3901
|
+
// src/engine/sensor-discovery.service.ts
|
|
3902
|
+
var import_common7 = require("@nestjs/common");
|
|
3903
|
+
var SensorDiscoveryService = class {
|
|
3904
|
+
constructor(discovery, reflector, registry) {
|
|
3905
|
+
this.discovery = discovery;
|
|
3906
|
+
this.reflector = reflector;
|
|
3907
|
+
this.registry = registry;
|
|
3908
|
+
this.logger = new import_common7.Logger(SensorDiscoveryService.name);
|
|
3909
|
+
}
|
|
3910
|
+
onApplicationBootstrap() {
|
|
3911
|
+
const providers = this.discovery.getProviders();
|
|
3912
|
+
let count = 0;
|
|
3913
|
+
for (const wrapper of providers) {
|
|
3914
|
+
const { instance } = wrapper;
|
|
3915
|
+
if (!instance || !instance.constructor) continue;
|
|
3916
|
+
const meta = this.reflector.get(
|
|
3917
|
+
SENSOR_METADATA_KEY,
|
|
3918
|
+
instance.constructor
|
|
3919
|
+
);
|
|
3920
|
+
if (!meta) continue;
|
|
3921
|
+
const sensor = instance;
|
|
3922
|
+
if (!sensor.name || sensor.order === void 0) {
|
|
3923
|
+
this.logger.warn(
|
|
3924
|
+
`@Sensor() on ${instance.constructor.name} missing name or order \u2014 skipped`
|
|
3925
|
+
);
|
|
3926
|
+
continue;
|
|
3260
3927
|
}
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
if (cnMatch) {
|
|
3265
|
-
return {
|
|
3266
|
-
valid: true,
|
|
3267
|
-
actorId: cnMatch[1],
|
|
3268
|
-
metadata: {
|
|
3269
|
-
subject: mtls.clientCertSubject,
|
|
3270
|
-
issuer: mtls.clientCertIssuer
|
|
3271
|
-
}
|
|
3272
|
-
};
|
|
3928
|
+
if (!sensor.phase) {
|
|
3929
|
+
const decoratorPhase = meta !== true ? meta.phase : void 0;
|
|
3930
|
+
sensor.phase = decoratorPhase ?? (sensor.order < PRE_DECODE_BOUNDARY ? "PRE_DECODE" : "POST_DECODE");
|
|
3273
3931
|
}
|
|
3932
|
+
this.registry.register(sensor);
|
|
3933
|
+
count++;
|
|
3274
3934
|
}
|
|
3275
|
-
|
|
3935
|
+
this.logger.log(`Auto-registered ${count} sensors via @Sensor()`);
|
|
3936
|
+
}
|
|
3937
|
+
};
|
|
3938
|
+
SensorDiscoveryService = __decorateClass([
|
|
3939
|
+
(0, import_common7.Injectable)()
|
|
3940
|
+
], SensorDiscoveryService);
|
|
3941
|
+
|
|
3942
|
+
// src/engine/registry/sensor.registry.ts
|
|
3943
|
+
var import_common8 = require("@nestjs/common");
|
|
3944
|
+
var SensorRegistry = class {
|
|
3945
|
+
constructor(configService) {
|
|
3946
|
+
this.configService = configService;
|
|
3947
|
+
this.sensors = [];
|
|
3948
|
+
this.logger = new import_common8.Logger(SensorRegistry.name);
|
|
3276
3949
|
}
|
|
3277
3950
|
/**
|
|
3278
|
-
*
|
|
3951
|
+
* Registers a new sensor in the registry.
|
|
3952
|
+
*
|
|
3953
|
+
* Validates that:
|
|
3954
|
+
* - AxisSensor has a unique name
|
|
3955
|
+
* - AxisSensor has an order field
|
|
3956
|
+
* - Pre-decode sensors have order < 40
|
|
3957
|
+
* - Post-decode sensors have order >= 40
|
|
3958
|
+
*
|
|
3959
|
+
* @param {AxisSensor} sensor - The sensor instance to register
|
|
3960
|
+
* @throws Error if validation fails
|
|
3279
3961
|
*/
|
|
3280
|
-
|
|
3281
|
-
if (!
|
|
3282
|
-
|
|
3962
|
+
register(sensor) {
|
|
3963
|
+
if (!sensor.name) {
|
|
3964
|
+
throw new Error("AxisSensor must have a name");
|
|
3283
3965
|
}
|
|
3284
|
-
|
|
3285
|
-
const
|
|
3286
|
-
|
|
3287
|
-
|
|
3966
|
+
const enabledSensorsStr = this.configService.get("ENABLED_SENSORS");
|
|
3967
|
+
const disabledSensorsStr = this.configService.get("DISABLED_SENSORS");
|
|
3968
|
+
const enabledSensors = enabledSensorsStr ? enabledSensorsStr.split(",").map((s) => s.trim()) : null;
|
|
3969
|
+
const disabledSensors = disabledSensorsStr ? disabledSensorsStr.split(",").map((s) => s.trim()) : [];
|
|
3970
|
+
if (enabledSensors && !enabledSensors.includes(sensor.name)) {
|
|
3971
|
+
this.logger.log(`Skipping disabled sensor (not in ENABLED_SENSORS): ${sensor.name}`);
|
|
3972
|
+
return;
|
|
3288
3973
|
}
|
|
3289
|
-
if (
|
|
3290
|
-
|
|
3291
|
-
|
|
3292
|
-
error: "Invalid or unregistered device public key"
|
|
3293
|
-
};
|
|
3974
|
+
if (disabledSensors.includes(sensor.name)) {
|
|
3975
|
+
this.logger.log(`Skipping disabled sensor (in DISABLED_SENSORS): ${sensor.name}`);
|
|
3976
|
+
return;
|
|
3294
3977
|
}
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
error: `Signature verification error: ${message}`
|
|
3310
|
-
};
|
|
3978
|
+
if (sensor.order === void 0) {
|
|
3979
|
+
throw new Error(`AxisSensor "${sensor.name}" must have an order field`);
|
|
3980
|
+
}
|
|
3981
|
+
const isPreDecodeSensor = this.isPreDecodeSensor(sensor);
|
|
3982
|
+
const isPostDecodeSensor = this.isPostDecodeSensor(sensor);
|
|
3983
|
+
if (isPreDecodeSensor && sensor.order >= 40) {
|
|
3984
|
+
this.logger.warn(
|
|
3985
|
+
`AxisSensor "${sensor.name}" is marked as PRE_DECODE but has order ${sensor.order} (should be < 40)`
|
|
3986
|
+
);
|
|
3987
|
+
}
|
|
3988
|
+
if (isPostDecodeSensor && sensor.order < 40) {
|
|
3989
|
+
this.logger.warn(
|
|
3990
|
+
`AxisSensor "${sensor.name}" is marked as POST_DECODE but has order ${sensor.order} (should be >= 40)`
|
|
3991
|
+
);
|
|
3311
3992
|
}
|
|
3993
|
+
this.sensors.push(sensor);
|
|
3994
|
+
const phaseLabel = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase || "UNKNOWN";
|
|
3995
|
+
this.logger.debug(
|
|
3996
|
+
`Registered sensor: ${sensor.name} (order: ${sensor.order}, phase: ${phaseLabel})`
|
|
3997
|
+
);
|
|
3312
3998
|
}
|
|
3313
3999
|
/**
|
|
3314
|
-
*
|
|
3315
|
-
* This key will be used for future `DEVICE_SE` proof verifications.
|
|
4000
|
+
* Returns all registered sensors, sorted by their execution order.
|
|
3316
4001
|
*
|
|
3317
|
-
* @
|
|
3318
|
-
* @param {Uint8Array} publicKey - 32-byte Ed25519 public key
|
|
3319
|
-
* @throws {Error} If the public key is not 32 bytes
|
|
4002
|
+
* @returns {AxisSensor[]} A sorted array of sensors
|
|
3320
4003
|
*/
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
this.deviceKeys.set(deviceId, publicKey);
|
|
3326
|
-
this.logger.log(`Registered device key for ${deviceId}`);
|
|
4004
|
+
list() {
|
|
4005
|
+
return [...this.sensors].sort(
|
|
4006
|
+
(a, b) => (a.order ?? 999) - (b.order ?? 999)
|
|
4007
|
+
);
|
|
3327
4008
|
}
|
|
3328
4009
|
/**
|
|
3329
|
-
*
|
|
4010
|
+
* Returns only pre-decode sensors (order < 40).
|
|
4011
|
+
* These sensors run in middleware on raw bytes before frame decoding.
|
|
4012
|
+
*
|
|
4013
|
+
* @returns {AxisPreSensor[]} Pre-decode sensors sorted by order
|
|
3330
4014
|
*/
|
|
3331
|
-
|
|
3332
|
-
return this.
|
|
4015
|
+
getPreDecodeSensors() {
|
|
4016
|
+
return this.list().filter((s) => (s.order ?? 999) < 40);
|
|
3333
4017
|
}
|
|
3334
4018
|
/**
|
|
3335
|
-
*
|
|
4019
|
+
* Returns only post-decode sensors (order >= 40).
|
|
4020
|
+
* These sensors run in the controller on fully decoded frames.
|
|
3336
4021
|
*
|
|
3337
|
-
* @
|
|
3338
|
-
* @param {string} actorId - The actor to associate with this certificate
|
|
4022
|
+
* @returns {AxisPostSensor[]} Post-decode sensors sorted by order
|
|
3339
4023
|
*/
|
|
3340
|
-
|
|
3341
|
-
this.
|
|
3342
|
-
|
|
4024
|
+
getPostDecodeSensors() {
|
|
4025
|
+
return this.list().filter(
|
|
4026
|
+
(s) => (s.order ?? 999) >= 40
|
|
4027
|
+
);
|
|
3343
4028
|
}
|
|
3344
4029
|
/**
|
|
3345
|
-
*
|
|
4030
|
+
* Helper: Check if a sensor is a pre-decode sensor.
|
|
4031
|
+
*
|
|
4032
|
+
* @private
|
|
4033
|
+
* @param {AxisSensor} sensor - The sensor to check
|
|
4034
|
+
* @returns {boolean} True if sensor is pre-decode
|
|
3346
4035
|
*/
|
|
3347
|
-
|
|
3348
|
-
|
|
4036
|
+
isPreDecodeSensor(sensor) {
|
|
4037
|
+
const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
|
|
4038
|
+
return phase === "PRE_DECODE" || (sensor.order ?? 999) < 40;
|
|
3349
4039
|
}
|
|
3350
4040
|
/**
|
|
3351
|
-
*
|
|
4041
|
+
* Helper: Check if a sensor is a post-decode sensor.
|
|
4042
|
+
*
|
|
4043
|
+
* @private
|
|
4044
|
+
* @param {AxisSensor} sensor - The sensor to check
|
|
4045
|
+
* @returns {boolean} True if sensor is post-decode
|
|
3352
4046
|
*/
|
|
3353
|
-
|
|
3354
|
-
const
|
|
3355
|
-
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
4047
|
+
isPostDecodeSensor(sensor) {
|
|
4048
|
+
const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
|
|
4049
|
+
return phase === "POST_DECODE" || (sensor.order ?? 999) >= 40;
|
|
4050
|
+
}
|
|
4051
|
+
/**
|
|
4052
|
+
* Returns sensor count by phase.
|
|
4053
|
+
* Useful for diagnostics and monitoring.
|
|
4054
|
+
*
|
|
4055
|
+
* @returns {{preDecodeCount: number, postDecodeCount: number}}
|
|
4056
|
+
*/
|
|
4057
|
+
getSensorCountByPhase() {
|
|
4058
|
+
return {
|
|
4059
|
+
preDecodeCount: this.getPreDecodeSensors().length,
|
|
4060
|
+
postDecodeCount: this.getPostDecodeSensors().length
|
|
4061
|
+
};
|
|
4062
|
+
}
|
|
4063
|
+
/**
|
|
4064
|
+
* Clears all registered sensors.
|
|
4065
|
+
* Useful for testing.
|
|
4066
|
+
*
|
|
4067
|
+
* @internal
|
|
4068
|
+
*/
|
|
4069
|
+
clear() {
|
|
4070
|
+
this.sensors = [];
|
|
3359
4071
|
}
|
|
3360
4072
|
};
|
|
3361
|
-
|
|
3362
|
-
(0,
|
|
3363
|
-
],
|
|
3364
|
-
|
|
3365
|
-
// src/decorators/index.ts
|
|
3366
|
-
var decorators_exports = {};
|
|
3367
|
-
__export(decorators_exports, {
|
|
3368
|
-
AxisContext: () => AxisContext,
|
|
3369
|
-
AxisDemoPubkey: () => AxisDemoPubkey,
|
|
3370
|
-
AxisFrame: () => AxisFrame3,
|
|
3371
|
-
AxisIp: () => AxisIp,
|
|
3372
|
-
AxisRaw: () => AxisRaw,
|
|
3373
|
-
HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
|
|
3374
|
-
Handler: () => Handler,
|
|
3375
|
-
INTENT_BODY_KEY: () => INTENT_BODY_KEY,
|
|
3376
|
-
INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
|
|
3377
|
-
INTENT_ROUTES_KEY: () => INTENT_ROUTES_KEY,
|
|
3378
|
-
INTENT_SENSORS_KEY: () => INTENT_SENSORS_KEY,
|
|
3379
|
-
Intent: () => Intent,
|
|
3380
|
-
IntentBody: () => IntentBody,
|
|
3381
|
-
IntentSensors: () => IntentSensors,
|
|
3382
|
-
SENSOR_METADATA_KEY: () => SENSOR_METADATA_KEY,
|
|
3383
|
-
Sensor: () => Sensor,
|
|
3384
|
-
TLV_FIELDS_KEY: () => TLV_FIELDS_KEY,
|
|
3385
|
-
TLV_VALIDATORS_KEY: () => TLV_VALIDATORS_KEY,
|
|
3386
|
-
TlvEnum: () => TlvEnum,
|
|
3387
|
-
TlvField: () => TlvField,
|
|
3388
|
-
TlvMinLen: () => TlvMinLen,
|
|
3389
|
-
TlvRange: () => TlvRange,
|
|
3390
|
-
TlvUtf8Pattern: () => TlvUtf8Pattern,
|
|
3391
|
-
TlvValidate: () => TlvValidate,
|
|
3392
|
-
buildDtoDecoder: () => buildDtoDecoder,
|
|
3393
|
-
extractDtoSchema: () => extractDtoSchema
|
|
3394
|
-
});
|
|
3395
|
-
|
|
3396
|
-
// src/decorators/axis-request.decorator.ts
|
|
3397
|
-
var import_common5 = require("@nestjs/common");
|
|
3398
|
-
function resolveIp(req) {
|
|
3399
|
-
return req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress || void 0;
|
|
3400
|
-
}
|
|
3401
|
-
var AxisRaw = (0, import_common5.createParamDecorator)(
|
|
3402
|
-
(_data, ctx) => {
|
|
3403
|
-
const req = ctx.switchToHttp().getRequest();
|
|
3404
|
-
return req.body;
|
|
3405
|
-
}
|
|
3406
|
-
);
|
|
3407
|
-
var AxisIp = (0, import_common5.createParamDecorator)(
|
|
3408
|
-
(_data, ctx) => {
|
|
3409
|
-
const req = ctx.switchToHttp().getRequest();
|
|
3410
|
-
return resolveIp(req);
|
|
3411
|
-
}
|
|
3412
|
-
);
|
|
3413
|
-
var AxisContext = (0, import_common5.createParamDecorator)(
|
|
3414
|
-
(_data, ctx) => {
|
|
3415
|
-
const req = ctx.switchToHttp().getRequest();
|
|
3416
|
-
const axisData = req.axis || {};
|
|
3417
|
-
return {
|
|
3418
|
-
raw: req.body,
|
|
3419
|
-
ip: resolveIp(req),
|
|
3420
|
-
preDecodeInput: axisData.preDecodeInput,
|
|
3421
|
-
frameBytesCount: axisData.frameBytesCount || 0
|
|
3422
|
-
};
|
|
3423
|
-
}
|
|
3424
|
-
);
|
|
3425
|
-
var AxisDemoPubkey = (0, import_common5.createParamDecorator)(
|
|
3426
|
-
(_data, ctx) => {
|
|
3427
|
-
if (process.env.NODE_ENV !== "development") return void 0;
|
|
3428
|
-
const req = ctx.switchToHttp().getRequest();
|
|
3429
|
-
return req.headers["x-demo-pubkey"];
|
|
3430
|
-
}
|
|
3431
|
-
);
|
|
3432
|
-
var AxisFrame3 = (0, import_common5.createParamDecorator)(
|
|
3433
|
-
(_data, ctx) => {
|
|
3434
|
-
const req = ctx.switchToHttp().getRequest();
|
|
3435
|
-
const decoded = req.axisDecoded;
|
|
3436
|
-
if (!decoded) {
|
|
3437
|
-
throw new Error(
|
|
3438
|
-
"@AxisFrame() requires AxisDecodeInterceptor on the route. Add @UseInterceptors(AxisDecodeInterceptor) to use this decorator."
|
|
3439
|
-
);
|
|
3440
|
-
}
|
|
3441
|
-
return decoded;
|
|
3442
|
-
}
|
|
3443
|
-
);
|
|
3444
|
-
|
|
3445
|
-
// src/decorators/sensor.decorator.ts
|
|
3446
|
-
var import_common6 = require("@nestjs/common");
|
|
3447
|
-
var SENSOR_METADATA_KEY = "axis:sensor";
|
|
3448
|
-
function Sensor(options) {
|
|
3449
|
-
return (0, import_common6.SetMetadata)(SENSOR_METADATA_KEY, options ?? true);
|
|
3450
|
-
}
|
|
3451
|
-
|
|
3452
|
-
// src/engine/index.ts
|
|
3453
|
-
var engine_exports = {};
|
|
3454
|
-
__export(engine_exports, {
|
|
3455
|
-
BAND: () => BAND,
|
|
3456
|
-
HandlerDiscoveryService: () => HandlerDiscoveryService,
|
|
3457
|
-
IntentRouter: () => IntentRouter,
|
|
3458
|
-
PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
|
|
3459
|
-
SensorDiscoveryService: () => SensorDiscoveryService,
|
|
3460
|
-
SensorRegistry: () => SensorRegistry,
|
|
3461
|
-
createObservation: () => createObservation,
|
|
3462
|
-
endStage: () => endStage,
|
|
3463
|
-
finalizeObservation: () => finalizeObservation,
|
|
3464
|
-
observation: () => observation_exports,
|
|
3465
|
-
recordSensor: () => recordSensor,
|
|
3466
|
-
startStage: () => startStage
|
|
3467
|
-
});
|
|
4073
|
+
SensorRegistry = __decorateClass([
|
|
4074
|
+
(0, import_common8.Injectable)()
|
|
4075
|
+
], SensorRegistry);
|
|
3468
4076
|
|
|
3469
4077
|
// src/engine/axis-observation.ts
|
|
3470
|
-
var
|
|
4078
|
+
var import_crypto7 = require("crypto");
|
|
3471
4079
|
function createObservation(transport, ip) {
|
|
3472
4080
|
return {
|
|
3473
|
-
id: (0,
|
|
4081
|
+
id: (0, import_crypto7.randomBytes)(16).toString("hex"),
|
|
3474
4082
|
startMs: Date.now(),
|
|
3475
4083
|
transport,
|
|
3476
4084
|
ip,
|
|
@@ -3502,251 +4110,1186 @@ function finalizeObservation(obs, decision, statusCode, resultCode) {
|
|
|
3502
4110
|
if (resultCode) obs.resultCode = resultCode;
|
|
3503
4111
|
}
|
|
3504
4112
|
|
|
3505
|
-
// src/
|
|
3506
|
-
var
|
|
3507
|
-
var
|
|
3508
|
-
constructor(
|
|
3509
|
-
this.
|
|
3510
|
-
this.scanner = scanner;
|
|
3511
|
-
this.router = router;
|
|
3512
|
-
this.logger = new import_common7.Logger(HandlerDiscoveryService.name);
|
|
4113
|
+
// src/security/axis-sensor-chain.service.ts
|
|
4114
|
+
var import_common9 = require("@nestjs/common");
|
|
4115
|
+
var AxisSensorChainService = class {
|
|
4116
|
+
constructor(registry) {
|
|
4117
|
+
this.registry = registry;
|
|
3513
4118
|
}
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
const
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
3534
|
-
|
|
3535
|
-
|
|
3536
|
-
|
|
4119
|
+
/**
|
|
4120
|
+
* Evaluate all applicable sensors based on phase.
|
|
4121
|
+
*/
|
|
4122
|
+
async evaluate(input, phase = "POST_DECODE", baseDecision) {
|
|
4123
|
+
if (phase === "PRE_DECODE") {
|
|
4124
|
+
return this.evaluateSensors(this.registry.getPreDecodeSensors(), input);
|
|
4125
|
+
}
|
|
4126
|
+
if (phase === "BOTH") {
|
|
4127
|
+
const rawPreResult = await this.evaluateSensors(
|
|
4128
|
+
this.registry.getPreDecodeSensors(),
|
|
4129
|
+
input
|
|
4130
|
+
);
|
|
4131
|
+
const preResult = normalizeSensorDecision(rawPreResult);
|
|
4132
|
+
if (!preResult.allow) return rawPreResult;
|
|
4133
|
+
return this.evaluateSensors(
|
|
4134
|
+
this.registry.getPostDecodeSensors(),
|
|
4135
|
+
input,
|
|
4136
|
+
rawPreResult
|
|
4137
|
+
);
|
|
4138
|
+
}
|
|
4139
|
+
return this.evaluateSensors(
|
|
4140
|
+
this.registry.getPostDecodeSensors(),
|
|
4141
|
+
input,
|
|
4142
|
+
baseDecision
|
|
4143
|
+
);
|
|
4144
|
+
}
|
|
4145
|
+
/** Run only pre-decode sensors. */
|
|
4146
|
+
async evaluatePre(input) {
|
|
4147
|
+
return this.evaluateSensors(this.registry.getPreDecodeSensors(), input);
|
|
4148
|
+
}
|
|
4149
|
+
/** Run only post-decode sensors. */
|
|
4150
|
+
async evaluatePost(input, baseDecision) {
|
|
4151
|
+
return this.evaluateSensors(
|
|
4152
|
+
this.registry.getPostDecodeSensors(),
|
|
4153
|
+
input,
|
|
4154
|
+
baseDecision
|
|
4155
|
+
);
|
|
4156
|
+
}
|
|
4157
|
+
async evaluateSensors(sensors, input, baseDecision) {
|
|
4158
|
+
const relevantSensors = sensors.filter(
|
|
4159
|
+
(s) => !s.supports || s.supports(input)
|
|
4160
|
+
);
|
|
4161
|
+
const normalizedBase = baseDecision ? normalizeSensorDecision(baseDecision) : void 0;
|
|
4162
|
+
let riskScore = normalizedBase?.riskScore ?? 0;
|
|
4163
|
+
const reasons = normalizedBase?.reasons ? [...normalizedBase.reasons] : [];
|
|
4164
|
+
const tags = normalizedBase?.tags ? { ...normalizedBase.tags } : {};
|
|
4165
|
+
let expSecondsMax = normalizedBase?.tighten?.expSecondsMax;
|
|
4166
|
+
let constraintsPatch = normalizedBase?.tighten?.constraintsPatch ? { ...normalizedBase.tighten.constraintsPatch } : {};
|
|
4167
|
+
for (const sensor of relevantSensors) {
|
|
4168
|
+
try {
|
|
4169
|
+
const t0 = Date.now();
|
|
4170
|
+
const rawDecision = await sensor.run(input);
|
|
4171
|
+
const elapsed = Date.now() - t0;
|
|
4172
|
+
const decision = normalizeSensorDecision(rawDecision);
|
|
4173
|
+
const obs = input.metadata?.observation;
|
|
4174
|
+
if (obs) {
|
|
4175
|
+
recordSensor(
|
|
4176
|
+
obs,
|
|
4177
|
+
sensor.name,
|
|
4178
|
+
decision.allow,
|
|
4179
|
+
decision.riskScore,
|
|
4180
|
+
elapsed,
|
|
4181
|
+
decision.reasons,
|
|
4182
|
+
decision.allow ? void 0 : decision.code
|
|
3537
4183
|
);
|
|
3538
|
-
registered++;
|
|
3539
|
-
totalIntents++;
|
|
3540
4184
|
}
|
|
3541
|
-
|
|
3542
|
-
|
|
3543
|
-
|
|
3544
|
-
|
|
3545
|
-
|
|
3546
|
-
|
|
4185
|
+
if (!decision.allow) {
|
|
4186
|
+
return {
|
|
4187
|
+
allow: false,
|
|
4188
|
+
riskScore: Math.min(100, riskScore + decision.riskScore),
|
|
4189
|
+
reasons: [...reasons, ...decision.reasons],
|
|
4190
|
+
tags
|
|
4191
|
+
};
|
|
4192
|
+
}
|
|
4193
|
+
riskScore = Math.min(100, riskScore + decision.riskScore);
|
|
4194
|
+
reasons.push(...decision.reasons);
|
|
4195
|
+
if (decision.tags) {
|
|
4196
|
+
Object.assign(tags, decision.tags);
|
|
4197
|
+
}
|
|
4198
|
+
if (decision.tighten?.expSecondsMax !== void 0) {
|
|
4199
|
+
expSecondsMax = expSecondsMax === void 0 ? decision.tighten.expSecondsMax : Math.min(expSecondsMax, decision.tighten.expSecondsMax);
|
|
4200
|
+
}
|
|
4201
|
+
if (decision.tighten?.constraintsPatch) {
|
|
4202
|
+
constraintsPatch = {
|
|
4203
|
+
...constraintsPatch,
|
|
4204
|
+
...decision.tighten.constraintsPatch
|
|
4205
|
+
};
|
|
4206
|
+
}
|
|
4207
|
+
} catch (error) {
|
|
4208
|
+
console.error(`[AXIS][SENSOR] ${sensor.name} failed:`, error);
|
|
4209
|
+
const obs = input.metadata?.observation;
|
|
4210
|
+
if (obs) {
|
|
4211
|
+
recordSensor(obs, sensor.name, false, 100, 0, [
|
|
4212
|
+
`sensor_error:${sensor.name}`
|
|
4213
|
+
]);
|
|
4214
|
+
}
|
|
4215
|
+
return {
|
|
4216
|
+
allow: false,
|
|
4217
|
+
riskScore: 100,
|
|
4218
|
+
reasons: [`sensor_error:${sensor.name}`]
|
|
4219
|
+
};
|
|
3547
4220
|
}
|
|
3548
4221
|
}
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
4222
|
+
const tightenPatch = Object.keys(constraintsPatch).length > 0 ? constraintsPatch : void 0;
|
|
4223
|
+
return {
|
|
4224
|
+
allow: true,
|
|
4225
|
+
riskScore,
|
|
4226
|
+
reasons,
|
|
4227
|
+
tags,
|
|
4228
|
+
tighten: expSecondsMax !== void 0 || tightenPatch ? {
|
|
4229
|
+
expSecondsMax,
|
|
4230
|
+
constraintsPatch: tightenPatch
|
|
4231
|
+
} : void 0
|
|
4232
|
+
};
|
|
3552
4233
|
}
|
|
3553
4234
|
};
|
|
3554
|
-
|
|
3555
|
-
(0,
|
|
3556
|
-
],
|
|
4235
|
+
AxisSensorChainService = __decorateClass([
|
|
4236
|
+
(0, import_common9.Injectable)()
|
|
4237
|
+
], AxisSensorChainService);
|
|
3557
4238
|
|
|
3558
|
-
// src/
|
|
3559
|
-
var
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
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
|
+
});
|
|
3574
4278
|
|
|
3575
|
-
// src/
|
|
3576
|
-
var
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
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";
|
|
3583
4297
|
}
|
|
3584
|
-
|
|
3585
|
-
|
|
3586
|
-
|
|
3587
|
-
|
|
3588
|
-
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
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
|
+
};
|
|
3605
4319
|
}
|
|
3606
|
-
this.registry.register(sensor);
|
|
3607
|
-
count++;
|
|
3608
4320
|
}
|
|
3609
|
-
|
|
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
|
+
};
|
|
3610
4374
|
}
|
|
3611
4375
|
};
|
|
3612
|
-
SensorDiscoveryService = __decorateClass([
|
|
3613
|
-
(0, import_common8.Injectable)()
|
|
3614
|
-
], SensorDiscoveryService);
|
|
3615
4376
|
|
|
3616
|
-
// src/
|
|
3617
|
-
var
|
|
3618
|
-
|
|
3619
|
-
|
|
3620
|
-
this.
|
|
3621
|
-
this.
|
|
3622
|
-
this.
|
|
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";
|
|
3623
4385
|
}
|
|
3624
|
-
|
|
3625
|
-
|
|
3626
|
-
|
|
3627
|
-
|
|
3628
|
-
|
|
3629
|
-
|
|
3630
|
-
|
|
3631
|
-
|
|
3632
|
-
|
|
3633
|
-
|
|
3634
|
-
|
|
3635
|
-
|
|
3636
|
-
register(sensor) {
|
|
3637
|
-
if (!sensor.name) {
|
|
3638
|
-
throw new Error("AxisSensor must have a name");
|
|
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
|
+
};
|
|
3639
4398
|
}
|
|
3640
|
-
const
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
3646
|
-
|
|
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
|
+
};
|
|
3647
4409
|
}
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
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
|
+
};
|
|
3651
4426
|
}
|
|
3652
|
-
|
|
3653
|
-
|
|
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
|
+
};
|
|
3654
4475
|
}
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
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
|
|
3660
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
|
+
}
|
|
3661
4762
|
}
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
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
|
|
3665
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
|
+
|
|
4926
|
+
// src/core/index.ts
|
|
4927
|
+
var core_exports = {};
|
|
4928
|
+
__export(core_exports, {
|
|
4929
|
+
AXIS_MAGIC: () => import_axis_protocol2.AXIS_MAGIC,
|
|
4930
|
+
AXIS_VERSION: () => import_axis_protocol2.AXIS_VERSION,
|
|
4931
|
+
AxisError: () => AxisError,
|
|
4932
|
+
AxisFrameZ: () => AxisFrameZ,
|
|
4933
|
+
BodyProfile: () => import_axis_protocol2.BodyProfile,
|
|
4934
|
+
ERR_BAD_SIGNATURE: () => import_axis_protocol2.ERR_BAD_SIGNATURE,
|
|
4935
|
+
ERR_CONTRACT_VIOLATION: () => import_axis_protocol2.ERR_CONTRACT_VIOLATION,
|
|
4936
|
+
ERR_INVALID_PACKET: () => import_axis_protocol2.ERR_INVALID_PACKET,
|
|
4937
|
+
ERR_REPLAY_DETECTED: () => import_axis_protocol2.ERR_REPLAY_DETECTED,
|
|
4938
|
+
FLAG_BODY_TLV: () => import_axis_protocol2.FLAG_BODY_TLV,
|
|
4939
|
+
FLAG_CHAIN_REQ: () => import_axis_protocol2.FLAG_CHAIN_REQ,
|
|
4940
|
+
FLAG_HAS_WITNESS: () => import_axis_protocol2.FLAG_HAS_WITNESS,
|
|
4941
|
+
MAX_BODY_LEN: () => import_axis_protocol2.MAX_BODY_LEN,
|
|
4942
|
+
MAX_FRAME_LEN: () => import_axis_protocol2.MAX_FRAME_LEN,
|
|
4943
|
+
MAX_HDR_LEN: () => import_axis_protocol2.MAX_HDR_LEN,
|
|
4944
|
+
MAX_SIG_LEN: () => import_axis_protocol2.MAX_SIG_LEN,
|
|
4945
|
+
NCERT_ALG: () => import_axis_protocol2.NCERT_ALG,
|
|
4946
|
+
NCERT_EXP: () => import_axis_protocol2.NCERT_EXP,
|
|
4947
|
+
NCERT_ISSUER_KID: () => import_axis_protocol2.NCERT_ISSUER_KID,
|
|
4948
|
+
NCERT_KID: () => import_axis_protocol2.NCERT_KID,
|
|
4949
|
+
NCERT_NBF: () => import_axis_protocol2.NCERT_NBF,
|
|
4950
|
+
NCERT_NODE_ID: () => import_axis_protocol2.NCERT_NODE_ID,
|
|
4951
|
+
NCERT_PAYLOAD: () => import_axis_protocol2.NCERT_PAYLOAD,
|
|
4952
|
+
NCERT_PUB: () => import_axis_protocol2.NCERT_PUB,
|
|
4953
|
+
NCERT_SCOPE: () => import_axis_protocol2.NCERT_SCOPE,
|
|
4954
|
+
NCERT_SIG: () => import_axis_protocol2.NCERT_SIG,
|
|
4955
|
+
PROOF_CAPSULE: () => import_axis_protocol2.PROOF_CAPSULE,
|
|
4956
|
+
PROOF_JWT: () => import_axis_protocol2.PROOF_JWT,
|
|
4957
|
+
PROOF_LOOM: () => import_axis_protocol2.PROOF_LOOM,
|
|
4958
|
+
PROOF_MTLS: () => import_axis_protocol2.PROOF_MTLS,
|
|
4959
|
+
PROOF_NONE: () => import_axis_protocol2.PROOF_NONE,
|
|
4960
|
+
PROOF_WITNESS: () => import_axis_protocol2.PROOF_WITNESS,
|
|
4961
|
+
ProofType: () => import_axis_protocol2.ProofType,
|
|
4962
|
+
TLV: () => import_axis_protocol.TLV,
|
|
4963
|
+
TLV_ACTOR_ID: () => import_axis_protocol2.TLV_ACTOR_ID,
|
|
4964
|
+
TLV_AUD: () => import_axis_protocol2.TLV_AUD,
|
|
4965
|
+
TLV_BODY_ARR: () => import_axis_protocol2.TLV_BODY_ARR,
|
|
4966
|
+
TLV_BODY_OBJ: () => import_axis_protocol2.TLV_BODY_OBJ,
|
|
4967
|
+
TLV_CAPSULE: () => import_axis_protocol2.TLV_CAPSULE,
|
|
4968
|
+
TLV_EFFECT: () => import_axis_protocol2.TLV_EFFECT,
|
|
4969
|
+
TLV_ERROR_CODE: () => import_axis_protocol2.TLV_ERROR_CODE,
|
|
4970
|
+
TLV_ERROR_MSG: () => import_axis_protocol2.TLV_ERROR_MSG,
|
|
4971
|
+
TLV_INDEX: () => import_axis_protocol2.TLV_INDEX,
|
|
4972
|
+
TLV_INTENT: () => import_axis_protocol2.TLV_INTENT,
|
|
4973
|
+
TLV_KID: () => import_axis_protocol2.TLV_KID,
|
|
4974
|
+
TLV_LOOM_PRESENCE_ID: () => import_axis_protocol2.TLV_LOOM_PRESENCE_ID,
|
|
4975
|
+
TLV_LOOM_THREAD_HASH: () => import_axis_protocol2.TLV_LOOM_THREAD_HASH,
|
|
4976
|
+
TLV_LOOM_WRIT: () => import_axis_protocol2.TLV_LOOM_WRIT,
|
|
4977
|
+
TLV_NODE: () => import_axis_protocol2.TLV_NODE,
|
|
4978
|
+
TLV_NODE_CERT_HASH: () => import_axis_protocol2.TLV_NODE_CERT_HASH,
|
|
4979
|
+
TLV_NODE_KID: () => import_axis_protocol2.TLV_NODE_KID,
|
|
4980
|
+
TLV_NONCE: () => import_axis_protocol2.TLV_NONCE,
|
|
4981
|
+
TLV_OFFSET: () => import_axis_protocol2.TLV_OFFSET,
|
|
4982
|
+
TLV_OK: () => import_axis_protocol2.TLV_OK,
|
|
4983
|
+
TLV_PID: () => import_axis_protocol2.TLV_PID,
|
|
4984
|
+
TLV_PREV_HASH: () => import_axis_protocol2.TLV_PREV_HASH,
|
|
4985
|
+
TLV_PROOF_REF: () => import_axis_protocol2.TLV_PROOF_REF,
|
|
4986
|
+
TLV_PROOF_TYPE: () => import_axis_protocol2.TLV_PROOF_TYPE,
|
|
4987
|
+
TLV_REALM: () => import_axis_protocol2.TLV_REALM,
|
|
4988
|
+
TLV_RECEIPT_HASH: () => import_axis_protocol2.TLV_RECEIPT_HASH,
|
|
4989
|
+
TLV_RID: () => import_axis_protocol2.TLV_RID,
|
|
4990
|
+
TLV_SHA256_CHUNK: () => import_axis_protocol2.TLV_SHA256_CHUNK,
|
|
4991
|
+
TLV_TRACE_ID: () => import_axis_protocol2.TLV_TRACE_ID,
|
|
4992
|
+
TLV_TS: () => import_axis_protocol2.TLV_TS,
|
|
4993
|
+
TLV_UPLOAD_ID: () => import_axis_protocol2.TLV_UPLOAD_ID,
|
|
4994
|
+
computeReceiptHash: () => computeReceiptHash,
|
|
4995
|
+
computeSignaturePayload: () => computeSignaturePayload,
|
|
4996
|
+
decodeArray: () => import_axis_protocol.decodeArray,
|
|
4997
|
+
decodeFrame: () => decodeFrame,
|
|
4998
|
+
decodeObject: () => import_axis_protocol.decodeObject,
|
|
4999
|
+
decodeTLVs: () => import_axis_protocol.decodeTLVs,
|
|
5000
|
+
decodeTLVsList: () => import_axis_protocol.decodeTLVsList,
|
|
5001
|
+
decodeVarint: () => import_axis_protocol3.decodeVarint,
|
|
5002
|
+
encodeFrame: () => encodeFrame,
|
|
5003
|
+
encodeTLVs: () => import_axis_protocol.encodeTLVs,
|
|
5004
|
+
encodeVarint: () => import_axis_protocol3.encodeVarint,
|
|
5005
|
+
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
5006
|
+
getSignTarget: () => getSignTarget,
|
|
5007
|
+
sha256: () => sha2564,
|
|
5008
|
+
signFrame: () => signFrame,
|
|
5009
|
+
varintLength: () => import_axis_protocol3.varintLength,
|
|
5010
|
+
verifyFrameSignature: () => verifyFrameSignature
|
|
5011
|
+
});
|
|
5012
|
+
|
|
5013
|
+
// src/crypto/index.ts
|
|
5014
|
+
var crypto_exports = {};
|
|
5015
|
+
__export(crypto_exports, {
|
|
5016
|
+
ProofVerificationService: () => ProofVerificationService,
|
|
5017
|
+
b64urlDecode: () => b64urlDecode,
|
|
5018
|
+
b64urlDecodeString: () => b64urlDecodeString,
|
|
5019
|
+
b64urlEncode: () => b64urlEncode,
|
|
5020
|
+
b64urlEncodeString: () => b64urlEncodeString,
|
|
5021
|
+
canonicalJson: () => canonicalJson,
|
|
5022
|
+
canonicalJsonExcluding: () => canonicalJsonExcluding
|
|
5023
|
+
});
|
|
5024
|
+
|
|
5025
|
+
// src/crypto/proof-verification.service.ts
|
|
5026
|
+
var import_common10 = require("@nestjs/common");
|
|
5027
|
+
var crypto4 = __toESM(require("crypto"));
|
|
5028
|
+
var nacl = __toESM(require("tweetnacl"));
|
|
5029
|
+
var ProofVerificationService = class {
|
|
5030
|
+
constructor() {
|
|
5031
|
+
this.logger = new import_common10.Logger(ProofVerificationService.name);
|
|
5032
|
+
// Cache of registered device public keys (deviceId -> pubKey)
|
|
5033
|
+
this.deviceKeys = /* @__PURE__ */ new Map();
|
|
5034
|
+
// Cache of trusted mTLS certificate fingerprints
|
|
5035
|
+
this.trustedCerts = /* @__PURE__ */ new Map();
|
|
5036
|
+
}
|
|
5037
|
+
/**
|
|
5038
|
+
* Verifies an authentication proof based on its type.
|
|
5039
|
+
*
|
|
5040
|
+
* **Supported Types:**
|
|
5041
|
+
* - 1 (CAPSULE): Delegated to `verifyCapsuleProof`
|
|
5042
|
+
* - 2 (JWT): Verified by `verifyJWTProof`
|
|
5043
|
+
* - 3 (MTLS_ID): Verified by `verifyMTLSProof`
|
|
5044
|
+
* - 4 (DEVICE_SE): Verified by `verifyDeviceSEProof`
|
|
5045
|
+
*
|
|
5046
|
+
* @param {ProofType} proofType - The numeric AXIS proof type
|
|
5047
|
+
* @param {Uint8Array} proofRef - The binary reference or token for the proof
|
|
5048
|
+
* @param {Object} context - Additional metadata required for specific proof types
|
|
5049
|
+
* @param {Uint8Array} [context.signTarget] - The canonical bytes that were signed (for Ed25519)
|
|
5050
|
+
* @param {Uint8Array} [context.signature] - The signature to verify (for Ed25519)
|
|
5051
|
+
* @param {MTLSContext} [context.mtls] - mTLS certificate data
|
|
5052
|
+
* @param {DeviceSEContext} [context.deviceSE] - Device Secure Element information
|
|
5053
|
+
* @returns {Promise<ProofVerificationResult>} The outcome of the verification
|
|
5054
|
+
*/
|
|
5055
|
+
async verifyProof(proofType, proofRef, context) {
|
|
5056
|
+
switch (proofType) {
|
|
5057
|
+
case 1:
|
|
5058
|
+
return this.verifyCapsuleProof(proofRef);
|
|
5059
|
+
case 2:
|
|
5060
|
+
return this.verifyJWTProof(proofRef);
|
|
5061
|
+
case 3:
|
|
5062
|
+
return this.verifyMTLSProof(context.mtls);
|
|
5063
|
+
case 4:
|
|
5064
|
+
return this.verifyDeviceSEProof(
|
|
5065
|
+
context.signTarget,
|
|
5066
|
+
context.signature,
|
|
5067
|
+
context.deviceSE
|
|
5068
|
+
);
|
|
5069
|
+
default:
|
|
5070
|
+
return { valid: false, error: `Unknown proof type: ${proofType}` };
|
|
5071
|
+
}
|
|
5072
|
+
}
|
|
5073
|
+
/**
|
|
5074
|
+
* Verify CAPSULE proof (delegated to CapsuleService)
|
|
5075
|
+
*/
|
|
5076
|
+
async verifyCapsuleProof(proofRef) {
|
|
5077
|
+
const capsuleId = new TextDecoder().decode(proofRef);
|
|
5078
|
+
return {
|
|
5079
|
+
valid: true,
|
|
5080
|
+
metadata: { capsuleId, requiresCapsuleValidation: true }
|
|
5081
|
+
};
|
|
5082
|
+
}
|
|
5083
|
+
/**
|
|
5084
|
+
* Verifies a JSON Web Token (JWT) proof.
|
|
5085
|
+
*
|
|
5086
|
+
* **Validation Logic:**
|
|
5087
|
+
* 1. Decodes the token string.
|
|
5088
|
+
* 2. Checks for valid 3-part JWT structure.
|
|
5089
|
+
* 3. Validates `exp` (expiration) and `nbf` (not before) claims.
|
|
5090
|
+
* 4. Extracts `actor_id` or `sub` as the identity.
|
|
5091
|
+
*
|
|
5092
|
+
* @param {Uint8Array} proofRef - Binary representation of the JWT string
|
|
5093
|
+
* @returns {Promise<ProofVerificationResult>} Result including the actor identifier
|
|
5094
|
+
*/
|
|
5095
|
+
async verifyJWTProof(proofRef) {
|
|
5096
|
+
try {
|
|
5097
|
+
const token = new TextDecoder().decode(proofRef);
|
|
5098
|
+
const parts = token.split(".");
|
|
5099
|
+
if (parts.length !== 3) {
|
|
5100
|
+
return { valid: false, error: "Invalid JWT format" };
|
|
5101
|
+
}
|
|
5102
|
+
const header = JSON.parse(Buffer.from(parts[0], "base64url").toString());
|
|
5103
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
5104
|
+
if (payload.exp && Date.now() / 1e3 > payload.exp) {
|
|
5105
|
+
return { valid: false, error: "JWT expired" };
|
|
5106
|
+
}
|
|
5107
|
+
if (payload.nbf && Date.now() / 1e3 < payload.nbf) {
|
|
5108
|
+
return { valid: false, error: "JWT not yet valid" };
|
|
5109
|
+
}
|
|
5110
|
+
return {
|
|
5111
|
+
valid: true,
|
|
5112
|
+
actorId: payload.sub || payload.actor_id,
|
|
5113
|
+
metadata: { iss: payload.iss, scope: payload.scope }
|
|
5114
|
+
};
|
|
5115
|
+
} catch (e) {
|
|
5116
|
+
const message = e instanceof Error ? e.message : "Unknown error";
|
|
5117
|
+
return { valid: false, error: `JWT parse error: ${message}` };
|
|
5118
|
+
}
|
|
5119
|
+
}
|
|
5120
|
+
/**
|
|
5121
|
+
* Verify mTLS client certificate proof
|
|
5122
|
+
*/
|
|
5123
|
+
async verifyMTLSProof(mtls) {
|
|
5124
|
+
if (!mtls) {
|
|
5125
|
+
return { valid: false, error: "No mTLS context provided" };
|
|
5126
|
+
}
|
|
5127
|
+
if (!mtls.verified) {
|
|
5128
|
+
return { valid: false, error: "mTLS not verified by TLS terminator" };
|
|
5129
|
+
}
|
|
5130
|
+
if (mtls.clientCertFingerprint) {
|
|
5131
|
+
const trusted = this.trustedCerts.get(mtls.clientCertFingerprint);
|
|
5132
|
+
if (trusted) {
|
|
5133
|
+
return {
|
|
5134
|
+
valid: true,
|
|
5135
|
+
actorId: trusted.actorId,
|
|
5136
|
+
metadata: {
|
|
5137
|
+
fingerprint: mtls.clientCertFingerprint,
|
|
5138
|
+
subject: mtls.clientCertSubject
|
|
5139
|
+
}
|
|
5140
|
+
};
|
|
5141
|
+
}
|
|
3666
5142
|
}
|
|
3667
|
-
|
|
3668
|
-
|
|
3669
|
-
|
|
3670
|
-
|
|
3671
|
-
|
|
3672
|
-
|
|
3673
|
-
|
|
3674
|
-
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
);
|
|
5143
|
+
if (mtls.clientCertSubject) {
|
|
5144
|
+
const cnMatch = mtls.clientCertSubject.match(/CN=([^,]+)/);
|
|
5145
|
+
if (cnMatch) {
|
|
5146
|
+
return {
|
|
5147
|
+
valid: true,
|
|
5148
|
+
actorId: cnMatch[1],
|
|
5149
|
+
metadata: {
|
|
5150
|
+
subject: mtls.clientCertSubject,
|
|
5151
|
+
issuer: mtls.clientCertIssuer
|
|
5152
|
+
}
|
|
5153
|
+
};
|
|
5154
|
+
}
|
|
5155
|
+
}
|
|
5156
|
+
return { valid: false, error: "Could not extract actor from certificate" };
|
|
3682
5157
|
}
|
|
3683
5158
|
/**
|
|
3684
|
-
*
|
|
3685
|
-
* These sensors run in middleware on raw bytes before frame decoding.
|
|
3686
|
-
*
|
|
3687
|
-
* @returns {AxisPreSensor[]} Pre-decode sensors sorted by order
|
|
5159
|
+
* Verify Device Secure Element signature
|
|
3688
5160
|
*/
|
|
3689
|
-
|
|
3690
|
-
|
|
5161
|
+
async verifyDeviceSEProof(signTarget, signature, deviceSE) {
|
|
5162
|
+
if (!deviceSE || !signTarget || !signature) {
|
|
5163
|
+
return { valid: false, error: "Missing Device SE context" };
|
|
5164
|
+
}
|
|
5165
|
+
let publicKey = deviceSE.publicKey;
|
|
5166
|
+
const registeredKey = this.deviceKeys.get(deviceSE.deviceId);
|
|
5167
|
+
if (registeredKey) {
|
|
5168
|
+
publicKey = registeredKey;
|
|
5169
|
+
}
|
|
5170
|
+
if (!publicKey || publicKey.length !== 32) {
|
|
5171
|
+
return {
|
|
5172
|
+
valid: false,
|
|
5173
|
+
error: "Invalid or unregistered device public key"
|
|
5174
|
+
};
|
|
5175
|
+
}
|
|
5176
|
+
try {
|
|
5177
|
+
const valid = nacl.sign.detached.verify(signTarget, signature, publicKey);
|
|
5178
|
+
if (!valid) {
|
|
5179
|
+
return { valid: false, error: "Device signature verification failed" };
|
|
5180
|
+
}
|
|
5181
|
+
return {
|
|
5182
|
+
valid: true,
|
|
5183
|
+
actorId: deviceSE.deviceId,
|
|
5184
|
+
metadata: { deviceId: deviceSE.deviceId, proofType: "DEVICE_SE" }
|
|
5185
|
+
};
|
|
5186
|
+
} catch (e) {
|
|
5187
|
+
const message = e instanceof Error ? e.message : "Unknown error";
|
|
5188
|
+
return {
|
|
5189
|
+
valid: false,
|
|
5190
|
+
error: `Signature verification error: ${message}`
|
|
5191
|
+
};
|
|
5192
|
+
}
|
|
3691
5193
|
}
|
|
3692
5194
|
/**
|
|
3693
|
-
*
|
|
3694
|
-
*
|
|
5195
|
+
* Registers a public key for a trusted device.
|
|
5196
|
+
* This key will be used for future `DEVICE_SE` proof verifications.
|
|
3695
5197
|
*
|
|
3696
|
-
* @
|
|
5198
|
+
* @param {string} deviceId - Unique identifier for the device
|
|
5199
|
+
* @param {Uint8Array} publicKey - 32-byte Ed25519 public key
|
|
5200
|
+
* @throws {Error} If the public key is not 32 bytes
|
|
3697
5201
|
*/
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
5202
|
+
registerDeviceKey(deviceId, publicKey) {
|
|
5203
|
+
if (publicKey.length !== 32) {
|
|
5204
|
+
throw new Error("Device public key must be 32 bytes (Ed25519)");
|
|
5205
|
+
}
|
|
5206
|
+
this.deviceKeys.set(deviceId, publicKey);
|
|
5207
|
+
this.logger.log(`Registered device key for ${deviceId}`);
|
|
3702
5208
|
}
|
|
3703
5209
|
/**
|
|
3704
|
-
*
|
|
3705
|
-
*
|
|
3706
|
-
* @private
|
|
3707
|
-
* @param {AxisSensor} sensor - The sensor to check
|
|
3708
|
-
* @returns {boolean} True if sensor is pre-decode
|
|
5210
|
+
* Unregister a device
|
|
3709
5211
|
*/
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
return phase === "PRE_DECODE" || (sensor.order ?? 999) < 40;
|
|
5212
|
+
unregisterDevice(deviceId) {
|
|
5213
|
+
return this.deviceKeys.delete(deviceId);
|
|
3713
5214
|
}
|
|
3714
5215
|
/**
|
|
3715
|
-
*
|
|
5216
|
+
* Registers a trusted mTLS certificate fingerprint and associates it with an actor.
|
|
3716
5217
|
*
|
|
3717
|
-
* @
|
|
3718
|
-
* @param {
|
|
3719
|
-
* @returns {boolean} True if sensor is post-decode
|
|
5218
|
+
* @param {string} fingerprint - SHA-256 fingerprint of the client certificate
|
|
5219
|
+
* @param {string} actorId - The actor to associate with this certificate
|
|
3720
5220
|
*/
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
5221
|
+
registerMTLSCert(fingerprint, actorId) {
|
|
5222
|
+
this.trustedCerts.set(fingerprint, { actorId, issuedAt: Date.now() });
|
|
5223
|
+
this.logger.log(`Registered mTLS cert ${fingerprint} for actor ${actorId}`);
|
|
3724
5224
|
}
|
|
3725
5225
|
/**
|
|
3726
|
-
*
|
|
3727
|
-
* Useful for diagnostics and monitoring.
|
|
3728
|
-
*
|
|
3729
|
-
* @returns {{preDecodeCount: number, postDecodeCount: number}}
|
|
5226
|
+
* Revoke an mTLS certificate
|
|
3730
5227
|
*/
|
|
3731
|
-
|
|
3732
|
-
return
|
|
3733
|
-
preDecodeCount: this.getPreDecodeSensors().length,
|
|
3734
|
-
postDecodeCount: this.getPostDecodeSensors().length
|
|
3735
|
-
};
|
|
5228
|
+
revokeMTLSCert(fingerprint) {
|
|
5229
|
+
return this.trustedCerts.delete(fingerprint);
|
|
3736
5230
|
}
|
|
3737
5231
|
/**
|
|
3738
|
-
*
|
|
3739
|
-
* Useful for testing.
|
|
3740
|
-
*
|
|
3741
|
-
* @internal
|
|
5232
|
+
* Calculate certificate fingerprint (SHA-256)
|
|
3742
5233
|
*/
|
|
3743
|
-
|
|
3744
|
-
|
|
5234
|
+
static calculateFingerprint(certPem) {
|
|
5235
|
+
const der = Buffer.from(
|
|
5236
|
+
certPem.replace(/-----BEGIN CERTIFICATE-----/, "").replace(/-----END CERTIFICATE-----/, "").replace(/\s/g, ""),
|
|
5237
|
+
"base64"
|
|
5238
|
+
);
|
|
5239
|
+
return crypto4.createHash("sha256").update(der).digest("hex");
|
|
3745
5240
|
}
|
|
3746
5241
|
};
|
|
3747
|
-
|
|
3748
|
-
(0,
|
|
3749
|
-
],
|
|
5242
|
+
ProofVerificationService = __decorateClass([
|
|
5243
|
+
(0, import_common10.Injectable)()
|
|
5244
|
+
], ProofVerificationService);
|
|
5245
|
+
|
|
5246
|
+
// src/decorators/index.ts
|
|
5247
|
+
var decorators_exports = {};
|
|
5248
|
+
__export(decorators_exports, {
|
|
5249
|
+
AxisContext: () => AxisContext,
|
|
5250
|
+
AxisDemoPubkey: () => AxisDemoPubkey,
|
|
5251
|
+
AxisFrame: () => AxisFrame3,
|
|
5252
|
+
AxisIp: () => AxisIp,
|
|
5253
|
+
AxisRaw: () => AxisRaw,
|
|
5254
|
+
HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
|
|
5255
|
+
Handler: () => Handler,
|
|
5256
|
+
INTENT_BODY_KEY: () => INTENT_BODY_KEY,
|
|
5257
|
+
INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
|
|
5258
|
+
INTENT_ROUTES_KEY: () => INTENT_ROUTES_KEY,
|
|
5259
|
+
INTENT_SENSORS_KEY: () => INTENT_SENSORS_KEY,
|
|
5260
|
+
Intent: () => Intent,
|
|
5261
|
+
IntentBody: () => IntentBody,
|
|
5262
|
+
IntentSensors: () => IntentSensors,
|
|
5263
|
+
SENSOR_METADATA_KEY: () => SENSOR_METADATA_KEY,
|
|
5264
|
+
Sensor: () => Sensor,
|
|
5265
|
+
TLV_FIELDS_KEY: () => TLV_FIELDS_KEY,
|
|
5266
|
+
TLV_VALIDATORS_KEY: () => TLV_VALIDATORS_KEY,
|
|
5267
|
+
TlvEnum: () => TlvEnum,
|
|
5268
|
+
TlvField: () => TlvField,
|
|
5269
|
+
TlvMinLen: () => TlvMinLen,
|
|
5270
|
+
TlvRange: () => TlvRange,
|
|
5271
|
+
TlvUtf8Pattern: () => TlvUtf8Pattern,
|
|
5272
|
+
TlvValidate: () => TlvValidate,
|
|
5273
|
+
buildDtoDecoder: () => buildDtoDecoder,
|
|
5274
|
+
extractDtoSchema: () => extractDtoSchema
|
|
5275
|
+
});
|
|
5276
|
+
|
|
5277
|
+
// src/engine/index.ts
|
|
5278
|
+
var engine_exports = {};
|
|
5279
|
+
__export(engine_exports, {
|
|
5280
|
+
BAND: () => BAND,
|
|
5281
|
+
HandlerDiscoveryService: () => HandlerDiscoveryService,
|
|
5282
|
+
IntentRouter: () => IntentRouter,
|
|
5283
|
+
PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
|
|
5284
|
+
SensorDiscoveryService: () => SensorDiscoveryService,
|
|
5285
|
+
SensorRegistry: () => SensorRegistry,
|
|
5286
|
+
createObservation: () => createObservation,
|
|
5287
|
+
endStage: () => endStage,
|
|
5288
|
+
finalizeObservation: () => finalizeObservation,
|
|
5289
|
+
observation: () => observation_exports,
|
|
5290
|
+
recordSensor: () => recordSensor,
|
|
5291
|
+
startStage: () => startStage
|
|
5292
|
+
});
|
|
3750
5293
|
|
|
3751
5294
|
// src/engine/observation/index.ts
|
|
3752
5295
|
var observation_exports = {};
|
|
@@ -4131,7 +5674,7 @@ var AxisErrorZ = z2.object({
|
|
|
4131
5674
|
});
|
|
4132
5675
|
|
|
4133
5676
|
// src/schemas/body-profile.validator.ts
|
|
4134
|
-
var
|
|
5677
|
+
var import_common11 = require("@nestjs/common");
|
|
4135
5678
|
var BodyProfile2 = /* @__PURE__ */ ((BodyProfile3) => {
|
|
4136
5679
|
BodyProfile3[BodyProfile3["RAW"] = 0] = "RAW";
|
|
4137
5680
|
BodyProfile3[BodyProfile3["TLV_MAP"] = 1] = "TLV_MAP";
|
|
@@ -4141,7 +5684,7 @@ var BodyProfile2 = /* @__PURE__ */ ((BodyProfile3) => {
|
|
|
4141
5684
|
})(BodyProfile2 || {});
|
|
4142
5685
|
var BodyProfileValidator = class {
|
|
4143
5686
|
constructor() {
|
|
4144
|
-
this.logger = new
|
|
5687
|
+
this.logger = new import_common11.Logger(BodyProfileValidator.name);
|
|
4145
5688
|
}
|
|
4146
5689
|
/**
|
|
4147
5690
|
* Validate body matches declared profile
|
|
@@ -4257,12 +5800,13 @@ var BodyProfileValidator = class {
|
|
|
4257
5800
|
}
|
|
4258
5801
|
};
|
|
4259
5802
|
BodyProfileValidator = __decorateClass([
|
|
4260
|
-
(0,
|
|
5803
|
+
(0, import_common11.Injectable)()
|
|
4261
5804
|
], BodyProfileValidator);
|
|
4262
5805
|
|
|
4263
5806
|
// src/security/index.ts
|
|
4264
5807
|
var security_exports = {};
|
|
4265
5808
|
__export(security_exports, {
|
|
5809
|
+
AxisSensorChainService: () => AxisSensorChainService,
|
|
4266
5810
|
CAPABILITIES: () => CAPABILITIES,
|
|
4267
5811
|
INTENT_REQUIREMENTS: () => INTENT_REQUIREMENTS,
|
|
4268
5812
|
PROOF_CAPABILITIES: () => PROOF_CAPABILITIES,
|
|
@@ -4295,7 +5839,7 @@ __export(sensors_exports, {
|
|
|
4295
5839
|
});
|
|
4296
5840
|
|
|
4297
5841
|
// src/sensors/access-profile-resolver.sensor.ts
|
|
4298
|
-
var
|
|
5842
|
+
var import_common12 = require("@nestjs/common");
|
|
4299
5843
|
var AccessProfileResolverSensor = class {
|
|
4300
5844
|
constructor() {
|
|
4301
5845
|
/** AxisSensor identifier */
|
|
@@ -4321,11 +5865,11 @@ var AccessProfileResolverSensor = class {
|
|
|
4321
5865
|
};
|
|
4322
5866
|
AccessProfileResolverSensor = __decorateClass([
|
|
4323
5867
|
Sensor(),
|
|
4324
|
-
(0,
|
|
5868
|
+
(0, import_common12.Injectable)()
|
|
4325
5869
|
], AccessProfileResolverSensor);
|
|
4326
5870
|
|
|
4327
5871
|
// src/sensors/body-budget.sensor.ts
|
|
4328
|
-
var
|
|
5872
|
+
var import_common13 = require("@nestjs/common");
|
|
4329
5873
|
var BodyBudgetSensor = class {
|
|
4330
5874
|
constructor() {
|
|
4331
5875
|
/** AxisSensor identifier */
|
|
@@ -4399,14 +5943,14 @@ var BodyBudgetSensor = class {
|
|
|
4399
5943
|
};
|
|
4400
5944
|
BodyBudgetSensor = __decorateClass([
|
|
4401
5945
|
Sensor(),
|
|
4402
|
-
(0,
|
|
5946
|
+
(0, import_common13.Injectable)()
|
|
4403
5947
|
], BodyBudgetSensor);
|
|
4404
5948
|
|
|
4405
5949
|
// src/sensors/capability-enforcement.sensor.ts
|
|
4406
|
-
var
|
|
5950
|
+
var import_common14 = require("@nestjs/common");
|
|
4407
5951
|
var CapabilityEnforcementSensor = class {
|
|
4408
5952
|
constructor() {
|
|
4409
|
-
this.logger = new
|
|
5953
|
+
this.logger = new import_common14.Logger(CapabilityEnforcementSensor.name);
|
|
4410
5954
|
/** AxisSensor identifier for logging and registry */
|
|
4411
5955
|
this.name = "CapabilityEnforcementSensor";
|
|
4412
5956
|
/**
|
|
@@ -4500,12 +6044,12 @@ var CapabilityEnforcementSensor = class {
|
|
|
4500
6044
|
};
|
|
4501
6045
|
CapabilityEnforcementSensor = __decorateClass([
|
|
4502
6046
|
Sensor(),
|
|
4503
|
-
(0,
|
|
6047
|
+
(0, import_common14.Injectable)()
|
|
4504
6048
|
], CapabilityEnforcementSensor);
|
|
4505
6049
|
|
|
4506
6050
|
// src/sensors/chunk-hash.sensor.ts
|
|
4507
|
-
var
|
|
4508
|
-
var
|
|
6051
|
+
var import_common15 = require("@nestjs/common");
|
|
6052
|
+
var import_crypto8 = require("crypto");
|
|
4509
6053
|
var ChunkHashSensor = class {
|
|
4510
6054
|
constructor() {
|
|
4511
6055
|
/** Sensor identifier */
|
|
@@ -4564,7 +6108,7 @@ var ChunkHashSensor = class {
|
|
|
4564
6108
|
reason: "Missing sha256Chunk TLV in header"
|
|
4565
6109
|
};
|
|
4566
6110
|
}
|
|
4567
|
-
const actual = (0,
|
|
6111
|
+
const actual = (0, import_crypto8.createHash)("sha256").update(bodyBytes).digest();
|
|
4568
6112
|
if (!Buffer.from(actual).equals(Buffer.from(expected))) {
|
|
4569
6113
|
return {
|
|
4570
6114
|
action: "DENY",
|
|
@@ -4577,15 +6121,15 @@ var ChunkHashSensor = class {
|
|
|
4577
6121
|
};
|
|
4578
6122
|
ChunkHashSensor = __decorateClass([
|
|
4579
6123
|
Sensor(),
|
|
4580
|
-
(0,
|
|
6124
|
+
(0, import_common15.Injectable)()
|
|
4581
6125
|
], ChunkHashSensor);
|
|
4582
6126
|
|
|
4583
6127
|
// src/sensors/entropy.sensor.ts
|
|
4584
|
-
var
|
|
4585
|
-
var
|
|
6128
|
+
var import_common16 = require("@nestjs/common");
|
|
6129
|
+
var crypto5 = __toESM(require("crypto"));
|
|
4586
6130
|
var EntropySensor = class {
|
|
4587
6131
|
constructor() {
|
|
4588
|
-
this.logger = new
|
|
6132
|
+
this.logger = new import_common16.Logger(EntropySensor.name);
|
|
4589
6133
|
/**
|
|
4590
6134
|
* Minimum acceptable entropy in bits per byte.
|
|
4591
6135
|
*
|
|
@@ -4750,19 +6294,19 @@ var EntropySensor = class {
|
|
|
4750
6294
|
* @returns {Uint8Array} Cryptographically secure random bytes
|
|
4751
6295
|
*/
|
|
4752
6296
|
static generateSecureRandom(length) {
|
|
4753
|
-
return new Uint8Array(
|
|
6297
|
+
return new Uint8Array(crypto5.randomBytes(length));
|
|
4754
6298
|
}
|
|
4755
6299
|
};
|
|
4756
6300
|
EntropySensor = __decorateClass([
|
|
4757
6301
|
Sensor(),
|
|
4758
|
-
(0,
|
|
6302
|
+
(0, import_common16.Injectable)()
|
|
4759
6303
|
], EntropySensor);
|
|
4760
6304
|
|
|
4761
6305
|
// src/sensors/execution-timeout.sensor.ts
|
|
4762
|
-
var
|
|
6306
|
+
var import_common17 = require("@nestjs/common");
|
|
4763
6307
|
var ExecutionTimeoutSensor = class {
|
|
4764
6308
|
constructor() {
|
|
4765
|
-
this.logger = new
|
|
6309
|
+
this.logger = new import_common17.Logger(ExecutionTimeoutSensor.name);
|
|
4766
6310
|
/** AxisSensor identifier */
|
|
4767
6311
|
this.name = "ExecutionTimeoutSensor";
|
|
4768
6312
|
/**
|
|
@@ -4840,11 +6384,11 @@ var ExecutionTimeoutSensor = class {
|
|
|
4840
6384
|
};
|
|
4841
6385
|
ExecutionTimeoutSensor = __decorateClass([
|
|
4842
6386
|
Sensor(),
|
|
4843
|
-
(0,
|
|
6387
|
+
(0, import_common17.Injectable)()
|
|
4844
6388
|
], ExecutionTimeoutSensor);
|
|
4845
6389
|
|
|
4846
6390
|
// src/sensors/frame-budget.sensor.ts
|
|
4847
|
-
var
|
|
6391
|
+
var import_common18 = require("@nestjs/common");
|
|
4848
6392
|
var FrameBudgetSensor = class {
|
|
4849
6393
|
constructor(config) {
|
|
4850
6394
|
this.config = config;
|
|
@@ -4903,11 +6447,11 @@ var FrameBudgetSensor = class {
|
|
|
4903
6447
|
};
|
|
4904
6448
|
FrameBudgetSensor = __decorateClass([
|
|
4905
6449
|
Sensor({ phase: "PRE_DECODE" }),
|
|
4906
|
-
(0,
|
|
6450
|
+
(0, import_common18.Injectable)()
|
|
4907
6451
|
], FrameBudgetSensor);
|
|
4908
6452
|
|
|
4909
6453
|
// src/sensors/frame-header-sanity.sensor.ts
|
|
4910
|
-
var
|
|
6454
|
+
var import_common19 = require("@nestjs/common");
|
|
4911
6455
|
var FrameHeaderSanitySensor = class {
|
|
4912
6456
|
constructor() {
|
|
4913
6457
|
this.name = "FrameHeaderSanitySensor";
|
|
@@ -4951,12 +6495,12 @@ var FrameHeaderSanitySensor = class {
|
|
|
4951
6495
|
}
|
|
4952
6496
|
};
|
|
4953
6497
|
FrameHeaderSanitySensor = __decorateClass([
|
|
4954
|
-
(0,
|
|
6498
|
+
(0, import_common19.Injectable)(),
|
|
4955
6499
|
Sensor({ phase: "PRE_DECODE" })
|
|
4956
6500
|
], FrameHeaderSanitySensor);
|
|
4957
6501
|
|
|
4958
6502
|
// src/sensors/header-tlv-limit.sensor.ts
|
|
4959
|
-
var
|
|
6503
|
+
var import_common20 = require("@nestjs/common");
|
|
4960
6504
|
var HeaderTLVLimitSensor = class {
|
|
4961
6505
|
constructor() {
|
|
4962
6506
|
this.name = "HeaderTLVLimitSensor";
|
|
@@ -4988,12 +6532,12 @@ var HeaderTLVLimitSensor = class {
|
|
|
4988
6532
|
}
|
|
4989
6533
|
};
|
|
4990
6534
|
HeaderTLVLimitSensor = __decorateClass([
|
|
4991
|
-
(0,
|
|
6535
|
+
(0, import_common20.Injectable)(),
|
|
4992
6536
|
Sensor()
|
|
4993
6537
|
], HeaderTLVLimitSensor);
|
|
4994
6538
|
|
|
4995
6539
|
// src/sensors/intent-allowlist.sensor.ts
|
|
4996
|
-
var
|
|
6540
|
+
var import_common21 = require("@nestjs/common");
|
|
4997
6541
|
var PUBLIC_INTENT_ALLOWLIST = [
|
|
4998
6542
|
"public.",
|
|
4999
6543
|
"schema.",
|
|
@@ -5028,12 +6572,12 @@ var IntentAllowlistSensor = class {
|
|
|
5028
6572
|
}
|
|
5029
6573
|
};
|
|
5030
6574
|
IntentAllowlistSensor = __decorateClass([
|
|
5031
|
-
(0,
|
|
6575
|
+
(0, import_common21.Injectable)(),
|
|
5032
6576
|
Sensor()
|
|
5033
6577
|
], IntentAllowlistSensor);
|
|
5034
6578
|
|
|
5035
6579
|
// src/sensors/intent-registry.sensor.ts
|
|
5036
|
-
var
|
|
6580
|
+
var import_common22 = require("@nestjs/common");
|
|
5037
6581
|
var IntentRegistrySensor = class {
|
|
5038
6582
|
constructor(router) {
|
|
5039
6583
|
this.router = router;
|
|
@@ -5056,12 +6600,12 @@ var IntentRegistrySensor = class {
|
|
|
5056
6600
|
}
|
|
5057
6601
|
};
|
|
5058
6602
|
IntentRegistrySensor = __decorateClass([
|
|
5059
|
-
(0,
|
|
6603
|
+
(0, import_common22.Injectable)(),
|
|
5060
6604
|
Sensor({ phase: "POST_DECODE" })
|
|
5061
6605
|
], IntentRegistrySensor);
|
|
5062
6606
|
|
|
5063
6607
|
// src/sensors/proof-presence.sensor.ts
|
|
5064
|
-
var
|
|
6608
|
+
var import_common23 = require("@nestjs/common");
|
|
5065
6609
|
var ProofPresenceSensor = class {
|
|
5066
6610
|
constructor() {
|
|
5067
6611
|
this.name = "ProofPresenceSensor";
|
|
@@ -5109,11 +6653,11 @@ var ProofPresenceSensor = class {
|
|
|
5109
6653
|
};
|
|
5110
6654
|
ProofPresenceSensor = __decorateClass([
|
|
5111
6655
|
Sensor(),
|
|
5112
|
-
(0,
|
|
6656
|
+
(0, import_common23.Injectable)()
|
|
5113
6657
|
], ProofPresenceSensor);
|
|
5114
6658
|
|
|
5115
6659
|
// src/sensors/protocol-strict.sensor.ts
|
|
5116
|
-
var
|
|
6660
|
+
var import_common24 = require("@nestjs/common");
|
|
5117
6661
|
var VALID_FLAGS = [
|
|
5118
6662
|
0,
|
|
5119
6663
|
// No flags
|
|
@@ -5131,7 +6675,7 @@ var VALID_FLAGS = [
|
|
|
5131
6675
|
var ProtocolStrictSensor = class {
|
|
5132
6676
|
constructor(config) {
|
|
5133
6677
|
this.config = config;
|
|
5134
|
-
this.logger = new
|
|
6678
|
+
this.logger = new import_common24.Logger(ProtocolStrictSensor.name);
|
|
5135
6679
|
/** Sensor identifier for logging and registry */
|
|
5136
6680
|
this.name = "ProtocolStrictSensor";
|
|
5137
6681
|
/**
|
|
@@ -5384,11 +6928,11 @@ var ProtocolStrictSensor = class {
|
|
|
5384
6928
|
};
|
|
5385
6929
|
ProtocolStrictSensor = __decorateClass([
|
|
5386
6930
|
Sensor({ phase: "PRE_DECODE" }),
|
|
5387
|
-
(0,
|
|
6931
|
+
(0, import_common24.Injectable)()
|
|
5388
6932
|
], ProtocolStrictSensor);
|
|
5389
6933
|
|
|
5390
6934
|
// src/sensors/receipt-policy.sensor.ts
|
|
5391
|
-
var
|
|
6935
|
+
var import_common25 = require("@nestjs/common");
|
|
5392
6936
|
var ReceiptPolicySensor = class {
|
|
5393
6937
|
constructor() {
|
|
5394
6938
|
this.name = "ReceiptPolicySensor";
|
|
@@ -5402,12 +6946,12 @@ var ReceiptPolicySensor = class {
|
|
|
5402
6946
|
}
|
|
5403
6947
|
};
|
|
5404
6948
|
ReceiptPolicySensor = __decorateClass([
|
|
5405
|
-
(0,
|
|
6949
|
+
(0, import_common25.Injectable)(),
|
|
5406
6950
|
Sensor()
|
|
5407
6951
|
], ReceiptPolicySensor);
|
|
5408
6952
|
|
|
5409
6953
|
// src/sensors/schema-validation.sensor.ts
|
|
5410
|
-
var
|
|
6954
|
+
var import_common26 = require("@nestjs/common");
|
|
5411
6955
|
function readU64be(b) {
|
|
5412
6956
|
if (b.length !== 8)
|
|
5413
6957
|
throw new AxisError("SCHEMA_TYPE_MISMATCH", "u64 must be 8 bytes", 400);
|
|
@@ -5582,11 +7126,11 @@ var SchemaValidationSensor = class {
|
|
|
5582
7126
|
};
|
|
5583
7127
|
SchemaValidationSensor = __decorateClass([
|
|
5584
7128
|
Sensor(),
|
|
5585
|
-
(0,
|
|
7129
|
+
(0, import_common26.Injectable)()
|
|
5586
7130
|
], SchemaValidationSensor);
|
|
5587
7131
|
|
|
5588
7132
|
// src/sensors/stream-scope.sensor.ts
|
|
5589
|
-
var
|
|
7133
|
+
var import_common27 = require("@nestjs/common");
|
|
5590
7134
|
var StreamScopeSensor = class {
|
|
5591
7135
|
constructor() {
|
|
5592
7136
|
/** Sensor identifier */
|
|
@@ -5632,11 +7176,11 @@ var StreamScopeSensor = class {
|
|
|
5632
7176
|
};
|
|
5633
7177
|
StreamScopeSensor = __decorateClass([
|
|
5634
7178
|
Sensor(),
|
|
5635
|
-
(0,
|
|
7179
|
+
(0, import_common27.Injectable)()
|
|
5636
7180
|
], StreamScopeSensor);
|
|
5637
7181
|
|
|
5638
7182
|
// src/sensors/tlv-parse.sensor.ts
|
|
5639
|
-
var
|
|
7183
|
+
var import_common28 = require("@nestjs/common");
|
|
5640
7184
|
var TLVParseSensor = class {
|
|
5641
7185
|
constructor() {
|
|
5642
7186
|
this.name = "TLVParseSensor";
|
|
@@ -5738,11 +7282,11 @@ var TLVParseSensor = class {
|
|
|
5738
7282
|
};
|
|
5739
7283
|
TLVParseSensor = __decorateClass([
|
|
5740
7284
|
Sensor(),
|
|
5741
|
-
(0,
|
|
7285
|
+
(0, import_common28.Injectable)()
|
|
5742
7286
|
], TLVParseSensor);
|
|
5743
7287
|
|
|
5744
7288
|
// src/sensors/varint-hardening.sensor.ts
|
|
5745
|
-
var
|
|
7289
|
+
var import_common29 = require("@nestjs/common");
|
|
5746
7290
|
var VarintHardeningSensor = class {
|
|
5747
7291
|
constructor() {
|
|
5748
7292
|
/** Sensor identifier */
|
|
@@ -5805,7 +7349,7 @@ var VarintHardeningSensor = class {
|
|
|
5805
7349
|
};
|
|
5806
7350
|
VarintHardeningSensor = __decorateClass([
|
|
5807
7351
|
Sensor({ phase: "PRE_DECODE" }),
|
|
5808
|
-
(0,
|
|
7352
|
+
(0, import_common29.Injectable)()
|
|
5809
7353
|
], VarintHardeningSensor);
|
|
5810
7354
|
|
|
5811
7355
|
// src/utils/index.ts
|
|
@@ -5877,16 +7421,26 @@ function toBuffer(value) {
|
|
|
5877
7421
|
AXIS_UPLOAD_SESSION_STORE,
|
|
5878
7422
|
AXIS_VERSION,
|
|
5879
7423
|
Ats1Codec,
|
|
7424
|
+
AxisContext,
|
|
7425
|
+
AxisDemoPubkey,
|
|
7426
|
+
AxisError,
|
|
5880
7427
|
AxisFilesDownloadHandler,
|
|
5881
7428
|
AxisFilesFinalizeHandler,
|
|
5882
7429
|
AxisFrameZ,
|
|
5883
7430
|
AxisIdDto,
|
|
7431
|
+
AxisIp,
|
|
5884
7432
|
AxisPacketTags,
|
|
5885
7433
|
AxisPartialType,
|
|
7434
|
+
AxisRaw,
|
|
5886
7435
|
AxisResponseDto,
|
|
7436
|
+
AxisSensorChainService,
|
|
5887
7437
|
AxisTlvDto,
|
|
7438
|
+
BAND,
|
|
5888
7439
|
BodyProfile,
|
|
5889
7440
|
CAPABILITIES,
|
|
7441
|
+
CCE_ERROR,
|
|
7442
|
+
CCE_PROTOCOL_VERSION,
|
|
7443
|
+
CceError,
|
|
5890
7444
|
ContractViolationError,
|
|
5891
7445
|
DEFAULT_CONTRACTS,
|
|
5892
7446
|
DEFAULT_TIMEOUT,
|
|
@@ -5902,7 +7456,10 @@ function toBuffer(value) {
|
|
|
5902
7456
|
FLAG_CHAIN_REQ,
|
|
5903
7457
|
FLAG_HAS_WITNESS,
|
|
5904
7458
|
HANDLER_METADATA_KEY,
|
|
7459
|
+
HANDLER_SENSORS_KEY,
|
|
5905
7460
|
Handler,
|
|
7461
|
+
HandlerDiscoveryService,
|
|
7462
|
+
HandlerSensors,
|
|
5906
7463
|
INTENT_BODY_KEY,
|
|
5907
7464
|
INTENT_METADATA_KEY,
|
|
5908
7465
|
INTENT_REQUIREMENTS,
|
|
@@ -5929,6 +7486,7 @@ function toBuffer(value) {
|
|
|
5929
7486
|
NCERT_PUB,
|
|
5930
7487
|
NCERT_SCOPE,
|
|
5931
7488
|
NCERT_SIG,
|
|
7489
|
+
PRE_DECODE_BOUNDARY,
|
|
5932
7490
|
PROOF_CAPABILITIES,
|
|
5933
7491
|
PROOF_CAPSULE,
|
|
5934
7492
|
PROOF_JWT,
|
|
@@ -5943,11 +7501,15 @@ function toBuffer(value) {
|
|
|
5943
7501
|
RESPONSE_TAG_UPDATED_AT,
|
|
5944
7502
|
RESPONSE_TAG_UPDATED_BY,
|
|
5945
7503
|
RiskDecision,
|
|
7504
|
+
SENSOR_METADATA_KEY,
|
|
5946
7505
|
Schema2002_PasskeyLoginOptionsRes,
|
|
5947
7506
|
Schema2011_PasskeyLoginVerifyReq,
|
|
5948
7507
|
Schema2012_PasskeyLoginVerifyRes,
|
|
5949
7508
|
Schema2021_PasskeyRegisterOptionsReq,
|
|
7509
|
+
Sensor,
|
|
5950
7510
|
SensorDecisions,
|
|
7511
|
+
SensorDiscoveryService,
|
|
7512
|
+
SensorRegistry,
|
|
5951
7513
|
TLV,
|
|
5952
7514
|
TLV_ACTOR_ID,
|
|
5953
7515
|
TLV_AUD,
|
|
@@ -6005,10 +7567,12 @@ function toBuffer(value) {
|
|
|
6005
7567
|
canonicalJson,
|
|
6006
7568
|
canonicalJsonExcluding,
|
|
6007
7569
|
canonicalizeObservation,
|
|
7570
|
+
cce,
|
|
6008
7571
|
classifyIntent,
|
|
6009
7572
|
computeReceiptHash,
|
|
6010
7573
|
computeSignaturePayload,
|
|
6011
7574
|
core,
|
|
7575
|
+
createObservation,
|
|
6012
7576
|
crypto,
|
|
6013
7577
|
decodeArray,
|
|
6014
7578
|
decodeAxis1Frame,
|
|
@@ -6025,8 +7589,11 @@ function toBuffer(value) {
|
|
|
6025
7589
|
encodeQueueMessage,
|
|
6026
7590
|
encodeTLVs,
|
|
6027
7591
|
encodeVarint,
|
|
7592
|
+
endStage,
|
|
6028
7593
|
engine,
|
|
7594
|
+
executeCcePipeline,
|
|
6029
7595
|
extractDtoSchema,
|
|
7596
|
+
finalizeObservation,
|
|
6030
7597
|
generateEd25519KeyPair,
|
|
6031
7598
|
getSignTarget,
|
|
6032
7599
|
hasScope,
|
|
@@ -6045,6 +7612,7 @@ function toBuffer(value) {
|
|
|
6045
7612
|
parseAutoClaimEntries,
|
|
6046
7613
|
parseScope,
|
|
6047
7614
|
parseStreamEntries,
|
|
7615
|
+
recordSensor,
|
|
6048
7616
|
resolveTimeout,
|
|
6049
7617
|
schemas,
|
|
6050
7618
|
security,
|
|
@@ -6053,6 +7621,7 @@ function toBuffer(value) {
|
|
|
6053
7621
|
sha256,
|
|
6054
7622
|
signFrame,
|
|
6055
7623
|
stableJsonStringify,
|
|
7624
|
+
startStage,
|
|
6056
7625
|
tlv,
|
|
6057
7626
|
u64be,
|
|
6058
7627
|
unpackPasskeyLoginOptionsReq,
|