@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.mjs
CHANGED
|
@@ -75,6 +75,22 @@ function IntentSensors(sensors) {
|
|
|
75
75
|
};
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
// src/decorators/handler-sensors.decorator.ts
|
|
79
|
+
import "reflect-metadata";
|
|
80
|
+
var HANDLER_SENSORS_KEY = "axis:handler:sensors";
|
|
81
|
+
function HandlerSensors(sensors) {
|
|
82
|
+
return (target) => {
|
|
83
|
+
Reflect.defineMetadata(HANDLER_SENSORS_KEY, sensors, target);
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/decorators/sensor.decorator.ts
|
|
88
|
+
import { SetMetadata as SetMetadata2 } from "@nestjs/common";
|
|
89
|
+
var SENSOR_METADATA_KEY = "axis:sensor";
|
|
90
|
+
function Sensor(options) {
|
|
91
|
+
return SetMetadata2(SENSOR_METADATA_KEY, options ?? true);
|
|
92
|
+
}
|
|
93
|
+
|
|
78
94
|
// src/decorators/tlv-field.decorator.ts
|
|
79
95
|
import "reflect-metadata";
|
|
80
96
|
var TLV_FIELDS_KEY = "axis:tlv:fields";
|
|
@@ -389,6 +405,626 @@ var SensorDecisions = {
|
|
|
389
405
|
}
|
|
390
406
|
};
|
|
391
407
|
|
|
408
|
+
// src/cce/cce-derivation.service.ts
|
|
409
|
+
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
410
|
+
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
411
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
412
|
+
|
|
413
|
+
// src/cce/cce.types.ts
|
|
414
|
+
var CCE_PROTOCOL_VERSION = "cce-v1";
|
|
415
|
+
var CCE_DERIVATION = {
|
|
416
|
+
/** Request execution context */
|
|
417
|
+
REQUEST: "axis:cce:req:v1",
|
|
418
|
+
/** Response execution context */
|
|
419
|
+
RESPONSE: "axis:cce:resp:v1",
|
|
420
|
+
/** Witness binding context */
|
|
421
|
+
WITNESS: "axis:cce:witness:v1"
|
|
422
|
+
};
|
|
423
|
+
var CCE_AES_KEY_BYTES = 32;
|
|
424
|
+
var CCE_IV_BYTES = 12;
|
|
425
|
+
var CCE_TAG_BYTES = 16;
|
|
426
|
+
var CCE_NONCE_BYTES = 32;
|
|
427
|
+
var CCE_ERROR = {
|
|
428
|
+
// Envelope errors
|
|
429
|
+
INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
|
|
430
|
+
UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
|
|
431
|
+
MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
|
|
432
|
+
MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
|
|
433
|
+
// Signature errors
|
|
434
|
+
CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
|
|
435
|
+
CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
|
|
436
|
+
// Capsule errors
|
|
437
|
+
CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
|
|
438
|
+
CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
|
|
439
|
+
CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
|
|
440
|
+
CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
|
|
441
|
+
CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
|
|
442
|
+
// Binding errors
|
|
443
|
+
AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
|
|
444
|
+
INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
|
|
445
|
+
TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
|
|
446
|
+
TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
|
|
447
|
+
// Replay / nonce errors
|
|
448
|
+
REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
|
|
449
|
+
NONCE_REUSED: "CCE_NONCE_REUSED",
|
|
450
|
+
// Decryption errors
|
|
451
|
+
DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
|
|
452
|
+
KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
|
|
453
|
+
AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
|
|
454
|
+
PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
|
|
455
|
+
// Schema / validation errors
|
|
456
|
+
PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
|
|
457
|
+
INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
|
|
458
|
+
// Policy errors
|
|
459
|
+
POLICY_DENIED: "CCE_POLICY_DENIED",
|
|
460
|
+
CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
|
|
461
|
+
// Handler errors
|
|
462
|
+
HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
|
|
463
|
+
HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
|
|
464
|
+
HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
|
|
465
|
+
// Response errors
|
|
466
|
+
RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
|
|
467
|
+
};
|
|
468
|
+
var CceError = class extends Error {
|
|
469
|
+
constructor(code, message, metadata) {
|
|
470
|
+
super(`[${code}] ${message}`);
|
|
471
|
+
this.code = code;
|
|
472
|
+
this.metadata = metadata;
|
|
473
|
+
this.name = "CceError";
|
|
474
|
+
}
|
|
475
|
+
/** Whether this error is safe to expose to the client */
|
|
476
|
+
get clientSafe() {
|
|
477
|
+
const internal = [
|
|
478
|
+
CCE_ERROR.DECRYPTION_FAILED,
|
|
479
|
+
CCE_ERROR.KEY_UNWRAP_FAILED,
|
|
480
|
+
CCE_ERROR.AEAD_TAG_MISMATCH,
|
|
481
|
+
CCE_ERROR.HANDLER_EXECUTION_FAILED,
|
|
482
|
+
CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
|
|
483
|
+
];
|
|
484
|
+
return !internal.includes(this.code);
|
|
485
|
+
}
|
|
486
|
+
/** Get client-safe representation */
|
|
487
|
+
toClientError() {
|
|
488
|
+
if (this.clientSafe) {
|
|
489
|
+
return { code: this.code, message: this.message };
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
493
|
+
message: "Request processing failed"
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
};
|
|
497
|
+
|
|
498
|
+
// src/cce/cce-derivation.service.ts
|
|
499
|
+
function buildSalt(capsuleId, capsuleNonce, requestNonce) {
|
|
500
|
+
const encoder = new TextEncoder();
|
|
501
|
+
const data = encoder.encode(
|
|
502
|
+
capsuleId + "|" + capsuleNonce + "|" + requestNonce
|
|
503
|
+
);
|
|
504
|
+
return sha256(data);
|
|
505
|
+
}
|
|
506
|
+
function buildInfo(contextPrefix, capsule, extraNonce) {
|
|
507
|
+
const encoder = new TextEncoder();
|
|
508
|
+
const parts = [
|
|
509
|
+
contextPrefix,
|
|
510
|
+
capsule.sub,
|
|
511
|
+
capsule.kid,
|
|
512
|
+
capsule.intent,
|
|
513
|
+
capsule.aud,
|
|
514
|
+
String(capsule.tps_from),
|
|
515
|
+
String(capsule.tps_to),
|
|
516
|
+
capsule.policy_hash ?? "",
|
|
517
|
+
capsule.ver
|
|
518
|
+
];
|
|
519
|
+
if (extraNonce) {
|
|
520
|
+
parts.push(extraNonce);
|
|
521
|
+
}
|
|
522
|
+
return encoder.encode(parts.join("|"));
|
|
523
|
+
}
|
|
524
|
+
function deriveRequestExecutionKey(input) {
|
|
525
|
+
const ikm = hexToBytes(input.axisLocalSecret);
|
|
526
|
+
const salt = buildSalt(
|
|
527
|
+
input.capsule.capsule_id,
|
|
528
|
+
input.capsule.capsule_nonce,
|
|
529
|
+
input.requestNonce
|
|
530
|
+
);
|
|
531
|
+
const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
|
|
532
|
+
return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
533
|
+
}
|
|
534
|
+
function deriveResponseExecutionKey(input) {
|
|
535
|
+
const ikm = hexToBytes(input.axisLocalSecret);
|
|
536
|
+
const encoder = new TextEncoder();
|
|
537
|
+
const saltData = encoder.encode(
|
|
538
|
+
input.capsule.capsule_id + "|" + input.capsule.capsule_nonce + "|" + input.requestNonce + "|" + input.responseNonce
|
|
539
|
+
);
|
|
540
|
+
const salt = sha256(saltData);
|
|
541
|
+
const info = buildInfo(
|
|
542
|
+
CCE_DERIVATION.RESPONSE,
|
|
543
|
+
input.capsule,
|
|
544
|
+
input.responseNonce
|
|
545
|
+
);
|
|
546
|
+
return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
547
|
+
}
|
|
548
|
+
function deriveWitnessKey(input) {
|
|
549
|
+
const ikm = hexToBytes(input.axisLocalSecret);
|
|
550
|
+
const salt = buildSalt(
|
|
551
|
+
input.capsule.capsule_id,
|
|
552
|
+
input.capsule.capsule_nonce,
|
|
553
|
+
input.requestNonce
|
|
554
|
+
);
|
|
555
|
+
const info = buildInfo(CCE_DERIVATION.WITNESS, input.capsule);
|
|
556
|
+
return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
557
|
+
}
|
|
558
|
+
function buildExecutionContext(input, requestId) {
|
|
559
|
+
const executionKey = deriveRequestExecutionKey(input);
|
|
560
|
+
const keyHash = bytesToHex(sha256(executionKey));
|
|
561
|
+
executionKey.fill(0);
|
|
562
|
+
return {
|
|
563
|
+
execution_key_hash: keyHash,
|
|
564
|
+
request_id: requestId,
|
|
565
|
+
capsule_id: input.capsule.capsule_id,
|
|
566
|
+
sub: input.capsule.sub,
|
|
567
|
+
kid: input.capsule.kid,
|
|
568
|
+
intent: input.capsule.intent,
|
|
569
|
+
aud: input.capsule.aud,
|
|
570
|
+
tps_from: input.capsule.tps_from,
|
|
571
|
+
tps_to: input.capsule.tps_to,
|
|
572
|
+
policy_hash: input.capsule.policy_hash,
|
|
573
|
+
derived_at: Math.floor(Date.now() / 1e3),
|
|
574
|
+
valid: true
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
function generateCceNonce() {
|
|
578
|
+
const bytes2 = new Uint8Array(CCE_NONCE_BYTES);
|
|
579
|
+
crypto.getRandomValues(bytes2);
|
|
580
|
+
return bytesToHex(bytes2);
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// src/cce/cce-response.service.ts
|
|
584
|
+
import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils.js";
|
|
585
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
586
|
+
|
|
587
|
+
// src/cce/cce-crypto.ts
|
|
588
|
+
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
|
|
589
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
|
|
590
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
591
|
+
function aesGcmEncrypt(key, plaintext, aad) {
|
|
592
|
+
if (key.length !== CCE_AES_KEY_BYTES) {
|
|
593
|
+
throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
|
|
594
|
+
}
|
|
595
|
+
const iv = randomBytes(CCE_IV_BYTES);
|
|
596
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
597
|
+
if (aad) {
|
|
598
|
+
cipher.setAAD(aad);
|
|
599
|
+
}
|
|
600
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
601
|
+
const tag = cipher.getAuthTag();
|
|
602
|
+
return {
|
|
603
|
+
iv: new Uint8Array(iv),
|
|
604
|
+
ciphertext: new Uint8Array(encrypted),
|
|
605
|
+
tag: new Uint8Array(tag)
|
|
606
|
+
};
|
|
607
|
+
}
|
|
608
|
+
function aesGcmDecrypt(key, iv, ciphertext, tag, aad) {
|
|
609
|
+
if (key.length !== CCE_AES_KEY_BYTES) {
|
|
610
|
+
throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
|
|
611
|
+
}
|
|
612
|
+
if (iv.length !== CCE_IV_BYTES) {
|
|
613
|
+
throw new Error(`IV must be ${CCE_IV_BYTES} bytes`);
|
|
614
|
+
}
|
|
615
|
+
if (tag.length !== CCE_TAG_BYTES) {
|
|
616
|
+
throw new Error(`Tag must be ${CCE_TAG_BYTES} bytes`);
|
|
617
|
+
}
|
|
618
|
+
try {
|
|
619
|
+
const decipher = createDecipheriv("aes-256-gcm", key, iv);
|
|
620
|
+
decipher.setAuthTag(tag);
|
|
621
|
+
if (aad) {
|
|
622
|
+
decipher.setAAD(aad);
|
|
623
|
+
}
|
|
624
|
+
const decrypted = Buffer.concat([
|
|
625
|
+
decipher.update(ciphertext),
|
|
626
|
+
decipher.final()
|
|
627
|
+
]);
|
|
628
|
+
return new Uint8Array(decrypted);
|
|
629
|
+
} catch {
|
|
630
|
+
return null;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
function generateAesKey() {
|
|
634
|
+
return new Uint8Array(randomBytes(CCE_AES_KEY_BYTES));
|
|
635
|
+
}
|
|
636
|
+
function generateIv() {
|
|
637
|
+
return new Uint8Array(randomBytes(CCE_IV_BYTES));
|
|
638
|
+
}
|
|
639
|
+
function base64UrlEncode(bytes2) {
|
|
640
|
+
return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
641
|
+
}
|
|
642
|
+
function base64UrlDecode(input) {
|
|
643
|
+
const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
644
|
+
const padding = "=".repeat((4 - base64.length % 4) % 4);
|
|
645
|
+
return new Uint8Array(Buffer.from(base64 + padding, "base64"));
|
|
646
|
+
}
|
|
647
|
+
function hashPayload(payload) {
|
|
648
|
+
return bytesToHex2(sha2562(payload));
|
|
649
|
+
}
|
|
650
|
+
var nodeAesGcmProvider = {
|
|
651
|
+
async decrypt(key, iv, ciphertext, tag, aad) {
|
|
652
|
+
return aesGcmDecrypt(key, iv, ciphertext, tag, aad);
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
|
|
656
|
+
// src/cce/cce-response.service.ts
|
|
657
|
+
async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
|
|
658
|
+
const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
|
|
659
|
+
const responseNonce = bytesToHex3(
|
|
660
|
+
new Uint8Array(randomBytes2(CCE_NONCE_BYTES))
|
|
661
|
+
);
|
|
662
|
+
const responseId = generateResponseId();
|
|
663
|
+
const aesKey = generateAesKey();
|
|
664
|
+
const aad = buildResponseAad(
|
|
665
|
+
request.request_id,
|
|
666
|
+
responseId,
|
|
667
|
+
request.correlation_id,
|
|
668
|
+
capsule.capsule_id,
|
|
669
|
+
responseNonce
|
|
670
|
+
);
|
|
671
|
+
const { iv, ciphertext, tag } = aesGcmEncrypt(aesKey, body, aad);
|
|
672
|
+
const encryptedKey = await clientKeyEncryptor.wrapKey(
|
|
673
|
+
aesKey,
|
|
674
|
+
request.client_kid,
|
|
675
|
+
clientPublicKeyHex
|
|
676
|
+
);
|
|
677
|
+
aesKey.fill(0);
|
|
678
|
+
const encryptedPayload = {
|
|
679
|
+
alg: "AES-256-GCM",
|
|
680
|
+
iv: base64UrlEncode(iv),
|
|
681
|
+
ciphertext: base64UrlEncode(ciphertext),
|
|
682
|
+
tag: base64UrlEncode(tag)
|
|
683
|
+
};
|
|
684
|
+
const algorithms = {
|
|
685
|
+
kem: encryptedKey.alg,
|
|
686
|
+
enc: "AES-256-GCM",
|
|
687
|
+
kdf: "HKDF-SHA256",
|
|
688
|
+
sig: "EdDSA"
|
|
689
|
+
};
|
|
690
|
+
const unsignedResponse = {
|
|
691
|
+
ver: CCE_PROTOCOL_VERSION,
|
|
692
|
+
response_id: responseId,
|
|
693
|
+
request_id: request.request_id,
|
|
694
|
+
correlation_id: request.correlation_id,
|
|
695
|
+
encrypted_key: encryptedKey,
|
|
696
|
+
encrypted_payload: encryptedPayload,
|
|
697
|
+
response_nonce: responseNonce,
|
|
698
|
+
algorithms,
|
|
699
|
+
status,
|
|
700
|
+
...witnessRef ? { witness_ref: witnessRef } : {}
|
|
701
|
+
};
|
|
702
|
+
const signPayload = new TextEncoder().encode(canonicalize(unsignedResponse));
|
|
703
|
+
const axisSig = await axisSigner.sign(signPayload);
|
|
704
|
+
const envelope = {
|
|
705
|
+
...unsignedResponse,
|
|
706
|
+
axis_sig: axisSig
|
|
707
|
+
};
|
|
708
|
+
return {
|
|
709
|
+
envelope,
|
|
710
|
+
responsePayloadHash: hashPayload(body)
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
function buildCceErrorResponse(requestId, correlationId, status, errorCode, message) {
|
|
714
|
+
return {
|
|
715
|
+
ver: CCE_PROTOCOL_VERSION,
|
|
716
|
+
request_id: requestId,
|
|
717
|
+
correlation_id: correlationId,
|
|
718
|
+
status,
|
|
719
|
+
error: { code: errorCode, message }
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
function generateResponseId() {
|
|
723
|
+
const bytes2 = randomBytes2(16);
|
|
724
|
+
return "resp_" + bytesToHex3(new Uint8Array(bytes2)).slice(0, 24);
|
|
725
|
+
}
|
|
726
|
+
function buildResponseAad(requestId, responseId, correlationId, capsuleId, responseNonce) {
|
|
727
|
+
const parts = [
|
|
728
|
+
requestId,
|
|
729
|
+
responseId,
|
|
730
|
+
correlationId,
|
|
731
|
+
capsuleId,
|
|
732
|
+
responseNonce
|
|
733
|
+
];
|
|
734
|
+
return new TextEncoder().encode(parts.join("|"));
|
|
735
|
+
}
|
|
736
|
+
function canonicalize(obj) {
|
|
737
|
+
if (Array.isArray(obj)) {
|
|
738
|
+
return "[" + obj.map(canonicalize).join(",") + "]";
|
|
739
|
+
}
|
|
740
|
+
if (obj !== null && typeof obj === "object") {
|
|
741
|
+
const sorted = Object.keys(obj).sort().map(
|
|
742
|
+
(k) => JSON.stringify(k) + ":" + canonicalize(obj[k])
|
|
743
|
+
);
|
|
744
|
+
return "{" + sorted.join(",") + "}";
|
|
745
|
+
}
|
|
746
|
+
return JSON.stringify(obj);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// src/cce/cce-witness.observer.ts
|
|
750
|
+
import { bytesToHex as bytesToHex4 } from "@noble/hashes/utils.js";
|
|
751
|
+
import { hkdf as hkdf2 } from "@noble/hashes/hkdf.js";
|
|
752
|
+
import { sha256 as sha2563 } from "@noble/hashes/sha2.js";
|
|
753
|
+
var InMemoryCceWitnessStore = class {
|
|
754
|
+
constructor() {
|
|
755
|
+
this.records = [];
|
|
756
|
+
}
|
|
757
|
+
async record(witness) {
|
|
758
|
+
this.records.push(witness);
|
|
759
|
+
}
|
|
760
|
+
getByRequestId(requestId) {
|
|
761
|
+
return this.records.find((w) => w.request_id === requestId);
|
|
762
|
+
}
|
|
763
|
+
getByCapsuleId(capsuleId) {
|
|
764
|
+
return this.records.filter((w) => w.capsule_id === capsuleId);
|
|
765
|
+
}
|
|
766
|
+
};
|
|
767
|
+
function buildWitnessRecord(envelope, capsule, verification, execution, options) {
|
|
768
|
+
const witnessId = generateWitnessId(envelope.request_id, capsule.capsule_id);
|
|
769
|
+
const executionContextHash = computeExecutionContextHash(
|
|
770
|
+
options.axisLocalSecret,
|
|
771
|
+
capsule,
|
|
772
|
+
envelope.request_nonce
|
|
773
|
+
);
|
|
774
|
+
return {
|
|
775
|
+
witness_id: witnessId,
|
|
776
|
+
request_id: envelope.request_id,
|
|
777
|
+
capsule_id: capsule.capsule_id,
|
|
778
|
+
sub: capsule.sub,
|
|
779
|
+
intent: capsule.intent,
|
|
780
|
+
aud: capsule.aud,
|
|
781
|
+
tps_from: capsule.tps_from,
|
|
782
|
+
tps_to: capsule.tps_to,
|
|
783
|
+
timestamp: Math.floor(Date.now() / 1e3),
|
|
784
|
+
verification: {
|
|
785
|
+
client_sig: verification.clientSigVerified,
|
|
786
|
+
capsule_sig: verification.capsuleSigVerified,
|
|
787
|
+
tps_valid: verification.tpsValid,
|
|
788
|
+
audience_match: verification.audienceMatch,
|
|
789
|
+
intent_match: verification.intentMatch,
|
|
790
|
+
replay_clean: verification.replayClean,
|
|
791
|
+
nonce_unique: verification.nonceUnique,
|
|
792
|
+
decryption_ok: verification.decryptionOk
|
|
793
|
+
},
|
|
794
|
+
execution: {
|
|
795
|
+
status: execution.status,
|
|
796
|
+
handler_duration_ms: execution.handlerDurationMs,
|
|
797
|
+
...execution.effect ? { effect: execution.effect } : {}
|
|
798
|
+
},
|
|
799
|
+
response_encrypted: options.responseEncrypted,
|
|
800
|
+
execution_context_hash: executionContextHash,
|
|
801
|
+
...options.requestPayload ? { request_payload_hash: hashPayload(options.requestPayload) } : {},
|
|
802
|
+
...options.responsePayload ? { response_payload_hash: hashPayload(options.responsePayload) } : {}
|
|
803
|
+
};
|
|
804
|
+
}
|
|
805
|
+
function extractVerificationState(metadata) {
|
|
806
|
+
return {
|
|
807
|
+
clientSigVerified: metadata.cceClientSigVerified === true,
|
|
808
|
+
capsuleSigVerified: metadata.cceCapsuleVerified === true,
|
|
809
|
+
tpsValid: metadata.cceTpsValid === true,
|
|
810
|
+
audienceMatch: metadata.cceBindingVerified === true,
|
|
811
|
+
intentMatch: metadata.cceBindingVerified === true,
|
|
812
|
+
replayClean: metadata.cceReplayClean === true,
|
|
813
|
+
nonceUnique: metadata.cceReplayClean === true,
|
|
814
|
+
decryptionOk: metadata.cceDecryptionOk === true
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
function generateWitnessId(requestId, capsuleId) {
|
|
818
|
+
const input = `witness:${requestId}:${capsuleId}:${Date.now()}`;
|
|
819
|
+
const hash = sha2563(new TextEncoder().encode(input));
|
|
820
|
+
return "wit_" + bytesToHex4(hash).slice(0, 24);
|
|
821
|
+
}
|
|
822
|
+
function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
|
|
823
|
+
const encoder = new TextEncoder();
|
|
824
|
+
const ikm = hexToBytes2(axisLocalSecret);
|
|
825
|
+
const salt = sha2563(
|
|
826
|
+
encoder.encode(
|
|
827
|
+
capsule.capsule_id + "|" + capsule.capsule_nonce + "|" + requestNonce
|
|
828
|
+
)
|
|
829
|
+
);
|
|
830
|
+
const info = encoder.encode(
|
|
831
|
+
[
|
|
832
|
+
CCE_DERIVATION.WITNESS,
|
|
833
|
+
capsule.sub,
|
|
834
|
+
capsule.kid,
|
|
835
|
+
capsule.intent,
|
|
836
|
+
capsule.aud,
|
|
837
|
+
String(capsule.tps_from),
|
|
838
|
+
String(capsule.tps_to),
|
|
839
|
+
capsule.policy_hash ?? "",
|
|
840
|
+
capsule.ver
|
|
841
|
+
].join("|")
|
|
842
|
+
);
|
|
843
|
+
const witnessKey = hkdf2(sha2563, ikm, salt, info, 32);
|
|
844
|
+
const hash = bytesToHex4(sha2563(witnessKey));
|
|
845
|
+
witnessKey.fill(0);
|
|
846
|
+
return hash;
|
|
847
|
+
}
|
|
848
|
+
function hexToBytes2(hex) {
|
|
849
|
+
const bytes2 = new Uint8Array(hex.length / 2);
|
|
850
|
+
for (let i = 0; i < bytes2.length; i++) {
|
|
851
|
+
bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
852
|
+
}
|
|
853
|
+
return bytes2;
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// src/cce/cce-pipeline.ts
|
|
857
|
+
async function executeCcePipeline(envelope, config) {
|
|
858
|
+
const startTime = Date.now();
|
|
859
|
+
if (envelope.ver !== CCE_PROTOCOL_VERSION) {
|
|
860
|
+
return {
|
|
861
|
+
ok: false,
|
|
862
|
+
error: {
|
|
863
|
+
code: CCE_ERROR.UNSUPPORTED_VERSION,
|
|
864
|
+
message: `Unsupported version: ${envelope.ver}`
|
|
865
|
+
},
|
|
866
|
+
status: "ERROR"
|
|
867
|
+
};
|
|
868
|
+
}
|
|
869
|
+
const sensorInput = {
|
|
870
|
+
intent: envelope.capsule.intent,
|
|
871
|
+
metadata: {
|
|
872
|
+
cce: true,
|
|
873
|
+
cceEnvelope: envelope,
|
|
874
|
+
contentType: "application/axis-cce"
|
|
875
|
+
}
|
|
876
|
+
};
|
|
877
|
+
const sortedSensors = [...config.sensors].sort(
|
|
878
|
+
(a, b) => (a.order ?? 999) - (b.order ?? 999)
|
|
879
|
+
);
|
|
880
|
+
for (const sensor of sortedSensors) {
|
|
881
|
+
if (sensor.supports && !sensor.supports(sensorInput)) {
|
|
882
|
+
continue;
|
|
883
|
+
}
|
|
884
|
+
let decision;
|
|
885
|
+
try {
|
|
886
|
+
decision = await sensor.run(sensorInput);
|
|
887
|
+
} catch (err) {
|
|
888
|
+
return {
|
|
889
|
+
ok: false,
|
|
890
|
+
error: {
|
|
891
|
+
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
892
|
+
message: `Sensor ${sensor.name} failed`
|
|
893
|
+
},
|
|
894
|
+
status: "ERROR"
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
const normalized = normalizeSensorDecision(decision);
|
|
898
|
+
if (!normalized.allow) {
|
|
899
|
+
const code = normalized.reasons[0]?.split(":")[0] ?? CCE_ERROR.DECRYPTION_FAILED;
|
|
900
|
+
return {
|
|
901
|
+
ok: false,
|
|
902
|
+
error: { code, message: normalized.reasons.join("; ") },
|
|
903
|
+
status: "DENIED"
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
const capsule = sensorInput.metadata?.cceCapsule;
|
|
908
|
+
const decryptedPayload = sensorInput.metadata?.cceDecryptedPayload;
|
|
909
|
+
const clientKey = sensorInput.metadata?.cceClientKey;
|
|
910
|
+
if (!capsule || !decryptedPayload || !clientKey) {
|
|
911
|
+
return {
|
|
912
|
+
ok: false,
|
|
913
|
+
error: {
|
|
914
|
+
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
915
|
+
message: "Sensor chain did not produce required outputs"
|
|
916
|
+
},
|
|
917
|
+
status: "ERROR"
|
|
918
|
+
};
|
|
919
|
+
}
|
|
920
|
+
const derivationInput = {
|
|
921
|
+
axisLocalSecret: config.axisLocalSecret,
|
|
922
|
+
capsule,
|
|
923
|
+
requestNonce: envelope.request_nonce
|
|
924
|
+
};
|
|
925
|
+
const executionContext = buildExecutionContext(
|
|
926
|
+
derivationInput,
|
|
927
|
+
envelope.request_id
|
|
928
|
+
);
|
|
929
|
+
const handler = config.handlers.get(capsule.intent);
|
|
930
|
+
if (!handler) {
|
|
931
|
+
return {
|
|
932
|
+
ok: false,
|
|
933
|
+
error: {
|
|
934
|
+
code: CCE_ERROR.HANDLER_NOT_FOUND,
|
|
935
|
+
message: `No handler for intent: ${capsule.intent}`
|
|
936
|
+
},
|
|
937
|
+
status: "ERROR"
|
|
938
|
+
};
|
|
939
|
+
}
|
|
940
|
+
const handlerContext = {
|
|
941
|
+
capsule,
|
|
942
|
+
executionContext,
|
|
943
|
+
envelope,
|
|
944
|
+
clientPublicKeyHex: clientKey.publicKeyHex,
|
|
945
|
+
intent: capsule.intent,
|
|
946
|
+
sub: capsule.sub
|
|
947
|
+
};
|
|
948
|
+
let result;
|
|
949
|
+
const handlerStart = Date.now();
|
|
950
|
+
try {
|
|
951
|
+
result = await handler(decryptedPayload, handlerContext);
|
|
952
|
+
} catch (err) {
|
|
953
|
+
const handlerDuration2 = Date.now() - handlerStart;
|
|
954
|
+
const verification2 = extractVerificationState(sensorInput.metadata ?? {});
|
|
955
|
+
const witness2 = buildWitnessRecord(
|
|
956
|
+
envelope,
|
|
957
|
+
capsule,
|
|
958
|
+
verification2,
|
|
959
|
+
{ status: "FAILED", handlerDurationMs: handlerDuration2 },
|
|
960
|
+
{
|
|
961
|
+
axisLocalSecret: config.axisLocalSecret,
|
|
962
|
+
requestPayload: decryptedPayload,
|
|
963
|
+
responseEncrypted: false
|
|
964
|
+
}
|
|
965
|
+
);
|
|
966
|
+
await config.witnessStore.record(witness2);
|
|
967
|
+
return {
|
|
968
|
+
ok: false,
|
|
969
|
+
error: {
|
|
970
|
+
code: CCE_ERROR.HANDLER_EXECUTION_FAILED,
|
|
971
|
+
message: "Handler execution failed"
|
|
972
|
+
},
|
|
973
|
+
status: "FAILED"
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
const handlerDuration = Date.now() - handlerStart;
|
|
977
|
+
let responseEnvelope;
|
|
978
|
+
let responsePayloadHash;
|
|
979
|
+
try {
|
|
980
|
+
const responseResult = await buildCceResponse(
|
|
981
|
+
{
|
|
982
|
+
request: envelope,
|
|
983
|
+
capsule,
|
|
984
|
+
status: result.status,
|
|
985
|
+
body: result.body,
|
|
986
|
+
clientPublicKeyHex: clientKey.publicKeyHex
|
|
987
|
+
},
|
|
988
|
+
config.clientKeyEncryptor,
|
|
989
|
+
config.axisSigner
|
|
990
|
+
);
|
|
991
|
+
responseEnvelope = responseResult.envelope;
|
|
992
|
+
responsePayloadHash = responseResult.responsePayloadHash;
|
|
993
|
+
} catch (err) {
|
|
994
|
+
return {
|
|
995
|
+
ok: false,
|
|
996
|
+
error: {
|
|
997
|
+
code: CCE_ERROR.RESPONSE_ENCRYPTION_FAILED,
|
|
998
|
+
message: "Response encryption failed"
|
|
999
|
+
},
|
|
1000
|
+
status: "ERROR"
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
const verification = extractVerificationState(sensorInput.metadata ?? {});
|
|
1004
|
+
const witness = buildWitnessRecord(
|
|
1005
|
+
envelope,
|
|
1006
|
+
capsule,
|
|
1007
|
+
verification,
|
|
1008
|
+
{
|
|
1009
|
+
status: result.status,
|
|
1010
|
+
handlerDurationMs: handlerDuration,
|
|
1011
|
+
effect: result.effect
|
|
1012
|
+
},
|
|
1013
|
+
{
|
|
1014
|
+
axisLocalSecret: config.axisLocalSecret,
|
|
1015
|
+
requestPayload: decryptedPayload,
|
|
1016
|
+
responsePayload: result.body,
|
|
1017
|
+
responseEncrypted: true
|
|
1018
|
+
}
|
|
1019
|
+
);
|
|
1020
|
+
await config.witnessStore.record(witness);
|
|
1021
|
+
return {
|
|
1022
|
+
ok: true,
|
|
1023
|
+
response: responseEnvelope,
|
|
1024
|
+
witnessId: witness.witness_id
|
|
1025
|
+
};
|
|
1026
|
+
}
|
|
1027
|
+
|
|
392
1028
|
// src/engine/intent.router.ts
|
|
393
1029
|
var IntentRouter = class {
|
|
394
1030
|
constructor(moduleRef) {
|
|
@@ -406,6 +1042,10 @@ var IntentRouter = class {
|
|
|
406
1042
|
this.intentValidators = /* @__PURE__ */ new Map();
|
|
407
1043
|
/** Per-intent operation kind */
|
|
408
1044
|
this.intentKinds = /* @__PURE__ */ new Map();
|
|
1045
|
+
/** CCE handler registry */
|
|
1046
|
+
this.cceHandlers = /* @__PURE__ */ new Map();
|
|
1047
|
+
/** CCE pipeline configuration (set via configureCce) */
|
|
1048
|
+
this.ccePipelineConfig = null;
|
|
409
1049
|
}
|
|
410
1050
|
getSchema(intent) {
|
|
411
1051
|
return this.intentSchemas.get(intent);
|
|
@@ -455,6 +1095,7 @@ var IntentRouter = class {
|
|
|
455
1095
|
);
|
|
456
1096
|
const prefix = handlerMeta?.intent || instance.name;
|
|
457
1097
|
const routes = Reflect.getMetadata(INTENT_ROUTES_KEY, instance.constructor) || [];
|
|
1098
|
+
const handlerSensors = Reflect.getMetadata(HANDLER_SENSORS_KEY, instance.constructor) || [];
|
|
458
1099
|
for (const route of routes) {
|
|
459
1100
|
const intentName = route.absolute ? route.action : `${prefix}.${route.action}`;
|
|
460
1101
|
const fn = instance[route.methodName].bind(instance);
|
|
@@ -463,7 +1104,12 @@ var IntentRouter = class {
|
|
|
463
1104
|
} else {
|
|
464
1105
|
this.register(intentName, fn);
|
|
465
1106
|
}
|
|
466
|
-
this.registerIntentMeta(
|
|
1107
|
+
this.registerIntentMeta(
|
|
1108
|
+
intentName,
|
|
1109
|
+
Object.getPrototypeOf(instance),
|
|
1110
|
+
String(route.methodName),
|
|
1111
|
+
handlerSensors
|
|
1112
|
+
);
|
|
467
1113
|
}
|
|
468
1114
|
const proto = Object.getPrototypeOf(instance);
|
|
469
1115
|
for (const key of Object.getOwnPropertyNames(proto)) {
|
|
@@ -472,7 +1118,7 @@ var IntentRouter = class {
|
|
|
472
1118
|
if (!this.handlers.has(meta.intent)) {
|
|
473
1119
|
this.register(meta.intent, instance[key].bind(instance));
|
|
474
1120
|
}
|
|
475
|
-
this.registerIntentMeta(meta.intent, proto, key);
|
|
1121
|
+
this.registerIntentMeta(meta.intent, proto, key, handlerSensors);
|
|
476
1122
|
}
|
|
477
1123
|
}
|
|
478
1124
|
/**
|
|
@@ -608,14 +1254,22 @@ var IntentRouter = class {
|
|
|
608
1254
|
this.logger.warn(`${intent} failed in ${ms}ms - ${error}`);
|
|
609
1255
|
}
|
|
610
1256
|
}
|
|
611
|
-
registerIntentMeta(intent, proto, methodName) {
|
|
1257
|
+
registerIntentMeta(intent, proto, methodName, handlerSensors) {
|
|
612
1258
|
const decoder = Reflect.getMetadata(INTENT_BODY_KEY, proto, methodName);
|
|
613
1259
|
if (decoder) {
|
|
614
1260
|
this.intentDecoders.set(intent, decoder);
|
|
615
1261
|
}
|
|
616
|
-
const
|
|
617
|
-
|
|
618
|
-
|
|
1262
|
+
const intentSensors = Reflect.getMetadata(
|
|
1263
|
+
INTENT_SENSORS_KEY,
|
|
1264
|
+
proto,
|
|
1265
|
+
methodName
|
|
1266
|
+
);
|
|
1267
|
+
const combined = [
|
|
1268
|
+
...handlerSensors || [],
|
|
1269
|
+
...Array.isArray(intentSensors) ? intentSensors : []
|
|
1270
|
+
];
|
|
1271
|
+
if (combined.length > 0) {
|
|
1272
|
+
this.intentSensors.set(intent, combined);
|
|
619
1273
|
}
|
|
620
1274
|
const meta = Reflect.getMetadata(INTENT_METADATA_KEY, proto, methodName);
|
|
621
1275
|
if (meta) {
|
|
@@ -655,6 +1309,58 @@ var IntentRouter = class {
|
|
|
655
1309
|
}
|
|
656
1310
|
}
|
|
657
1311
|
}
|
|
1312
|
+
// ===========================================================================
|
|
1313
|
+
// CCE — Capsule-Carried Encryption Support
|
|
1314
|
+
// ===========================================================================
|
|
1315
|
+
/**
|
|
1316
|
+
* Configure the CCE pipeline.
|
|
1317
|
+
* Must be called before routeCce() can process encrypted requests.
|
|
1318
|
+
*/
|
|
1319
|
+
configureCce(config) {
|
|
1320
|
+
this.ccePipelineConfig = config;
|
|
1321
|
+
this.logger.log("CCE pipeline configured");
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Register a CCE-encrypted intent handler.
|
|
1325
|
+
* CCE handlers receive decrypted payloads and execution context.
|
|
1326
|
+
*/
|
|
1327
|
+
registerCceHandler(intent, handler) {
|
|
1328
|
+
this.cceHandlers.set(intent, handler);
|
|
1329
|
+
this.logger.debug(`CCE handler registered: ${intent}`);
|
|
1330
|
+
}
|
|
1331
|
+
/**
|
|
1332
|
+
* Check if a CCE handler exists for the given intent.
|
|
1333
|
+
*/
|
|
1334
|
+
hasCceHandler(intent) {
|
|
1335
|
+
return this.cceHandlers.has(intent);
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Route a CCE-encrypted request through the full pipeline.
|
|
1339
|
+
*
|
|
1340
|
+
* Steps:
|
|
1341
|
+
* 1. Sensor chain (envelope validation → capsule verification → replay → decrypt)
|
|
1342
|
+
* 2. Execution context derivation
|
|
1343
|
+
* 3. Handler execution
|
|
1344
|
+
* 4. Response encryption
|
|
1345
|
+
* 5. Witness recording
|
|
1346
|
+
*/
|
|
1347
|
+
async routeCce(envelope) {
|
|
1348
|
+
if (!this.ccePipelineConfig) {
|
|
1349
|
+
return {
|
|
1350
|
+
ok: false,
|
|
1351
|
+
error: {
|
|
1352
|
+
code: "CCE_NOT_CONFIGURED",
|
|
1353
|
+
message: "CCE pipeline not configured. Call configureCce() first."
|
|
1354
|
+
},
|
|
1355
|
+
status: "ERROR"
|
|
1356
|
+
};
|
|
1357
|
+
}
|
|
1358
|
+
const config = {
|
|
1359
|
+
...this.ccePipelineConfig,
|
|
1360
|
+
handlers: this.cceHandlers
|
|
1361
|
+
};
|
|
1362
|
+
return executeCcePipeline(envelope, config);
|
|
1363
|
+
}
|
|
658
1364
|
storeSchema(meta) {
|
|
659
1365
|
if (meta.dto) {
|
|
660
1366
|
if (meta.tlv && meta.tlv.length > 0) {
|
|
@@ -718,6 +1424,23 @@ IntentRouter = __decorateClass([
|
|
|
718
1424
|
__decorateParam(0, Optional())
|
|
719
1425
|
], IntentRouter);
|
|
720
1426
|
|
|
1427
|
+
// src/engine/sensor-bands.ts
|
|
1428
|
+
var BAND = {
|
|
1429
|
+
/** Pre-decode: raw byte validation, geo, budget, magic */
|
|
1430
|
+
WIRE: 0,
|
|
1431
|
+
/** Post-decode: identity resolution, capsule, proof */
|
|
1432
|
+
IDENTITY: 40,
|
|
1433
|
+
/** Post-decode: authorization, signature, rate limiting */
|
|
1434
|
+
POLICY: 90,
|
|
1435
|
+
/** Post-decode: content validation, TLV, schema, files */
|
|
1436
|
+
CONTENT: 140,
|
|
1437
|
+
/** Post-decode: business logic sensors, streams, WS */
|
|
1438
|
+
BUSINESS: 200,
|
|
1439
|
+
/** Post-decode: audit, logging (always last) */
|
|
1440
|
+
AUDIT: 900
|
|
1441
|
+
};
|
|
1442
|
+
var PRE_DECODE_BOUNDARY = 40;
|
|
1443
|
+
|
|
721
1444
|
// src/engine/observation/stable-json.ts
|
|
722
1445
|
function normalize(value) {
|
|
723
1446
|
if (Array.isArray(value)) {
|
|
@@ -992,7 +1715,7 @@ function verifyResponse(ctx, response) {
|
|
|
992
1715
|
import { encodeVarint, decodeVarint, varintLength } from "@nextera.one/axis-protocol";
|
|
993
1716
|
|
|
994
1717
|
// src/core/signature.ts
|
|
995
|
-
import * as
|
|
1718
|
+
import * as crypto2 from "crypto";
|
|
996
1719
|
|
|
997
1720
|
// src/core/axis-bin.ts
|
|
998
1721
|
import * as z from "zod";
|
|
@@ -1122,19 +1845,19 @@ function signFrame(frame, privateKey) {
|
|
|
1122
1845
|
32
|
|
1123
1846
|
]);
|
|
1124
1847
|
const pkcs8Key = Buffer.concat([pkcs8Prefix, privateKey]);
|
|
1125
|
-
keyObject =
|
|
1848
|
+
keyObject = crypto2.createPrivateKey({
|
|
1126
1849
|
key: pkcs8Key,
|
|
1127
1850
|
format: "der",
|
|
1128
1851
|
type: "pkcs8"
|
|
1129
1852
|
});
|
|
1130
1853
|
} else {
|
|
1131
|
-
keyObject =
|
|
1854
|
+
keyObject = crypto2.createPrivateKey({
|
|
1132
1855
|
key: privateKey,
|
|
1133
1856
|
format: "der",
|
|
1134
1857
|
type: "pkcs8"
|
|
1135
1858
|
});
|
|
1136
1859
|
}
|
|
1137
|
-
const signature =
|
|
1860
|
+
const signature = crypto2.sign(null, payload, keyObject);
|
|
1138
1861
|
if (signature.length !== 64) {
|
|
1139
1862
|
throw new Error("Ed25519 signature must be 64 bytes");
|
|
1140
1863
|
}
|
|
@@ -1166,19 +1889,19 @@ function verifyFrameSignature(frame, publicKey) {
|
|
|
1166
1889
|
0
|
|
1167
1890
|
]);
|
|
1168
1891
|
const spkiKey = Buffer.concat([spkiPrefix, publicKey]);
|
|
1169
|
-
keyObject =
|
|
1892
|
+
keyObject = crypto2.createPublicKey({
|
|
1170
1893
|
key: spkiKey,
|
|
1171
1894
|
format: "der",
|
|
1172
1895
|
type: "spki"
|
|
1173
1896
|
});
|
|
1174
1897
|
} else {
|
|
1175
|
-
keyObject =
|
|
1898
|
+
keyObject = crypto2.createPublicKey({
|
|
1176
1899
|
key: publicKey,
|
|
1177
1900
|
format: "der",
|
|
1178
1901
|
type: "spki"
|
|
1179
1902
|
});
|
|
1180
1903
|
}
|
|
1181
|
-
const valid =
|
|
1904
|
+
const valid = crypto2.verify(
|
|
1182
1905
|
null,
|
|
1183
1906
|
payload,
|
|
1184
1907
|
keyObject,
|
|
@@ -1190,17 +1913,17 @@ function verifyFrameSignature(frame, publicKey) {
|
|
|
1190
1913
|
}
|
|
1191
1914
|
}
|
|
1192
1915
|
function generateEd25519KeyPair() {
|
|
1193
|
-
const { privateKey, publicKey } =
|
|
1916
|
+
const { privateKey, publicKey } = crypto2.generateKeyPairSync("ed25519");
|
|
1194
1917
|
return {
|
|
1195
1918
|
privateKey: privateKey.export({ type: "pkcs8", format: "der" }),
|
|
1196
1919
|
publicKey: publicKey.export({ type: "spki", format: "der" })
|
|
1197
1920
|
};
|
|
1198
1921
|
}
|
|
1199
|
-
function
|
|
1200
|
-
return
|
|
1922
|
+
function sha2564(data) {
|
|
1923
|
+
return crypto2.createHash("sha256").update(data).digest();
|
|
1201
1924
|
}
|
|
1202
1925
|
function computeReceiptHash(receiptBytes, prevHash) {
|
|
1203
|
-
const hasher =
|
|
1926
|
+
const hasher = crypto2.createHash("sha256");
|
|
1204
1927
|
hasher.update(receiptBytes);
|
|
1205
1928
|
if (prevHash && prevHash.length > 0) {
|
|
1206
1929
|
hasher.update(prevHash);
|
|
@@ -1258,7 +1981,7 @@ __export(ats1_exports, {
|
|
|
1258
1981
|
encodeU64BE: () => encodeU64BE,
|
|
1259
1982
|
encodeUVarint: () => encodeUVarint,
|
|
1260
1983
|
logicalBodyToTLVs: () => logicalBodyToTLVs,
|
|
1261
|
-
sha256: () =>
|
|
1984
|
+
sha256: () => sha2565,
|
|
1262
1985
|
tlvsToLogicalBody: () => tlvsToLogicalBody,
|
|
1263
1986
|
tlvsToMap: () => tlvsToMap,
|
|
1264
1987
|
validateTLVsAgainstSchema: () => validateTLVsAgainstSchema
|
|
@@ -1312,7 +2035,7 @@ function decodeU64BE(buf) {
|
|
|
1312
2035
|
if (buf.length !== 8) throw new Error("decodeU64BE: length must be 8");
|
|
1313
2036
|
return buf.readBigUInt64BE(0);
|
|
1314
2037
|
}
|
|
1315
|
-
function
|
|
2038
|
+
function sha2565(data) {
|
|
1316
2039
|
return createHash3("sha256").update(data).digest();
|
|
1317
2040
|
}
|
|
1318
2041
|
function encodeTLV(tag, value) {
|
|
@@ -1629,7 +2352,7 @@ function decodeAxisHeaderFromTLVs(hdrTlvs, limits = DEFAULT_LIMITS) {
|
|
|
1629
2352
|
function encodeAxisRequestBinary(schema, req, limits = DEFAULT_LIMITS) {
|
|
1630
2353
|
const bodyTlvs = logicalBodyToTLVs(schema, req.body, limits);
|
|
1631
2354
|
const bodyBytes = encodeTLVStreamCanonical(bodyTlvs);
|
|
1632
|
-
const bodyHash =
|
|
2355
|
+
const bodyHash = sha2565(bodyBytes);
|
|
1633
2356
|
const hdr = {
|
|
1634
2357
|
...req.hdr,
|
|
1635
2358
|
schemaId: schema.schemaId,
|
|
@@ -1645,7 +2368,7 @@ function decodeAxisRequestBinary(schema, hdrBytes, bodyBytes, limits = DEFAULT_L
|
|
|
1645
2368
|
const hdr = decodeAxisHeaderFromTLVs(hdrTlvs, limits);
|
|
1646
2369
|
if (hdr.schemaId !== schema.schemaId)
|
|
1647
2370
|
throw new Error("decodeAxisRequestBinary: schemaId mismatch");
|
|
1648
|
-
const bh =
|
|
2371
|
+
const bh = sha2565(bodyBytes);
|
|
1649
2372
|
if (!Buffer.from(hdr.bodyHash).equals(bh))
|
|
1650
2373
|
throw new Error("decodeAxisRequestBinary: body_hash mismatch");
|
|
1651
2374
|
const body = tlvsToLogicalBody(schema, bodyTlvs, limits);
|
|
@@ -1718,7 +2441,7 @@ function packPasskeyLoginOptionsReq(params) {
|
|
|
1718
2441
|
}
|
|
1719
2442
|
);
|
|
1720
2443
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
1721
|
-
const bodyHash =
|
|
2444
|
+
const bodyHash = sha2565(body);
|
|
1722
2445
|
const hdr = buildAts1Hdr({
|
|
1723
2446
|
intentId: params.intentId,
|
|
1724
2447
|
schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_OPTIONS_REQ,
|
|
@@ -1787,7 +2510,7 @@ function packPasskeyRegisterOptionsReq(params) {
|
|
|
1787
2510
|
}
|
|
1788
2511
|
);
|
|
1789
2512
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
1790
|
-
const bodyHash =
|
|
2513
|
+
const bodyHash = sha2565(body);
|
|
1791
2514
|
const hdr = buildAts1Hdr({
|
|
1792
2515
|
intentId: params.intentId,
|
|
1793
2516
|
schemaId: ATS1_SCHEMA.PASSKEY_REGISTER_OPTIONS_REQ,
|
|
@@ -1818,7 +2541,7 @@ function packPasskeyLoginVerifyReq(params) {
|
|
|
1818
2541
|
}
|
|
1819
2542
|
});
|
|
1820
2543
|
const body = encodeTLVStreamCanonical(bodyTlvs);
|
|
1821
|
-
const bodyHash =
|
|
2544
|
+
const bodyHash = sha2565(body);
|
|
1822
2545
|
const hdr = buildAts1Hdr({
|
|
1823
2546
|
intentId: params.intentId,
|
|
1824
2547
|
schemaId: ATS1_SCHEMA.PASSKEY_LOGIN_VERIFY_REQ,
|
|
@@ -1902,7 +2625,7 @@ function packPasskeyLoginVerifyRes(params) {
|
|
|
1902
2625
|
}
|
|
1903
2626
|
|
|
1904
2627
|
// src/codec/tlv.encode.ts
|
|
1905
|
-
import { randomBytes as
|
|
2628
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
1906
2629
|
function encVarint(x) {
|
|
1907
2630
|
if (x < 0n) throw new Error("VARINT_NEG");
|
|
1908
2631
|
const out = [];
|
|
@@ -1930,7 +2653,7 @@ function bytes(b) {
|
|
|
1930
2653
|
return Buffer.isBuffer(b) ? b : Buffer.from(b);
|
|
1931
2654
|
}
|
|
1932
2655
|
function nonce16() {
|
|
1933
|
-
return
|
|
2656
|
+
return randomBytes4(16);
|
|
1934
2657
|
}
|
|
1935
2658
|
function tlv(type, value) {
|
|
1936
2659
|
if (!Number.isSafeInteger(type) || type < 0) throw new Error("TLV_BAD_TYPE");
|
|
@@ -2658,7 +3381,7 @@ function isTimestampValid(ts, skewSeconds = 120) {
|
|
|
2658
3381
|
|
|
2659
3382
|
// src/upload/axis-files.handlers.ts
|
|
2660
3383
|
import { Inject, Injectable as Injectable3, Logger as Logger2, Optional as Optional2 } from "@nestjs/common";
|
|
2661
|
-
import * as
|
|
3384
|
+
import * as crypto3 from "crypto";
|
|
2662
3385
|
|
|
2663
3386
|
// src/upload/upload.tokens.ts
|
|
2664
3387
|
var AXIS_UPLOAD_SESSION_STORE = "AXIS_UPLOAD_SESSION_STORE";
|
|
@@ -2759,7 +3482,7 @@ var AxisFilesFinalizeHandler = class {
|
|
|
2759
3482
|
if (!await this.files.hasTemp(fileId)) {
|
|
2760
3483
|
throw new Error("CHUNKS_NOT_FOUND");
|
|
2761
3484
|
}
|
|
2762
|
-
const hash =
|
|
3485
|
+
const hash = crypto3.createHash("sha256");
|
|
2763
3486
|
const rs = this.files.createTempReadStream(fileId);
|
|
2764
3487
|
for await (const chunk of rs) {
|
|
2765
3488
|
hash.update(chunk);
|
|
@@ -2883,92 +3606,54 @@ var DiskUploadFileStore = class {
|
|
|
2883
3606
|
}
|
|
2884
3607
|
};
|
|
2885
3608
|
|
|
2886
|
-
// src/
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
TLV_LOOM_PRESENCE_ID: () => TLV_LOOM_PRESENCE_ID,
|
|
2935
|
-
TLV_LOOM_THREAD_HASH: () => TLV_LOOM_THREAD_HASH,
|
|
2936
|
-
TLV_LOOM_WRIT: () => TLV_LOOM_WRIT,
|
|
2937
|
-
TLV_NODE: () => TLV_NODE,
|
|
2938
|
-
TLV_NODE_CERT_HASH: () => TLV_NODE_CERT_HASH,
|
|
2939
|
-
TLV_NODE_KID: () => TLV_NODE_KID,
|
|
2940
|
-
TLV_NONCE: () => TLV_NONCE,
|
|
2941
|
-
TLV_OFFSET: () => TLV_OFFSET,
|
|
2942
|
-
TLV_OK: () => TLV_OK,
|
|
2943
|
-
TLV_PID: () => TLV_PID,
|
|
2944
|
-
TLV_PREV_HASH: () => TLV_PREV_HASH,
|
|
2945
|
-
TLV_PROOF_REF: () => TLV_PROOF_REF,
|
|
2946
|
-
TLV_PROOF_TYPE: () => TLV_PROOF_TYPE,
|
|
2947
|
-
TLV_REALM: () => TLV_REALM,
|
|
2948
|
-
TLV_RECEIPT_HASH: () => TLV_RECEIPT_HASH,
|
|
2949
|
-
TLV_RID: () => TLV_RID,
|
|
2950
|
-
TLV_SHA256_CHUNK: () => TLV_SHA256_CHUNK,
|
|
2951
|
-
TLV_TRACE_ID: () => TLV_TRACE_ID,
|
|
2952
|
-
TLV_TS: () => TLV_TS,
|
|
2953
|
-
TLV_UPLOAD_ID: () => TLV_UPLOAD_ID,
|
|
2954
|
-
computeReceiptHash: () => computeReceiptHash,
|
|
2955
|
-
computeSignaturePayload: () => computeSignaturePayload,
|
|
2956
|
-
decodeArray: () => decodeArray,
|
|
2957
|
-
decodeFrame: () => decodeFrame,
|
|
2958
|
-
decodeObject: () => decodeObject,
|
|
2959
|
-
decodeTLVs: () => decodeTLVs,
|
|
2960
|
-
decodeTLVsList: () => decodeTLVsList,
|
|
2961
|
-
decodeVarint: () => decodeVarint,
|
|
2962
|
-
encodeFrame: () => encodeFrame,
|
|
2963
|
-
encodeTLVs: () => encodeTLVs,
|
|
2964
|
-
encodeVarint: () => encodeVarint,
|
|
2965
|
-
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
2966
|
-
getSignTarget: () => getSignTarget,
|
|
2967
|
-
sha256: () => sha256,
|
|
2968
|
-
signFrame: () => signFrame,
|
|
2969
|
-
varintLength: () => varintLength,
|
|
2970
|
-
verifyFrameSignature: () => verifyFrameSignature
|
|
2971
|
-
});
|
|
3609
|
+
// src/decorators/axis-request.decorator.ts
|
|
3610
|
+
import { createParamDecorator } from "@nestjs/common";
|
|
3611
|
+
function resolveIp(req) {
|
|
3612
|
+
return req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress || void 0;
|
|
3613
|
+
}
|
|
3614
|
+
var AxisRaw = createParamDecorator(
|
|
3615
|
+
(_data, ctx) => {
|
|
3616
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3617
|
+
return req.body;
|
|
3618
|
+
}
|
|
3619
|
+
);
|
|
3620
|
+
var AxisIp = createParamDecorator(
|
|
3621
|
+
(_data, ctx) => {
|
|
3622
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3623
|
+
return resolveIp(req);
|
|
3624
|
+
}
|
|
3625
|
+
);
|
|
3626
|
+
var AxisContext = createParamDecorator(
|
|
3627
|
+
(_data, ctx) => {
|
|
3628
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3629
|
+
const axisData = req.axis || {};
|
|
3630
|
+
return {
|
|
3631
|
+
raw: req.body,
|
|
3632
|
+
ip: resolveIp(req),
|
|
3633
|
+
preDecodeInput: axisData.preDecodeInput,
|
|
3634
|
+
frameBytesCount: axisData.frameBytesCount || 0
|
|
3635
|
+
};
|
|
3636
|
+
}
|
|
3637
|
+
);
|
|
3638
|
+
var AxisDemoPubkey = createParamDecorator(
|
|
3639
|
+
(_data, ctx) => {
|
|
3640
|
+
if (process.env.NODE_ENV !== "development") return void 0;
|
|
3641
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3642
|
+
return req.headers["x-demo-pubkey"];
|
|
3643
|
+
}
|
|
3644
|
+
);
|
|
3645
|
+
var AxisFrame3 = createParamDecorator(
|
|
3646
|
+
(_data, ctx) => {
|
|
3647
|
+
const req = ctx.switchToHttp().getRequest();
|
|
3648
|
+
const decoded = req.axisDecoded;
|
|
3649
|
+
if (!decoded) {
|
|
3650
|
+
throw new Error(
|
|
3651
|
+
"@AxisFrame() requires AxisDecodeInterceptor on the route. Add @UseInterceptors(AxisDecodeInterceptor) to use this decorator."
|
|
3652
|
+
);
|
|
3653
|
+
}
|
|
3654
|
+
return decoded;
|
|
3655
|
+
}
|
|
3656
|
+
);
|
|
2972
3657
|
|
|
2973
3658
|
// src/core/axis-error.ts
|
|
2974
3659
|
var AxisError = class extends Error {
|
|
@@ -2981,348 +3666,246 @@ var AxisError = class extends Error {
|
|
|
2981
3666
|
}
|
|
2982
3667
|
};
|
|
2983
3668
|
|
|
2984
|
-
// src/
|
|
2985
|
-
var crypto_exports = {};
|
|
2986
|
-
__export(crypto_exports, {
|
|
2987
|
-
ProofVerificationService: () => ProofVerificationService,
|
|
2988
|
-
b64urlDecode: () => b64urlDecode,
|
|
2989
|
-
b64urlDecodeString: () => b64urlDecodeString,
|
|
2990
|
-
b64urlEncode: () => b64urlEncode,
|
|
2991
|
-
b64urlEncodeString: () => b64urlEncodeString,
|
|
2992
|
-
canonicalJson: () => canonicalJson,
|
|
2993
|
-
canonicalJsonExcluding: () => canonicalJsonExcluding
|
|
2994
|
-
});
|
|
2995
|
-
|
|
2996
|
-
// src/crypto/proof-verification.service.ts
|
|
3669
|
+
// src/engine/handler-discovery.service.ts
|
|
2997
3670
|
import { Injectable as Injectable4, Logger as Logger3 } from "@nestjs/common";
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
this.
|
|
3003
|
-
|
|
3004
|
-
this.deviceKeys = /* @__PURE__ */ new Map();
|
|
3005
|
-
// Cache of trusted mTLS certificate fingerprints
|
|
3006
|
-
this.trustedCerts = /* @__PURE__ */ new Map();
|
|
3671
|
+
var HandlerDiscoveryService = class {
|
|
3672
|
+
constructor(discovery, scanner, router) {
|
|
3673
|
+
this.discovery = discovery;
|
|
3674
|
+
this.scanner = scanner;
|
|
3675
|
+
this.router = router;
|
|
3676
|
+
this.logger = new Logger3(HandlerDiscoveryService.name);
|
|
3007
3677
|
}
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
async verifyProof(proofType, proofRef, context) {
|
|
3027
|
-
switch (proofType) {
|
|
3028
|
-
case 1:
|
|
3029
|
-
return this.verifyCapsuleProof(proofRef);
|
|
3030
|
-
case 2:
|
|
3031
|
-
return this.verifyJWTProof(proofRef);
|
|
3032
|
-
case 3:
|
|
3033
|
-
return this.verifyMTLSProof(context.mtls);
|
|
3034
|
-
case 4:
|
|
3035
|
-
return this.verifyDeviceSEProof(
|
|
3036
|
-
context.signTarget,
|
|
3037
|
-
context.signature,
|
|
3038
|
-
context.deviceSE
|
|
3678
|
+
onModuleInit() {
|
|
3679
|
+
const providers = this.discovery.getProviders();
|
|
3680
|
+
let totalIntents = 0;
|
|
3681
|
+
for (const wrapper of providers) {
|
|
3682
|
+
const { instance, metatype } = wrapper;
|
|
3683
|
+
if (!instance || !metatype) continue;
|
|
3684
|
+
const handlerMeta = Reflect.getMetadata(HANDLER_METADATA_KEY, metatype);
|
|
3685
|
+
if (!handlerMeta) continue;
|
|
3686
|
+
const handlerName = handlerMeta.intent || metatype.name;
|
|
3687
|
+
const proto = Object.getPrototypeOf(instance);
|
|
3688
|
+
const methods = this.scanner.getAllMethodNames(proto);
|
|
3689
|
+
let registered = 0;
|
|
3690
|
+
const handlerSensors = Reflect.getMetadata(HANDLER_SENSORS_KEY, metatype) || [];
|
|
3691
|
+
for (const methodName of methods) {
|
|
3692
|
+
const meta = Reflect.getMetadata(
|
|
3693
|
+
INTENT_METADATA_KEY,
|
|
3694
|
+
proto,
|
|
3695
|
+
methodName
|
|
3039
3696
|
);
|
|
3040
|
-
|
|
3041
|
-
|
|
3697
|
+
if (!meta?.intent) continue;
|
|
3698
|
+
if (!this.router.has(meta.intent)) {
|
|
3699
|
+
this.router.register(
|
|
3700
|
+
meta.intent,
|
|
3701
|
+
instance[methodName].bind(instance)
|
|
3702
|
+
);
|
|
3703
|
+
registered++;
|
|
3704
|
+
totalIntents++;
|
|
3705
|
+
}
|
|
3706
|
+
this.router.registerIntentMeta(
|
|
3707
|
+
meta.intent,
|
|
3708
|
+
proto,
|
|
3709
|
+
methodName,
|
|
3710
|
+
handlerSensors
|
|
3711
|
+
);
|
|
3712
|
+
}
|
|
3713
|
+
if (registered > 0) {
|
|
3714
|
+
this.logger.log(
|
|
3715
|
+
`Auto-registered ${registered} intents from ${handlerName}`
|
|
3716
|
+
);
|
|
3717
|
+
}
|
|
3042
3718
|
}
|
|
3719
|
+
this.logger.log(
|
|
3720
|
+
`Handler discovery complete: ${totalIntents} intents auto-registered`
|
|
3721
|
+
);
|
|
3043
3722
|
}
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3723
|
+
};
|
|
3724
|
+
HandlerDiscoveryService = __decorateClass([
|
|
3725
|
+
Injectable4()
|
|
3726
|
+
], HandlerDiscoveryService);
|
|
3727
|
+
|
|
3728
|
+
// src/engine/sensor-discovery.service.ts
|
|
3729
|
+
import { Injectable as Injectable5, Logger as Logger4 } from "@nestjs/common";
|
|
3730
|
+
var SensorDiscoveryService = class {
|
|
3731
|
+
constructor(discovery, reflector, registry) {
|
|
3732
|
+
this.discovery = discovery;
|
|
3733
|
+
this.reflector = reflector;
|
|
3734
|
+
this.registry = registry;
|
|
3735
|
+
this.logger = new Logger4(SensorDiscoveryService.name);
|
|
3053
3736
|
}
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
return { valid: false, error: "Invalid JWT format" };
|
|
3072
|
-
}
|
|
3073
|
-
const header = JSON.parse(Buffer.from(parts[0], "base64url").toString());
|
|
3074
|
-
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
3075
|
-
if (payload.exp && Date.now() / 1e3 > payload.exp) {
|
|
3076
|
-
return { valid: false, error: "JWT expired" };
|
|
3737
|
+
onApplicationBootstrap() {
|
|
3738
|
+
const providers = this.discovery.getProviders();
|
|
3739
|
+
let count = 0;
|
|
3740
|
+
for (const wrapper of providers) {
|
|
3741
|
+
const { instance } = wrapper;
|
|
3742
|
+
if (!instance || !instance.constructor) continue;
|
|
3743
|
+
const meta = this.reflector.get(
|
|
3744
|
+
SENSOR_METADATA_KEY,
|
|
3745
|
+
instance.constructor
|
|
3746
|
+
);
|
|
3747
|
+
if (!meta) continue;
|
|
3748
|
+
const sensor = instance;
|
|
3749
|
+
if (!sensor.name || sensor.order === void 0) {
|
|
3750
|
+
this.logger.warn(
|
|
3751
|
+
`@Sensor() on ${instance.constructor.name} missing name or order \u2014 skipped`
|
|
3752
|
+
);
|
|
3753
|
+
continue;
|
|
3077
3754
|
}
|
|
3078
|
-
if (
|
|
3079
|
-
|
|
3755
|
+
if (!sensor.phase) {
|
|
3756
|
+
const decoratorPhase = meta !== true ? meta.phase : void 0;
|
|
3757
|
+
sensor.phase = decoratorPhase ?? (sensor.order < PRE_DECODE_BOUNDARY ? "PRE_DECODE" : "POST_DECODE");
|
|
3080
3758
|
}
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
actorId: payload.sub || payload.actor_id,
|
|
3084
|
-
metadata: { iss: payload.iss, scope: payload.scope }
|
|
3085
|
-
};
|
|
3086
|
-
} catch (e) {
|
|
3087
|
-
const message = e instanceof Error ? e.message : "Unknown error";
|
|
3088
|
-
return { valid: false, error: `JWT parse error: ${message}` };
|
|
3759
|
+
this.registry.register(sensor);
|
|
3760
|
+
count++;
|
|
3089
3761
|
}
|
|
3762
|
+
this.logger.log(`Auto-registered ${count} sensors via @Sensor()`);
|
|
3090
3763
|
}
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
if (trusted) {
|
|
3104
|
-
return {
|
|
3105
|
-
valid: true,
|
|
3106
|
-
actorId: trusted.actorId,
|
|
3107
|
-
metadata: {
|
|
3108
|
-
fingerprint: mtls.clientCertFingerprint,
|
|
3109
|
-
subject: mtls.clientCertSubject
|
|
3110
|
-
}
|
|
3111
|
-
};
|
|
3112
|
-
}
|
|
3113
|
-
}
|
|
3114
|
-
if (mtls.clientCertSubject) {
|
|
3115
|
-
const cnMatch = mtls.clientCertSubject.match(/CN=([^,]+)/);
|
|
3116
|
-
if (cnMatch) {
|
|
3117
|
-
return {
|
|
3118
|
-
valid: true,
|
|
3119
|
-
actorId: cnMatch[1],
|
|
3120
|
-
metadata: {
|
|
3121
|
-
subject: mtls.clientCertSubject,
|
|
3122
|
-
issuer: mtls.clientCertIssuer
|
|
3123
|
-
}
|
|
3124
|
-
};
|
|
3125
|
-
}
|
|
3126
|
-
}
|
|
3127
|
-
return { valid: false, error: "Could not extract actor from certificate" };
|
|
3764
|
+
};
|
|
3765
|
+
SensorDiscoveryService = __decorateClass([
|
|
3766
|
+
Injectable5()
|
|
3767
|
+
], SensorDiscoveryService);
|
|
3768
|
+
|
|
3769
|
+
// src/engine/registry/sensor.registry.ts
|
|
3770
|
+
import { Injectable as Injectable6, Logger as Logger5 } from "@nestjs/common";
|
|
3771
|
+
var SensorRegistry = class {
|
|
3772
|
+
constructor(configService) {
|
|
3773
|
+
this.configService = configService;
|
|
3774
|
+
this.sensors = [];
|
|
3775
|
+
this.logger = new Logger5(SensorRegistry.name);
|
|
3128
3776
|
}
|
|
3129
3777
|
/**
|
|
3130
|
-
*
|
|
3778
|
+
* Registers a new sensor in the registry.
|
|
3779
|
+
*
|
|
3780
|
+
* Validates that:
|
|
3781
|
+
* - AxisSensor has a unique name
|
|
3782
|
+
* - AxisSensor has an order field
|
|
3783
|
+
* - Pre-decode sensors have order < 40
|
|
3784
|
+
* - Post-decode sensors have order >= 40
|
|
3785
|
+
*
|
|
3786
|
+
* @param {AxisSensor} sensor - The sensor instance to register
|
|
3787
|
+
* @throws Error if validation fails
|
|
3131
3788
|
*/
|
|
3132
|
-
|
|
3133
|
-
if (!
|
|
3134
|
-
|
|
3789
|
+
register(sensor) {
|
|
3790
|
+
if (!sensor.name) {
|
|
3791
|
+
throw new Error("AxisSensor must have a name");
|
|
3135
3792
|
}
|
|
3136
|
-
|
|
3137
|
-
const
|
|
3138
|
-
|
|
3139
|
-
|
|
3793
|
+
const enabledSensorsStr = this.configService.get("ENABLED_SENSORS");
|
|
3794
|
+
const disabledSensorsStr = this.configService.get("DISABLED_SENSORS");
|
|
3795
|
+
const enabledSensors = enabledSensorsStr ? enabledSensorsStr.split(",").map((s) => s.trim()) : null;
|
|
3796
|
+
const disabledSensors = disabledSensorsStr ? disabledSensorsStr.split(",").map((s) => s.trim()) : [];
|
|
3797
|
+
if (enabledSensors && !enabledSensors.includes(sensor.name)) {
|
|
3798
|
+
this.logger.log(`Skipping disabled sensor (not in ENABLED_SENSORS): ${sensor.name}`);
|
|
3799
|
+
return;
|
|
3140
3800
|
}
|
|
3141
|
-
if (
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
error: "Invalid or unregistered device public key"
|
|
3145
|
-
};
|
|
3801
|
+
if (disabledSensors.includes(sensor.name)) {
|
|
3802
|
+
this.logger.log(`Skipping disabled sensor (in DISABLED_SENSORS): ${sensor.name}`);
|
|
3803
|
+
return;
|
|
3146
3804
|
}
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
error: `Signature verification error: ${message}`
|
|
3162
|
-
};
|
|
3805
|
+
if (sensor.order === void 0) {
|
|
3806
|
+
throw new Error(`AxisSensor "${sensor.name}" must have an order field`);
|
|
3807
|
+
}
|
|
3808
|
+
const isPreDecodeSensor = this.isPreDecodeSensor(sensor);
|
|
3809
|
+
const isPostDecodeSensor = this.isPostDecodeSensor(sensor);
|
|
3810
|
+
if (isPreDecodeSensor && sensor.order >= 40) {
|
|
3811
|
+
this.logger.warn(
|
|
3812
|
+
`AxisSensor "${sensor.name}" is marked as PRE_DECODE but has order ${sensor.order} (should be < 40)`
|
|
3813
|
+
);
|
|
3814
|
+
}
|
|
3815
|
+
if (isPostDecodeSensor && sensor.order < 40) {
|
|
3816
|
+
this.logger.warn(
|
|
3817
|
+
`AxisSensor "${sensor.name}" is marked as POST_DECODE but has order ${sensor.order} (should be >= 40)`
|
|
3818
|
+
);
|
|
3163
3819
|
}
|
|
3820
|
+
this.sensors.push(sensor);
|
|
3821
|
+
const phaseLabel = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase || "UNKNOWN";
|
|
3822
|
+
this.logger.debug(
|
|
3823
|
+
`Registered sensor: ${sensor.name} (order: ${sensor.order}, phase: ${phaseLabel})`
|
|
3824
|
+
);
|
|
3164
3825
|
}
|
|
3165
3826
|
/**
|
|
3166
|
-
*
|
|
3167
|
-
* This key will be used for future `DEVICE_SE` proof verifications.
|
|
3827
|
+
* Returns all registered sensors, sorted by their execution order.
|
|
3168
3828
|
*
|
|
3169
|
-
* @
|
|
3170
|
-
* @param {Uint8Array} publicKey - 32-byte Ed25519 public key
|
|
3171
|
-
* @throws {Error} If the public key is not 32 bytes
|
|
3829
|
+
* @returns {AxisSensor[]} A sorted array of sensors
|
|
3172
3830
|
*/
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
this.deviceKeys.set(deviceId, publicKey);
|
|
3178
|
-
this.logger.log(`Registered device key for ${deviceId}`);
|
|
3831
|
+
list() {
|
|
3832
|
+
return [...this.sensors].sort(
|
|
3833
|
+
(a, b) => (a.order ?? 999) - (b.order ?? 999)
|
|
3834
|
+
);
|
|
3179
3835
|
}
|
|
3180
3836
|
/**
|
|
3181
|
-
*
|
|
3837
|
+
* Returns only pre-decode sensors (order < 40).
|
|
3838
|
+
* These sensors run in middleware on raw bytes before frame decoding.
|
|
3839
|
+
*
|
|
3840
|
+
* @returns {AxisPreSensor[]} Pre-decode sensors sorted by order
|
|
3182
3841
|
*/
|
|
3183
|
-
|
|
3184
|
-
return this.
|
|
3842
|
+
getPreDecodeSensors() {
|
|
3843
|
+
return this.list().filter((s) => (s.order ?? 999) < 40);
|
|
3185
3844
|
}
|
|
3186
3845
|
/**
|
|
3187
|
-
*
|
|
3846
|
+
* Returns only post-decode sensors (order >= 40).
|
|
3847
|
+
* These sensors run in the controller on fully decoded frames.
|
|
3188
3848
|
*
|
|
3189
|
-
* @
|
|
3190
|
-
* @param {string} actorId - The actor to associate with this certificate
|
|
3849
|
+
* @returns {AxisPostSensor[]} Post-decode sensors sorted by order
|
|
3191
3850
|
*/
|
|
3192
|
-
|
|
3193
|
-
this.
|
|
3194
|
-
|
|
3851
|
+
getPostDecodeSensors() {
|
|
3852
|
+
return this.list().filter(
|
|
3853
|
+
(s) => (s.order ?? 999) >= 40
|
|
3854
|
+
);
|
|
3195
3855
|
}
|
|
3196
3856
|
/**
|
|
3197
|
-
*
|
|
3857
|
+
* Helper: Check if a sensor is a pre-decode sensor.
|
|
3858
|
+
*
|
|
3859
|
+
* @private
|
|
3860
|
+
* @param {AxisSensor} sensor - The sensor to check
|
|
3861
|
+
* @returns {boolean} True if sensor is pre-decode
|
|
3198
3862
|
*/
|
|
3199
|
-
|
|
3200
|
-
|
|
3863
|
+
isPreDecodeSensor(sensor) {
|
|
3864
|
+
const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
|
|
3865
|
+
return phase === "PRE_DECODE" || (sensor.order ?? 999) < 40;
|
|
3201
3866
|
}
|
|
3202
3867
|
/**
|
|
3203
|
-
*
|
|
3868
|
+
* Helper: Check if a sensor is a post-decode sensor.
|
|
3869
|
+
*
|
|
3870
|
+
* @private
|
|
3871
|
+
* @param {AxisSensor} sensor - The sensor to check
|
|
3872
|
+
* @returns {boolean} True if sensor is post-decode
|
|
3204
3873
|
*/
|
|
3205
|
-
|
|
3206
|
-
const
|
|
3207
|
-
|
|
3208
|
-
"base64"
|
|
3209
|
-
);
|
|
3210
|
-
return crypto3.createHash("sha256").update(der).digest("hex");
|
|
3211
|
-
}
|
|
3212
|
-
};
|
|
3213
|
-
ProofVerificationService = __decorateClass([
|
|
3214
|
-
Injectable4()
|
|
3215
|
-
], ProofVerificationService);
|
|
3216
|
-
|
|
3217
|
-
// src/decorators/index.ts
|
|
3218
|
-
var decorators_exports = {};
|
|
3219
|
-
__export(decorators_exports, {
|
|
3220
|
-
AxisContext: () => AxisContext,
|
|
3221
|
-
AxisDemoPubkey: () => AxisDemoPubkey,
|
|
3222
|
-
AxisFrame: () => AxisFrame3,
|
|
3223
|
-
AxisIp: () => AxisIp,
|
|
3224
|
-
AxisRaw: () => AxisRaw,
|
|
3225
|
-
HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
|
|
3226
|
-
Handler: () => Handler,
|
|
3227
|
-
INTENT_BODY_KEY: () => INTENT_BODY_KEY,
|
|
3228
|
-
INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
|
|
3229
|
-
INTENT_ROUTES_KEY: () => INTENT_ROUTES_KEY,
|
|
3230
|
-
INTENT_SENSORS_KEY: () => INTENT_SENSORS_KEY,
|
|
3231
|
-
Intent: () => Intent,
|
|
3232
|
-
IntentBody: () => IntentBody,
|
|
3233
|
-
IntentSensors: () => IntentSensors,
|
|
3234
|
-
SENSOR_METADATA_KEY: () => SENSOR_METADATA_KEY,
|
|
3235
|
-
Sensor: () => Sensor,
|
|
3236
|
-
TLV_FIELDS_KEY: () => TLV_FIELDS_KEY,
|
|
3237
|
-
TLV_VALIDATORS_KEY: () => TLV_VALIDATORS_KEY,
|
|
3238
|
-
TlvEnum: () => TlvEnum,
|
|
3239
|
-
TlvField: () => TlvField,
|
|
3240
|
-
TlvMinLen: () => TlvMinLen,
|
|
3241
|
-
TlvRange: () => TlvRange,
|
|
3242
|
-
TlvUtf8Pattern: () => TlvUtf8Pattern,
|
|
3243
|
-
TlvValidate: () => TlvValidate,
|
|
3244
|
-
buildDtoDecoder: () => buildDtoDecoder,
|
|
3245
|
-
extractDtoSchema: () => extractDtoSchema
|
|
3246
|
-
});
|
|
3247
|
-
|
|
3248
|
-
// src/decorators/axis-request.decorator.ts
|
|
3249
|
-
import { createParamDecorator } from "@nestjs/common";
|
|
3250
|
-
function resolveIp(req) {
|
|
3251
|
-
return req.headers["x-forwarded-for"]?.split(",")[0]?.trim() || req.headers["x-real-ip"] || req.socket.remoteAddress || void 0;
|
|
3252
|
-
}
|
|
3253
|
-
var AxisRaw = createParamDecorator(
|
|
3254
|
-
(_data, ctx) => {
|
|
3255
|
-
const req = ctx.switchToHttp().getRequest();
|
|
3256
|
-
return req.body;
|
|
3257
|
-
}
|
|
3258
|
-
);
|
|
3259
|
-
var AxisIp = createParamDecorator(
|
|
3260
|
-
(_data, ctx) => {
|
|
3261
|
-
const req = ctx.switchToHttp().getRequest();
|
|
3262
|
-
return resolveIp(req);
|
|
3874
|
+
isPostDecodeSensor(sensor) {
|
|
3875
|
+
const phase = typeof sensor.phase === "string" ? sensor.phase : sensor.phase?.phase;
|
|
3876
|
+
return phase === "POST_DECODE" || (sensor.order ?? 999) >= 40;
|
|
3263
3877
|
}
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3878
|
+
/**
|
|
3879
|
+
* Returns sensor count by phase.
|
|
3880
|
+
* Useful for diagnostics and monitoring.
|
|
3881
|
+
*
|
|
3882
|
+
* @returns {{preDecodeCount: number, postDecodeCount: number}}
|
|
3883
|
+
*/
|
|
3884
|
+
getSensorCountByPhase() {
|
|
3269
3885
|
return {
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
preDecodeInput: axisData.preDecodeInput,
|
|
3273
|
-
frameBytesCount: axisData.frameBytesCount || 0
|
|
3886
|
+
preDecodeCount: this.getPreDecodeSensors().length,
|
|
3887
|
+
postDecodeCount: this.getPostDecodeSensors().length
|
|
3274
3888
|
};
|
|
3275
3889
|
}
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
var AxisFrame3 = createParamDecorator(
|
|
3285
|
-
(_data, ctx) => {
|
|
3286
|
-
const req = ctx.switchToHttp().getRequest();
|
|
3287
|
-
const decoded = req.axisDecoded;
|
|
3288
|
-
if (!decoded) {
|
|
3289
|
-
throw new Error(
|
|
3290
|
-
"@AxisFrame() requires AxisDecodeInterceptor on the route. Add @UseInterceptors(AxisDecodeInterceptor) to use this decorator."
|
|
3291
|
-
);
|
|
3292
|
-
}
|
|
3293
|
-
return decoded;
|
|
3890
|
+
/**
|
|
3891
|
+
* Clears all registered sensors.
|
|
3892
|
+
* Useful for testing.
|
|
3893
|
+
*
|
|
3894
|
+
* @internal
|
|
3895
|
+
*/
|
|
3896
|
+
clear() {
|
|
3897
|
+
this.sensors = [];
|
|
3294
3898
|
}
|
|
3295
|
-
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
var SENSOR_METADATA_KEY = "axis:sensor";
|
|
3300
|
-
function Sensor(options) {
|
|
3301
|
-
return SetMetadata2(SENSOR_METADATA_KEY, options ?? true);
|
|
3302
|
-
}
|
|
3303
|
-
|
|
3304
|
-
// src/engine/index.ts
|
|
3305
|
-
var engine_exports = {};
|
|
3306
|
-
__export(engine_exports, {
|
|
3307
|
-
BAND: () => BAND,
|
|
3308
|
-
HandlerDiscoveryService: () => HandlerDiscoveryService,
|
|
3309
|
-
IntentRouter: () => IntentRouter,
|
|
3310
|
-
PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
|
|
3311
|
-
SensorDiscoveryService: () => SensorDiscoveryService,
|
|
3312
|
-
SensorRegistry: () => SensorRegistry,
|
|
3313
|
-
createObservation: () => createObservation,
|
|
3314
|
-
endStage: () => endStage,
|
|
3315
|
-
finalizeObservation: () => finalizeObservation,
|
|
3316
|
-
observation: () => observation_exports,
|
|
3317
|
-
recordSensor: () => recordSensor,
|
|
3318
|
-
startStage: () => startStage
|
|
3319
|
-
});
|
|
3899
|
+
};
|
|
3900
|
+
SensorRegistry = __decorateClass([
|
|
3901
|
+
Injectable6()
|
|
3902
|
+
], SensorRegistry);
|
|
3320
3903
|
|
|
3321
3904
|
// src/engine/axis-observation.ts
|
|
3322
|
-
import { randomBytes as
|
|
3905
|
+
import { randomBytes as randomBytes5 } from "crypto";
|
|
3323
3906
|
function createObservation(transport, ip) {
|
|
3324
3907
|
return {
|
|
3325
|
-
id:
|
|
3908
|
+
id: randomBytes5(16).toString("hex"),
|
|
3326
3909
|
startMs: Date.now(),
|
|
3327
3910
|
transport,
|
|
3328
3911
|
ip,
|
|
@@ -3354,251 +3937,1186 @@ function finalizeObservation(obs, decision, statusCode, resultCode) {
|
|
|
3354
3937
|
if (resultCode) obs.resultCode = resultCode;
|
|
3355
3938
|
}
|
|
3356
3939
|
|
|
3357
|
-
// src/
|
|
3358
|
-
import { Injectable as
|
|
3359
|
-
var
|
|
3360
|
-
constructor(
|
|
3361
|
-
this.
|
|
3362
|
-
this.scanner = scanner;
|
|
3363
|
-
this.router = router;
|
|
3364
|
-
this.logger = new Logger4(HandlerDiscoveryService.name);
|
|
3940
|
+
// src/security/axis-sensor-chain.service.ts
|
|
3941
|
+
import { Injectable as Injectable7 } from "@nestjs/common";
|
|
3942
|
+
var AxisSensorChainService = class {
|
|
3943
|
+
constructor(registry) {
|
|
3944
|
+
this.registry = registry;
|
|
3365
3945
|
}
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
const
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3946
|
+
/**
|
|
3947
|
+
* Evaluate all applicable sensors based on phase.
|
|
3948
|
+
*/
|
|
3949
|
+
async evaluate(input, phase = "POST_DECODE", baseDecision) {
|
|
3950
|
+
if (phase === "PRE_DECODE") {
|
|
3951
|
+
return this.evaluateSensors(this.registry.getPreDecodeSensors(), input);
|
|
3952
|
+
}
|
|
3953
|
+
if (phase === "BOTH") {
|
|
3954
|
+
const rawPreResult = await this.evaluateSensors(
|
|
3955
|
+
this.registry.getPreDecodeSensors(),
|
|
3956
|
+
input
|
|
3957
|
+
);
|
|
3958
|
+
const preResult = normalizeSensorDecision(rawPreResult);
|
|
3959
|
+
if (!preResult.allow) return rawPreResult;
|
|
3960
|
+
return this.evaluateSensors(
|
|
3961
|
+
this.registry.getPostDecodeSensors(),
|
|
3962
|
+
input,
|
|
3963
|
+
rawPreResult
|
|
3964
|
+
);
|
|
3965
|
+
}
|
|
3966
|
+
return this.evaluateSensors(
|
|
3967
|
+
this.registry.getPostDecodeSensors(),
|
|
3968
|
+
input,
|
|
3969
|
+
baseDecision
|
|
3970
|
+
);
|
|
3971
|
+
}
|
|
3972
|
+
/** Run only pre-decode sensors. */
|
|
3973
|
+
async evaluatePre(input) {
|
|
3974
|
+
return this.evaluateSensors(this.registry.getPreDecodeSensors(), input);
|
|
3975
|
+
}
|
|
3976
|
+
/** Run only post-decode sensors. */
|
|
3977
|
+
async evaluatePost(input, baseDecision) {
|
|
3978
|
+
return this.evaluateSensors(
|
|
3979
|
+
this.registry.getPostDecodeSensors(),
|
|
3980
|
+
input,
|
|
3981
|
+
baseDecision
|
|
3982
|
+
);
|
|
3983
|
+
}
|
|
3984
|
+
async evaluateSensors(sensors, input, baseDecision) {
|
|
3985
|
+
const relevantSensors = sensors.filter(
|
|
3986
|
+
(s) => !s.supports || s.supports(input)
|
|
3987
|
+
);
|
|
3988
|
+
const normalizedBase = baseDecision ? normalizeSensorDecision(baseDecision) : void 0;
|
|
3989
|
+
let riskScore = normalizedBase?.riskScore ?? 0;
|
|
3990
|
+
const reasons = normalizedBase?.reasons ? [...normalizedBase.reasons] : [];
|
|
3991
|
+
const tags = normalizedBase?.tags ? { ...normalizedBase.tags } : {};
|
|
3992
|
+
let expSecondsMax = normalizedBase?.tighten?.expSecondsMax;
|
|
3993
|
+
let constraintsPatch = normalizedBase?.tighten?.constraintsPatch ? { ...normalizedBase.tighten.constraintsPatch } : {};
|
|
3994
|
+
for (const sensor of relevantSensors) {
|
|
3995
|
+
try {
|
|
3996
|
+
const t0 = Date.now();
|
|
3997
|
+
const rawDecision = await sensor.run(input);
|
|
3998
|
+
const elapsed = Date.now() - t0;
|
|
3999
|
+
const decision = normalizeSensorDecision(rawDecision);
|
|
4000
|
+
const obs = input.metadata?.observation;
|
|
4001
|
+
if (obs) {
|
|
4002
|
+
recordSensor(
|
|
4003
|
+
obs,
|
|
4004
|
+
sensor.name,
|
|
4005
|
+
decision.allow,
|
|
4006
|
+
decision.riskScore,
|
|
4007
|
+
elapsed,
|
|
4008
|
+
decision.reasons,
|
|
4009
|
+
decision.allow ? void 0 : decision.code
|
|
3389
4010
|
);
|
|
3390
|
-
registered++;
|
|
3391
|
-
totalIntents++;
|
|
3392
4011
|
}
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
4012
|
+
if (!decision.allow) {
|
|
4013
|
+
return {
|
|
4014
|
+
allow: false,
|
|
4015
|
+
riskScore: Math.min(100, riskScore + decision.riskScore),
|
|
4016
|
+
reasons: [...reasons, ...decision.reasons],
|
|
4017
|
+
tags
|
|
4018
|
+
};
|
|
4019
|
+
}
|
|
4020
|
+
riskScore = Math.min(100, riskScore + decision.riskScore);
|
|
4021
|
+
reasons.push(...decision.reasons);
|
|
4022
|
+
if (decision.tags) {
|
|
4023
|
+
Object.assign(tags, decision.tags);
|
|
4024
|
+
}
|
|
4025
|
+
if (decision.tighten?.expSecondsMax !== void 0) {
|
|
4026
|
+
expSecondsMax = expSecondsMax === void 0 ? decision.tighten.expSecondsMax : Math.min(expSecondsMax, decision.tighten.expSecondsMax);
|
|
4027
|
+
}
|
|
4028
|
+
if (decision.tighten?.constraintsPatch) {
|
|
4029
|
+
constraintsPatch = {
|
|
4030
|
+
...constraintsPatch,
|
|
4031
|
+
...decision.tighten.constraintsPatch
|
|
4032
|
+
};
|
|
4033
|
+
}
|
|
4034
|
+
} catch (error) {
|
|
4035
|
+
console.error(`[AXIS][SENSOR] ${sensor.name} failed:`, error);
|
|
4036
|
+
const obs = input.metadata?.observation;
|
|
4037
|
+
if (obs) {
|
|
4038
|
+
recordSensor(obs, sensor.name, false, 100, 0, [
|
|
4039
|
+
`sensor_error:${sensor.name}`
|
|
4040
|
+
]);
|
|
4041
|
+
}
|
|
4042
|
+
return {
|
|
4043
|
+
allow: false,
|
|
4044
|
+
riskScore: 100,
|
|
4045
|
+
reasons: [`sensor_error:${sensor.name}`]
|
|
4046
|
+
};
|
|
3399
4047
|
}
|
|
3400
4048
|
}
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
4049
|
+
const tightenPatch = Object.keys(constraintsPatch).length > 0 ? constraintsPatch : void 0;
|
|
4050
|
+
return {
|
|
4051
|
+
allow: true,
|
|
4052
|
+
riskScore,
|
|
4053
|
+
reasons,
|
|
4054
|
+
tags,
|
|
4055
|
+
tighten: expSecondsMax !== void 0 || tightenPatch ? {
|
|
4056
|
+
expSecondsMax,
|
|
4057
|
+
constraintsPatch: tightenPatch
|
|
4058
|
+
} : void 0
|
|
4059
|
+
};
|
|
3404
4060
|
}
|
|
3405
4061
|
};
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
],
|
|
4062
|
+
AxisSensorChainService = __decorateClass([
|
|
4063
|
+
Injectable7()
|
|
4064
|
+
], AxisSensorChainService);
|
|
3409
4065
|
|
|
3410
|
-
// src/
|
|
3411
|
-
var
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
4066
|
+
// src/cce/index.ts
|
|
4067
|
+
var cce_exports = {};
|
|
4068
|
+
__export(cce_exports, {
|
|
4069
|
+
CCE_AES_KEY_BYTES: () => CCE_AES_KEY_BYTES,
|
|
4070
|
+
CCE_DERIVATION: () => CCE_DERIVATION,
|
|
4071
|
+
CCE_ERROR: () => CCE_ERROR,
|
|
4072
|
+
CCE_IV_BYTES: () => CCE_IV_BYTES,
|
|
4073
|
+
CCE_NONCE_BYTES: () => CCE_NONCE_BYTES,
|
|
4074
|
+
CCE_PROTOCOL_VERSION: () => CCE_PROTOCOL_VERSION,
|
|
4075
|
+
CCE_TAG_BYTES: () => CCE_TAG_BYTES,
|
|
4076
|
+
CceAudienceIntentBindingSensor: () => CceAudienceIntentBindingSensor,
|
|
4077
|
+
CceCapsuleVerificationSensor: () => CceCapsuleVerificationSensor,
|
|
4078
|
+
CceClientSignatureSensor: () => CceClientSignatureSensor,
|
|
4079
|
+
CceEnvelopeValidationSensor: () => CceEnvelopeValidationSensor,
|
|
4080
|
+
CceError: () => CceError,
|
|
4081
|
+
CcePayloadDecryptionSensor: () => CcePayloadDecryptionSensor,
|
|
4082
|
+
CceReplayProtectionSensor: () => CceReplayProtectionSensor,
|
|
4083
|
+
CceTpsWindowSensor: () => CceTpsWindowSensor,
|
|
4084
|
+
InMemoryCceReplayStore: () => InMemoryCceReplayStore,
|
|
4085
|
+
InMemoryCceWitnessStore: () => InMemoryCceWitnessStore,
|
|
4086
|
+
aesGcmDecrypt: () => aesGcmDecrypt,
|
|
4087
|
+
aesGcmEncrypt: () => aesGcmEncrypt,
|
|
4088
|
+
base64UrlDecode: () => base64UrlDecode,
|
|
4089
|
+
base64UrlEncode: () => base64UrlEncode,
|
|
4090
|
+
buildCceErrorResponse: () => buildCceErrorResponse,
|
|
4091
|
+
buildCceResponse: () => buildCceResponse,
|
|
4092
|
+
buildExecutionContext: () => buildExecutionContext,
|
|
4093
|
+
buildWitnessRecord: () => buildWitnessRecord,
|
|
4094
|
+
deriveRequestExecutionKey: () => deriveRequestExecutionKey,
|
|
4095
|
+
deriveResponseExecutionKey: () => deriveResponseExecutionKey,
|
|
4096
|
+
deriveWitnessKey: () => deriveWitnessKey,
|
|
4097
|
+
executeCcePipeline: () => executeCcePipeline,
|
|
4098
|
+
extractVerificationState: () => extractVerificationState,
|
|
4099
|
+
generateAesKey: () => generateAesKey,
|
|
4100
|
+
generateCceNonce: () => generateCceNonce,
|
|
4101
|
+
generateIv: () => generateIv,
|
|
4102
|
+
hashPayload: () => hashPayload,
|
|
4103
|
+
nodeAesGcmProvider: () => nodeAesGcmProvider
|
|
4104
|
+
});
|
|
3426
4105
|
|
|
3427
|
-
// src/
|
|
3428
|
-
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
4106
|
+
// src/cce/sensors/cce-envelope-validation.sensor.ts
|
|
4107
|
+
var REQUIRED_FIELDS = [
|
|
4108
|
+
"ver",
|
|
4109
|
+
"request_id",
|
|
4110
|
+
"correlation_id",
|
|
4111
|
+
"client_kid",
|
|
4112
|
+
"capsule",
|
|
4113
|
+
"encrypted_key",
|
|
4114
|
+
"encrypted_payload",
|
|
4115
|
+
"request_nonce",
|
|
4116
|
+
"client_sig",
|
|
4117
|
+
"algorithms"
|
|
4118
|
+
];
|
|
4119
|
+
var CceEnvelopeValidationSensor = class {
|
|
4120
|
+
constructor() {
|
|
4121
|
+
this.name = "cce.envelope.validation";
|
|
4122
|
+
this.order = 5;
|
|
4123
|
+
this.phase = "PRE_DECODE";
|
|
3435
4124
|
}
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
4125
|
+
supports(input) {
|
|
4126
|
+
return input.metadata?.cce === true || input.metadata?.contentType === "application/axis-cce";
|
|
4127
|
+
}
|
|
4128
|
+
async run(input) {
|
|
4129
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4130
|
+
if (!envelope) {
|
|
4131
|
+
return {
|
|
4132
|
+
allow: false,
|
|
4133
|
+
riskScore: 100,
|
|
4134
|
+
reasons: [CCE_ERROR.INVALID_ENVELOPE],
|
|
4135
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4136
|
+
};
|
|
4137
|
+
}
|
|
4138
|
+
for (const field of REQUIRED_FIELDS) {
|
|
4139
|
+
if (envelope[field] === void 0 || envelope[field] === null) {
|
|
4140
|
+
return {
|
|
4141
|
+
allow: false,
|
|
4142
|
+
riskScore: 100,
|
|
4143
|
+
reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: missing ${field}`],
|
|
4144
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4145
|
+
};
|
|
3457
4146
|
}
|
|
3458
|
-
this.registry.register(sensor);
|
|
3459
|
-
count++;
|
|
3460
4147
|
}
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
// src/engine/registry/sensor.registry.ts
|
|
3469
|
-
import { Injectable as Injectable7, Logger as Logger6 } from "@nestjs/common";
|
|
3470
|
-
var SensorRegistry = class {
|
|
3471
|
-
constructor(configService) {
|
|
3472
|
-
this.configService = configService;
|
|
3473
|
-
this.sensors = [];
|
|
3474
|
-
this.logger = new Logger6(SensorRegistry.name);
|
|
3475
|
-
}
|
|
3476
|
-
/**
|
|
3477
|
-
* Registers a new sensor in the registry.
|
|
3478
|
-
*
|
|
3479
|
-
* Validates that:
|
|
3480
|
-
* - AxisSensor has a unique name
|
|
3481
|
-
* - AxisSensor has an order field
|
|
3482
|
-
* - Pre-decode sensors have order < 40
|
|
3483
|
-
* - Post-decode sensors have order >= 40
|
|
3484
|
-
*
|
|
3485
|
-
* @param {AxisSensor} sensor - The sensor instance to register
|
|
3486
|
-
* @throws Error if validation fails
|
|
3487
|
-
*/
|
|
3488
|
-
register(sensor) {
|
|
3489
|
-
if (!sensor.name) {
|
|
3490
|
-
throw new Error("AxisSensor must have a name");
|
|
4148
|
+
if (envelope.ver !== CCE_PROTOCOL_VERSION) {
|
|
4149
|
+
return {
|
|
4150
|
+
allow: false,
|
|
4151
|
+
riskScore: 100,
|
|
4152
|
+
reasons: [`${CCE_ERROR.UNSUPPORTED_VERSION}: ${envelope.ver}`],
|
|
4153
|
+
code: CCE_ERROR.UNSUPPORTED_VERSION
|
|
4154
|
+
};
|
|
3491
4155
|
}
|
|
3492
|
-
|
|
3493
|
-
|
|
3494
|
-
|
|
3495
|
-
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
4156
|
+
if (!/^[0-9a-f]+$/i.test(envelope.request_nonce)) {
|
|
4157
|
+
return {
|
|
4158
|
+
allow: false,
|
|
4159
|
+
riskScore: 100,
|
|
4160
|
+
reasons: [
|
|
4161
|
+
`${CCE_ERROR.INVALID_ENVELOPE}: invalid request_nonce format`
|
|
4162
|
+
],
|
|
4163
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4164
|
+
};
|
|
3499
4165
|
}
|
|
3500
|
-
if (
|
|
3501
|
-
|
|
3502
|
-
|
|
4166
|
+
if (envelope.request_nonce.length !== CCE_NONCE_BYTES * 2) {
|
|
4167
|
+
return {
|
|
4168
|
+
allow: false,
|
|
4169
|
+
riskScore: 100,
|
|
4170
|
+
reasons: [`${CCE_ERROR.INVALID_ENVELOPE}: request_nonce wrong length`],
|
|
4171
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4172
|
+
};
|
|
3503
4173
|
}
|
|
3504
|
-
|
|
3505
|
-
|
|
4174
|
+
const capsule = envelope.capsule;
|
|
4175
|
+
if (!capsule.capsule_id || !capsule.ver || !capsule.sub || !capsule.kid || !capsule.intent || !capsule.aud || !capsule.issuer_sig) {
|
|
4176
|
+
return {
|
|
4177
|
+
allow: false,
|
|
4178
|
+
riskScore: 100,
|
|
4179
|
+
reasons: [`${CCE_ERROR.MISSING_CAPSULE}: incomplete capsule claims`],
|
|
4180
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4181
|
+
};
|
|
3506
4182
|
}
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
4183
|
+
if (!envelope.encrypted_key.ciphertext || !envelope.encrypted_key.alg) {
|
|
4184
|
+
return {
|
|
4185
|
+
allow: false,
|
|
4186
|
+
riskScore: 100,
|
|
4187
|
+
reasons: [
|
|
4188
|
+
`${CCE_ERROR.MISSING_ENCRYPTED_KEY}: incomplete encrypted_key`
|
|
4189
|
+
],
|
|
4190
|
+
code: CCE_ERROR.MISSING_ENCRYPTED_KEY
|
|
4191
|
+
};
|
|
3513
4192
|
}
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
4193
|
+
input.metadata = input.metadata ?? {};
|
|
4194
|
+
input.metadata.cceEnvelopeValid = true;
|
|
4195
|
+
return {
|
|
4196
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4197
|
+
allow: true,
|
|
4198
|
+
riskScore: 0,
|
|
4199
|
+
reasons: []
|
|
4200
|
+
};
|
|
4201
|
+
}
|
|
4202
|
+
};
|
|
4203
|
+
|
|
4204
|
+
// src/cce/sensors/cce-client-signature.sensor.ts
|
|
4205
|
+
var CceClientSignatureSensor = class {
|
|
4206
|
+
constructor(keyResolver, signatureVerifier) {
|
|
4207
|
+
this.keyResolver = keyResolver;
|
|
4208
|
+
this.signatureVerifier = signatureVerifier;
|
|
4209
|
+
this.name = "cce.client.signature";
|
|
4210
|
+
this.order = 45;
|
|
4211
|
+
this.phase = "POST_DECODE";
|
|
4212
|
+
}
|
|
4213
|
+
supports(input) {
|
|
4214
|
+
return input.metadata?.cceEnvelopeValid === true;
|
|
4215
|
+
}
|
|
4216
|
+
async run(input) {
|
|
4217
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4218
|
+
if (!envelope) {
|
|
4219
|
+
return {
|
|
4220
|
+
allow: false,
|
|
4221
|
+
riskScore: 100,
|
|
4222
|
+
reasons: [CCE_ERROR.INVALID_ENVELOPE],
|
|
4223
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4224
|
+
};
|
|
3518
4225
|
}
|
|
3519
|
-
this.
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
4226
|
+
const keyRecord = await this.keyResolver.resolve(envelope.client_kid);
|
|
4227
|
+
if (!keyRecord) {
|
|
4228
|
+
return {
|
|
4229
|
+
allow: false,
|
|
4230
|
+
riskScore: 100,
|
|
4231
|
+
reasons: [
|
|
4232
|
+
`${CCE_ERROR.CLIENT_KEY_NOT_FOUND}: kid=${envelope.client_kid}`
|
|
4233
|
+
],
|
|
4234
|
+
code: CCE_ERROR.CLIENT_KEY_NOT_FOUND
|
|
4235
|
+
};
|
|
4236
|
+
}
|
|
4237
|
+
const { client_sig, ...signable } = envelope;
|
|
4238
|
+
const canonical = canonicalize2(signable);
|
|
4239
|
+
const message = new TextEncoder().encode(canonical);
|
|
4240
|
+
const valid = await this.signatureVerifier.verify(
|
|
4241
|
+
message,
|
|
4242
|
+
client_sig.value,
|
|
4243
|
+
keyRecord.publicKeyHex,
|
|
4244
|
+
keyRecord.alg
|
|
3523
4245
|
);
|
|
4246
|
+
if (!valid) {
|
|
4247
|
+
return {
|
|
4248
|
+
allow: false,
|
|
4249
|
+
riskScore: 100,
|
|
4250
|
+
reasons: [CCE_ERROR.CLIENT_SIG_INVALID],
|
|
4251
|
+
code: CCE_ERROR.CLIENT_SIG_INVALID
|
|
4252
|
+
};
|
|
4253
|
+
}
|
|
4254
|
+
input.metadata = input.metadata ?? {};
|
|
4255
|
+
input.metadata.cceClientKey = keyRecord;
|
|
4256
|
+
input.metadata.cceClientSigVerified = true;
|
|
4257
|
+
return {
|
|
4258
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4259
|
+
allow: true,
|
|
4260
|
+
riskScore: 0,
|
|
4261
|
+
reasons: [],
|
|
4262
|
+
meta: { kid: envelope.client_kid }
|
|
4263
|
+
};
|
|
4264
|
+
}
|
|
4265
|
+
};
|
|
4266
|
+
function canonicalize2(obj) {
|
|
4267
|
+
if (Array.isArray(obj)) {
|
|
4268
|
+
return "[" + obj.map(canonicalize2).join(",") + "]";
|
|
4269
|
+
}
|
|
4270
|
+
if (obj !== null && typeof obj === "object") {
|
|
4271
|
+
const sorted = Object.keys(obj).sort().map(
|
|
4272
|
+
(k) => JSON.stringify(k) + ":" + canonicalize2(obj[k])
|
|
4273
|
+
);
|
|
4274
|
+
return "{" + sorted.join(",") + "}";
|
|
4275
|
+
}
|
|
4276
|
+
return JSON.stringify(obj);
|
|
4277
|
+
}
|
|
4278
|
+
|
|
4279
|
+
// src/cce/sensors/cce-capsule-verification.sensor.ts
|
|
4280
|
+
import { blake3 } from "@noble/hashes/blake3.js";
|
|
4281
|
+
import { bytesToHex as bytesToHex5 } from "@noble/hashes/utils.js";
|
|
4282
|
+
var CceCapsuleVerificationSensor = class {
|
|
4283
|
+
constructor(issuerKeyResolver, capsuleVerifier) {
|
|
4284
|
+
this.issuerKeyResolver = issuerKeyResolver;
|
|
4285
|
+
this.capsuleVerifier = capsuleVerifier;
|
|
4286
|
+
this.name = "cce.capsule.verification";
|
|
4287
|
+
this.order = 50;
|
|
4288
|
+
this.phase = "POST_DECODE";
|
|
4289
|
+
}
|
|
4290
|
+
supports(input) {
|
|
4291
|
+
return input.metadata?.cceEnvelopeValid === true;
|
|
4292
|
+
}
|
|
4293
|
+
async run(input) {
|
|
4294
|
+
const capsule = input.metadata?.cceEnvelope?.capsule;
|
|
4295
|
+
if (!capsule) {
|
|
4296
|
+
return {
|
|
4297
|
+
allow: false,
|
|
4298
|
+
riskScore: 100,
|
|
4299
|
+
reasons: [CCE_ERROR.MISSING_CAPSULE],
|
|
4300
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4301
|
+
};
|
|
4302
|
+
}
|
|
4303
|
+
if (capsule.ver !== CCE_PROTOCOL_VERSION) {
|
|
4304
|
+
return {
|
|
4305
|
+
allow: false,
|
|
4306
|
+
riskScore: 100,
|
|
4307
|
+
reasons: [
|
|
4308
|
+
`${CCE_ERROR.CAPSULE_SIG_INVALID}: wrong version ${capsule.ver}`
|
|
4309
|
+
],
|
|
4310
|
+
code: CCE_ERROR.CAPSULE_SIG_INVALID
|
|
4311
|
+
};
|
|
4312
|
+
}
|
|
4313
|
+
const { capsule_id, issuer_sig, ...claimsBody } = capsule;
|
|
4314
|
+
const expectedId = computeCceCapsuleId(claimsBody);
|
|
4315
|
+
if (capsule_id !== expectedId) {
|
|
4316
|
+
return {
|
|
4317
|
+
allow: false,
|
|
4318
|
+
riskScore: 100,
|
|
4319
|
+
reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: content hash mismatch`],
|
|
4320
|
+
code: CCE_ERROR.CAPSULE_SIG_INVALID
|
|
4321
|
+
};
|
|
4322
|
+
}
|
|
4323
|
+
const issuerKey = await this.issuerKeyResolver.resolve(
|
|
4324
|
+
capsule.issuer_sig.kid
|
|
4325
|
+
);
|
|
4326
|
+
if (!issuerKey) {
|
|
4327
|
+
return {
|
|
4328
|
+
allow: false,
|
|
4329
|
+
riskScore: 100,
|
|
4330
|
+
reasons: [`${CCE_ERROR.CAPSULE_SIG_INVALID}: issuer key not found`],
|
|
4331
|
+
code: CCE_ERROR.CAPSULE_SIG_INVALID
|
|
4332
|
+
};
|
|
4333
|
+
}
|
|
4334
|
+
const { issuer_sig: sig, ...rest } = capsule;
|
|
4335
|
+
const sigValid = await this.capsuleVerifier.verify(
|
|
4336
|
+
rest,
|
|
4337
|
+
sig,
|
|
4338
|
+
issuerKey.publicKeyHex
|
|
4339
|
+
);
|
|
4340
|
+
if (!sigValid) {
|
|
4341
|
+
return {
|
|
4342
|
+
allow: false,
|
|
4343
|
+
riskScore: 100,
|
|
4344
|
+
reasons: [CCE_ERROR.CAPSULE_SIG_INVALID],
|
|
4345
|
+
code: CCE_ERROR.CAPSULE_SIG_INVALID
|
|
4346
|
+
};
|
|
4347
|
+
}
|
|
4348
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
4349
|
+
if (capsule.exp < nowSeconds) {
|
|
4350
|
+
return {
|
|
4351
|
+
allow: false,
|
|
4352
|
+
riskScore: 100,
|
|
4353
|
+
reasons: [`${CCE_ERROR.CAPSULE_EXPIRED}: exp=${capsule.exp}`],
|
|
4354
|
+
code: CCE_ERROR.CAPSULE_EXPIRED
|
|
4355
|
+
};
|
|
4356
|
+
}
|
|
4357
|
+
if (capsule.iat > nowSeconds + 5) {
|
|
4358
|
+
return {
|
|
4359
|
+
allow: false,
|
|
4360
|
+
riskScore: 100,
|
|
4361
|
+
reasons: [`${CCE_ERROR.CAPSULE_NOT_YET_VALID}: iat=${capsule.iat}`],
|
|
4362
|
+
code: CCE_ERROR.CAPSULE_NOT_YET_VALID
|
|
4363
|
+
};
|
|
4364
|
+
}
|
|
4365
|
+
input.metadata = input.metadata ?? {};
|
|
4366
|
+
input.metadata.cceCapsuleVerified = true;
|
|
4367
|
+
input.metadata.cceCapsule = capsule;
|
|
4368
|
+
return {
|
|
4369
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4370
|
+
allow: true,
|
|
4371
|
+
riskScore: 0,
|
|
4372
|
+
reasons: [],
|
|
4373
|
+
meta: { capsule_id: capsule.capsule_id }
|
|
4374
|
+
};
|
|
4375
|
+
}
|
|
4376
|
+
};
|
|
4377
|
+
function canonicalize3(obj) {
|
|
4378
|
+
if (Array.isArray(obj)) {
|
|
4379
|
+
return "[" + obj.map(canonicalize3).join(",") + "]";
|
|
4380
|
+
}
|
|
4381
|
+
if (obj !== null && typeof obj === "object") {
|
|
4382
|
+
const sorted = Object.keys(obj).sort().map(
|
|
4383
|
+
(k) => JSON.stringify(k) + ":" + canonicalize3(obj[k])
|
|
4384
|
+
);
|
|
4385
|
+
return "{" + sorted.join(",") + "}";
|
|
4386
|
+
}
|
|
4387
|
+
return JSON.stringify(obj);
|
|
4388
|
+
}
|
|
4389
|
+
function computeCceCapsuleId(claims) {
|
|
4390
|
+
const canonical = canonicalize3(claims);
|
|
4391
|
+
const hash = blake3(new TextEncoder().encode(canonical));
|
|
4392
|
+
return "cce_b3_" + bytesToHex5(hash).slice(0, 32);
|
|
4393
|
+
}
|
|
4394
|
+
|
|
4395
|
+
// src/cce/sensors/cce-tps-window.sensor.ts
|
|
4396
|
+
var DEFAULT_SKEW_MS = 5e3;
|
|
4397
|
+
var CceTpsWindowSensor = class {
|
|
4398
|
+
constructor(skewMs = DEFAULT_SKEW_MS) {
|
|
4399
|
+
this.skewMs = skewMs;
|
|
4400
|
+
this.name = "cce.tps.window";
|
|
4401
|
+
this.order = 92;
|
|
4402
|
+
this.phase = "POST_DECODE";
|
|
4403
|
+
}
|
|
4404
|
+
supports(input) {
|
|
4405
|
+
return input.metadata?.cceCapsuleVerified === true;
|
|
4406
|
+
}
|
|
4407
|
+
async run(input) {
|
|
4408
|
+
const capsule = input.metadata?.cceCapsule;
|
|
4409
|
+
if (!capsule) {
|
|
4410
|
+
return {
|
|
4411
|
+
allow: false,
|
|
4412
|
+
riskScore: 100,
|
|
4413
|
+
reasons: [CCE_ERROR.MISSING_CAPSULE],
|
|
4414
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4415
|
+
};
|
|
4416
|
+
}
|
|
4417
|
+
const nowMs = Date.now();
|
|
4418
|
+
if (nowMs > capsule.tps_to + this.skewMs) {
|
|
4419
|
+
return {
|
|
4420
|
+
allow: false,
|
|
4421
|
+
riskScore: 100,
|
|
4422
|
+
reasons: [
|
|
4423
|
+
`${CCE_ERROR.TPS_WINDOW_EXPIRED}: window ended at ${capsule.tps_to}, now=${nowMs}`
|
|
4424
|
+
],
|
|
4425
|
+
code: CCE_ERROR.TPS_WINDOW_EXPIRED
|
|
4426
|
+
};
|
|
4427
|
+
}
|
|
4428
|
+
if (nowMs < capsule.tps_from - this.skewMs) {
|
|
4429
|
+
return {
|
|
4430
|
+
allow: false,
|
|
4431
|
+
riskScore: 100,
|
|
4432
|
+
reasons: [
|
|
4433
|
+
`${CCE_ERROR.TPS_WINDOW_FUTURE}: window starts at ${capsule.tps_from}, now=${nowMs}`
|
|
4434
|
+
],
|
|
4435
|
+
code: CCE_ERROR.TPS_WINDOW_FUTURE
|
|
4436
|
+
};
|
|
4437
|
+
}
|
|
4438
|
+
input.metadata = input.metadata ?? {};
|
|
4439
|
+
input.metadata.cceTpsValid = true;
|
|
4440
|
+
return {
|
|
4441
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4442
|
+
allow: true,
|
|
4443
|
+
riskScore: 0,
|
|
4444
|
+
reasons: []
|
|
4445
|
+
};
|
|
4446
|
+
}
|
|
4447
|
+
};
|
|
4448
|
+
|
|
4449
|
+
// src/cce/sensors/cce-audience-intent-binding.sensor.ts
|
|
4450
|
+
var CceAudienceIntentBindingSensor = class {
|
|
4451
|
+
constructor(axisAudience) {
|
|
4452
|
+
this.axisAudience = axisAudience;
|
|
4453
|
+
this.name = "cce.audience.intent.binding";
|
|
4454
|
+
this.order = 95;
|
|
4455
|
+
this.phase = "POST_DECODE";
|
|
4456
|
+
}
|
|
4457
|
+
supports(input) {
|
|
4458
|
+
return input.metadata?.cceCapsuleVerified === true;
|
|
4459
|
+
}
|
|
4460
|
+
async run(input) {
|
|
4461
|
+
const capsule = input.metadata?.cceCapsule;
|
|
4462
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4463
|
+
if (!capsule || !envelope) {
|
|
4464
|
+
return {
|
|
4465
|
+
allow: false,
|
|
4466
|
+
riskScore: 100,
|
|
4467
|
+
reasons: [CCE_ERROR.MISSING_CAPSULE],
|
|
4468
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4469
|
+
};
|
|
4470
|
+
}
|
|
4471
|
+
if (capsule.aud !== this.axisAudience) {
|
|
4472
|
+
return {
|
|
4473
|
+
allow: false,
|
|
4474
|
+
riskScore: 100,
|
|
4475
|
+
reasons: [
|
|
4476
|
+
`${CCE_ERROR.AUDIENCE_MISMATCH}: capsule.aud=${capsule.aud}, expected=${this.axisAudience}`
|
|
4477
|
+
],
|
|
4478
|
+
code: CCE_ERROR.AUDIENCE_MISMATCH
|
|
4479
|
+
};
|
|
4480
|
+
}
|
|
4481
|
+
const requestIntent = input.intent ?? input.metadata?.cceRequestIntent;
|
|
4482
|
+
if (requestIntent && capsule.intent !== requestIntent) {
|
|
4483
|
+
return {
|
|
4484
|
+
allow: false,
|
|
4485
|
+
riskScore: 100,
|
|
4486
|
+
reasons: [
|
|
4487
|
+
`${CCE_ERROR.INTENT_MISMATCH}: capsule.intent=${capsule.intent}, request=${requestIntent}`
|
|
4488
|
+
],
|
|
4489
|
+
code: CCE_ERROR.INTENT_MISMATCH
|
|
4490
|
+
};
|
|
4491
|
+
}
|
|
4492
|
+
if (envelope.client_kid !== capsule.kid) {
|
|
4493
|
+
return {
|
|
4494
|
+
allow: false,
|
|
4495
|
+
riskScore: 100,
|
|
4496
|
+
reasons: [
|
|
4497
|
+
`${CCE_ERROR.INTENT_MISMATCH}: envelope.kid=${envelope.client_kid}, capsule.kid=${capsule.kid}`
|
|
4498
|
+
],
|
|
4499
|
+
code: CCE_ERROR.INTENT_MISMATCH
|
|
4500
|
+
};
|
|
4501
|
+
}
|
|
4502
|
+
input.metadata = input.metadata ?? {};
|
|
4503
|
+
input.metadata.cceBindingVerified = true;
|
|
4504
|
+
return {
|
|
4505
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4506
|
+
allow: true,
|
|
4507
|
+
riskScore: 0,
|
|
4508
|
+
reasons: []
|
|
4509
|
+
};
|
|
4510
|
+
}
|
|
4511
|
+
};
|
|
4512
|
+
|
|
4513
|
+
// src/cce/sensors/cce-replay-protection.sensor.ts
|
|
4514
|
+
var InMemoryCceReplayStore = class {
|
|
4515
|
+
constructor() {
|
|
4516
|
+
this.nonces = /* @__PURE__ */ new Map();
|
|
4517
|
+
this.consumed = /* @__PURE__ */ new Set();
|
|
4518
|
+
this.revoked = /* @__PURE__ */ new Set();
|
|
4519
|
+
}
|
|
4520
|
+
async checkAndMark(key, ttlMs) {
|
|
4521
|
+
this.cleanup();
|
|
4522
|
+
if (this.nonces.has(key)) return false;
|
|
4523
|
+
this.nonces.set(key, Date.now() + ttlMs);
|
|
4524
|
+
return true;
|
|
4525
|
+
}
|
|
4526
|
+
async isCapsuleConsumed(capsuleId) {
|
|
4527
|
+
return this.consumed.has(capsuleId);
|
|
4528
|
+
}
|
|
4529
|
+
async markCapsuleConsumed(capsuleId, _ttlMs) {
|
|
4530
|
+
this.consumed.add(capsuleId);
|
|
4531
|
+
}
|
|
4532
|
+
async isCapsuleRevoked(capsuleId) {
|
|
4533
|
+
return this.revoked.has(capsuleId);
|
|
4534
|
+
}
|
|
4535
|
+
/** Revoke a capsule (for testing/admin) */
|
|
4536
|
+
revoke(capsuleId) {
|
|
4537
|
+
this.revoked.add(capsuleId);
|
|
4538
|
+
}
|
|
4539
|
+
cleanup() {
|
|
4540
|
+
const now = Date.now();
|
|
4541
|
+
for (const [key, expiresAt] of this.nonces) {
|
|
4542
|
+
if (expiresAt < now) this.nonces.delete(key);
|
|
4543
|
+
}
|
|
4544
|
+
}
|
|
4545
|
+
};
|
|
4546
|
+
var CceReplayProtectionSensor = class {
|
|
4547
|
+
constructor(replayStore, options) {
|
|
4548
|
+
this.replayStore = replayStore;
|
|
4549
|
+
this.name = "cce.replay.protection";
|
|
4550
|
+
this.order = 98;
|
|
4551
|
+
this.phase = "POST_DECODE";
|
|
4552
|
+
this.nonceTtlMs = options?.nonceTtlMs ?? 5 * 60 * 1e3;
|
|
4553
|
+
}
|
|
4554
|
+
supports(input) {
|
|
4555
|
+
return input.metadata?.cceCapsuleVerified === true;
|
|
4556
|
+
}
|
|
4557
|
+
async run(input) {
|
|
4558
|
+
const capsule = input.metadata?.cceCapsule;
|
|
4559
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4560
|
+
if (!capsule || !envelope) {
|
|
4561
|
+
return {
|
|
4562
|
+
allow: false,
|
|
4563
|
+
riskScore: 100,
|
|
4564
|
+
reasons: [CCE_ERROR.MISSING_CAPSULE],
|
|
4565
|
+
code: CCE_ERROR.MISSING_CAPSULE
|
|
4566
|
+
};
|
|
4567
|
+
}
|
|
4568
|
+
const revoked = await this.replayStore.isCapsuleRevoked(capsule.capsule_id);
|
|
4569
|
+
if (revoked) {
|
|
4570
|
+
return {
|
|
4571
|
+
allow: false,
|
|
4572
|
+
riskScore: 100,
|
|
4573
|
+
reasons: [`${CCE_ERROR.CAPSULE_REVOKED}: ${capsule.capsule_id}`],
|
|
4574
|
+
code: CCE_ERROR.CAPSULE_REVOKED
|
|
4575
|
+
};
|
|
4576
|
+
}
|
|
4577
|
+
if (capsule.mode === "SINGLE_USE") {
|
|
4578
|
+
const consumed = await this.replayStore.isCapsuleConsumed(
|
|
4579
|
+
capsule.capsule_id
|
|
4580
|
+
);
|
|
4581
|
+
if (consumed) {
|
|
4582
|
+
return {
|
|
4583
|
+
allow: false,
|
|
4584
|
+
riskScore: 100,
|
|
4585
|
+
reasons: [`${CCE_ERROR.CAPSULE_CONSUMED}: ${capsule.capsule_id}`],
|
|
4586
|
+
code: CCE_ERROR.CAPSULE_CONSUMED
|
|
4587
|
+
};
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
const nonceKey = `cce:nonce:${capsule.sub}:${capsule.aud}:${capsule.intent}:${envelope.request_nonce}`;
|
|
4591
|
+
const nonceValid = await this.replayStore.checkAndMark(
|
|
4592
|
+
nonceKey,
|
|
4593
|
+
this.nonceTtlMs
|
|
4594
|
+
);
|
|
4595
|
+
if (!nonceValid) {
|
|
4596
|
+
return {
|
|
4597
|
+
allow: false,
|
|
4598
|
+
riskScore: 100,
|
|
4599
|
+
reasons: [
|
|
4600
|
+
`${CCE_ERROR.NONCE_REUSED}: ${envelope.request_nonce.slice(0, 16)}...`
|
|
4601
|
+
],
|
|
4602
|
+
code: CCE_ERROR.NONCE_REUSED
|
|
4603
|
+
};
|
|
4604
|
+
}
|
|
4605
|
+
if (capsule.mode === "SINGLE_USE") {
|
|
4606
|
+
const capsuleTtl = (capsule.exp - capsule.iat) * 1e3 + 6e4;
|
|
4607
|
+
await this.replayStore.markCapsuleConsumed(
|
|
4608
|
+
capsule.capsule_id,
|
|
4609
|
+
capsuleTtl
|
|
4610
|
+
);
|
|
4611
|
+
}
|
|
4612
|
+
input.metadata = input.metadata ?? {};
|
|
4613
|
+
input.metadata.cceReplayClean = true;
|
|
4614
|
+
return {
|
|
4615
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4616
|
+
allow: true,
|
|
4617
|
+
riskScore: 0,
|
|
4618
|
+
reasons: []
|
|
4619
|
+
};
|
|
4620
|
+
}
|
|
4621
|
+
};
|
|
4622
|
+
|
|
4623
|
+
// src/cce/sensors/cce-payload-decryption.sensor.ts
|
|
4624
|
+
var CcePayloadDecryptionSensor = class {
|
|
4625
|
+
constructor(keyProvider, aesProvider, maxPayloadBytes = 64 * 1024) {
|
|
4626
|
+
this.keyProvider = keyProvider;
|
|
4627
|
+
this.aesProvider = aesProvider;
|
|
4628
|
+
this.maxPayloadBytes = maxPayloadBytes;
|
|
4629
|
+
this.name = "cce.payload.decryption";
|
|
4630
|
+
this.order = 145;
|
|
4631
|
+
this.phase = "POST_DECODE";
|
|
4632
|
+
}
|
|
4633
|
+
supports(input) {
|
|
4634
|
+
return input.metadata?.cceEnvelopeValid === true && input.metadata?.cceClientSigVerified === true && input.metadata?.cceCapsuleVerified === true && input.metadata?.cceReplayClean === true;
|
|
4635
|
+
}
|
|
4636
|
+
async run(input) {
|
|
4637
|
+
const envelope = input.metadata?.cceEnvelope;
|
|
4638
|
+
if (!envelope) {
|
|
4639
|
+
return {
|
|
4640
|
+
allow: false,
|
|
4641
|
+
riskScore: 100,
|
|
4642
|
+
reasons: [CCE_ERROR.INVALID_ENVELOPE],
|
|
4643
|
+
code: CCE_ERROR.INVALID_ENVELOPE
|
|
4644
|
+
};
|
|
4645
|
+
}
|
|
4646
|
+
let aesKey;
|
|
4647
|
+
try {
|
|
4648
|
+
aesKey = await this.keyProvider.unwrapKey(
|
|
4649
|
+
envelope.encrypted_key.ciphertext,
|
|
4650
|
+
envelope.encrypted_key.alg,
|
|
4651
|
+
envelope.encrypted_key.axis_kid,
|
|
4652
|
+
envelope.encrypted_key.ephemeral_pk
|
|
4653
|
+
);
|
|
4654
|
+
} catch {
|
|
4655
|
+
return {
|
|
4656
|
+
allow: false,
|
|
4657
|
+
riskScore: 100,
|
|
4658
|
+
reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
|
|
4659
|
+
code: CCE_ERROR.KEY_UNWRAP_FAILED
|
|
4660
|
+
};
|
|
4661
|
+
}
|
|
4662
|
+
if (!aesKey) {
|
|
4663
|
+
return {
|
|
4664
|
+
allow: false,
|
|
4665
|
+
riskScore: 100,
|
|
4666
|
+
reasons: [CCE_ERROR.KEY_UNWRAP_FAILED],
|
|
4667
|
+
code: CCE_ERROR.KEY_UNWRAP_FAILED
|
|
4668
|
+
};
|
|
4669
|
+
}
|
|
4670
|
+
let iv;
|
|
4671
|
+
let ciphertext;
|
|
4672
|
+
let tag;
|
|
4673
|
+
try {
|
|
4674
|
+
iv = base64UrlDecode2(envelope.encrypted_payload.iv);
|
|
4675
|
+
ciphertext = base64UrlDecode2(envelope.encrypted_payload.ciphertext);
|
|
4676
|
+
tag = base64UrlDecode2(envelope.encrypted_payload.tag);
|
|
4677
|
+
} catch {
|
|
4678
|
+
return {
|
|
4679
|
+
allow: false,
|
|
4680
|
+
riskScore: 100,
|
|
4681
|
+
reasons: [`${CCE_ERROR.DECRYPTION_FAILED}: invalid base64url encoding`],
|
|
4682
|
+
code: CCE_ERROR.DECRYPTION_FAILED
|
|
4683
|
+
};
|
|
4684
|
+
}
|
|
4685
|
+
if (ciphertext.length > this.maxPayloadBytes) {
|
|
4686
|
+
return {
|
|
4687
|
+
allow: false,
|
|
4688
|
+
riskScore: 100,
|
|
4689
|
+
reasons: [
|
|
4690
|
+
`${CCE_ERROR.PAYLOAD_TOO_LARGE}: ${ciphertext.length} > ${this.maxPayloadBytes}`
|
|
4691
|
+
],
|
|
4692
|
+
code: CCE_ERROR.PAYLOAD_TOO_LARGE
|
|
4693
|
+
};
|
|
4694
|
+
}
|
|
4695
|
+
const aad = buildAad(envelope);
|
|
4696
|
+
let plaintext;
|
|
4697
|
+
try {
|
|
4698
|
+
plaintext = await this.aesProvider.decrypt(
|
|
4699
|
+
aesKey,
|
|
4700
|
+
iv,
|
|
4701
|
+
ciphertext,
|
|
4702
|
+
tag,
|
|
4703
|
+
aad
|
|
4704
|
+
);
|
|
4705
|
+
} catch {
|
|
4706
|
+
plaintext = null;
|
|
4707
|
+
} finally {
|
|
4708
|
+
aesKey.fill(0);
|
|
4709
|
+
}
|
|
4710
|
+
if (!plaintext) {
|
|
4711
|
+
return {
|
|
4712
|
+
allow: false,
|
|
4713
|
+
riskScore: 100,
|
|
4714
|
+
reasons: [CCE_ERROR.AEAD_TAG_MISMATCH],
|
|
4715
|
+
code: CCE_ERROR.AEAD_TAG_MISMATCH
|
|
4716
|
+
};
|
|
4717
|
+
}
|
|
4718
|
+
input.metadata = input.metadata ?? {};
|
|
4719
|
+
input.metadata.cceDecryptedPayload = plaintext;
|
|
4720
|
+
input.metadata.cceDecryptionOk = true;
|
|
4721
|
+
return {
|
|
4722
|
+
decision: "ALLOW" /* ALLOW */,
|
|
4723
|
+
allow: true,
|
|
4724
|
+
riskScore: 0,
|
|
4725
|
+
reasons: []
|
|
4726
|
+
};
|
|
4727
|
+
}
|
|
4728
|
+
};
|
|
4729
|
+
function buildAad(envelope) {
|
|
4730
|
+
const parts = [
|
|
4731
|
+
envelope.ver,
|
|
4732
|
+
envelope.request_id,
|
|
4733
|
+
envelope.correlation_id,
|
|
4734
|
+
envelope.client_kid,
|
|
4735
|
+
envelope.capsule.capsule_id,
|
|
4736
|
+
envelope.capsule.intent,
|
|
4737
|
+
envelope.capsule.aud,
|
|
4738
|
+
envelope.request_nonce
|
|
4739
|
+
];
|
|
4740
|
+
return new TextEncoder().encode(parts.join("|"));
|
|
4741
|
+
}
|
|
4742
|
+
function base64UrlDecode2(input) {
|
|
4743
|
+
const base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
|
4744
|
+
const padding = "=".repeat((4 - base64.length % 4) % 4);
|
|
4745
|
+
const binary = atob(base64 + padding);
|
|
4746
|
+
const bytes2 = new Uint8Array(binary.length);
|
|
4747
|
+
for (let i = 0; i < binary.length; i++) {
|
|
4748
|
+
bytes2[i] = binary.charCodeAt(i);
|
|
4749
|
+
}
|
|
4750
|
+
return bytes2;
|
|
4751
|
+
}
|
|
4752
|
+
|
|
4753
|
+
// src/core/index.ts
|
|
4754
|
+
var core_exports = {};
|
|
4755
|
+
__export(core_exports, {
|
|
4756
|
+
AXIS_MAGIC: () => AXIS_MAGIC,
|
|
4757
|
+
AXIS_VERSION: () => AXIS_VERSION,
|
|
4758
|
+
AxisError: () => AxisError,
|
|
4759
|
+
AxisFrameZ: () => AxisFrameZ,
|
|
4760
|
+
BodyProfile: () => BodyProfile,
|
|
4761
|
+
ERR_BAD_SIGNATURE: () => ERR_BAD_SIGNATURE,
|
|
4762
|
+
ERR_CONTRACT_VIOLATION: () => ERR_CONTRACT_VIOLATION,
|
|
4763
|
+
ERR_INVALID_PACKET: () => ERR_INVALID_PACKET,
|
|
4764
|
+
ERR_REPLAY_DETECTED: () => ERR_REPLAY_DETECTED,
|
|
4765
|
+
FLAG_BODY_TLV: () => FLAG_BODY_TLV,
|
|
4766
|
+
FLAG_CHAIN_REQ: () => FLAG_CHAIN_REQ,
|
|
4767
|
+
FLAG_HAS_WITNESS: () => FLAG_HAS_WITNESS,
|
|
4768
|
+
MAX_BODY_LEN: () => MAX_BODY_LEN,
|
|
4769
|
+
MAX_FRAME_LEN: () => MAX_FRAME_LEN,
|
|
4770
|
+
MAX_HDR_LEN: () => MAX_HDR_LEN,
|
|
4771
|
+
MAX_SIG_LEN: () => MAX_SIG_LEN,
|
|
4772
|
+
NCERT_ALG: () => NCERT_ALG,
|
|
4773
|
+
NCERT_EXP: () => NCERT_EXP,
|
|
4774
|
+
NCERT_ISSUER_KID: () => NCERT_ISSUER_KID,
|
|
4775
|
+
NCERT_KID: () => NCERT_KID,
|
|
4776
|
+
NCERT_NBF: () => NCERT_NBF,
|
|
4777
|
+
NCERT_NODE_ID: () => NCERT_NODE_ID,
|
|
4778
|
+
NCERT_PAYLOAD: () => NCERT_PAYLOAD,
|
|
4779
|
+
NCERT_PUB: () => NCERT_PUB,
|
|
4780
|
+
NCERT_SCOPE: () => NCERT_SCOPE,
|
|
4781
|
+
NCERT_SIG: () => NCERT_SIG,
|
|
4782
|
+
PROOF_CAPSULE: () => PROOF_CAPSULE,
|
|
4783
|
+
PROOF_JWT: () => PROOF_JWT,
|
|
4784
|
+
PROOF_LOOM: () => PROOF_LOOM,
|
|
4785
|
+
PROOF_MTLS: () => PROOF_MTLS,
|
|
4786
|
+
PROOF_NONE: () => PROOF_NONE,
|
|
4787
|
+
PROOF_WITNESS: () => PROOF_WITNESS,
|
|
4788
|
+
ProofType: () => ProofType,
|
|
4789
|
+
TLV: () => TLV,
|
|
4790
|
+
TLV_ACTOR_ID: () => TLV_ACTOR_ID,
|
|
4791
|
+
TLV_AUD: () => TLV_AUD,
|
|
4792
|
+
TLV_BODY_ARR: () => TLV_BODY_ARR,
|
|
4793
|
+
TLV_BODY_OBJ: () => TLV_BODY_OBJ,
|
|
4794
|
+
TLV_CAPSULE: () => TLV_CAPSULE,
|
|
4795
|
+
TLV_EFFECT: () => TLV_EFFECT,
|
|
4796
|
+
TLV_ERROR_CODE: () => TLV_ERROR_CODE,
|
|
4797
|
+
TLV_ERROR_MSG: () => TLV_ERROR_MSG,
|
|
4798
|
+
TLV_INDEX: () => TLV_INDEX,
|
|
4799
|
+
TLV_INTENT: () => TLV_INTENT,
|
|
4800
|
+
TLV_KID: () => TLV_KID,
|
|
4801
|
+
TLV_LOOM_PRESENCE_ID: () => TLV_LOOM_PRESENCE_ID,
|
|
4802
|
+
TLV_LOOM_THREAD_HASH: () => TLV_LOOM_THREAD_HASH,
|
|
4803
|
+
TLV_LOOM_WRIT: () => TLV_LOOM_WRIT,
|
|
4804
|
+
TLV_NODE: () => TLV_NODE,
|
|
4805
|
+
TLV_NODE_CERT_HASH: () => TLV_NODE_CERT_HASH,
|
|
4806
|
+
TLV_NODE_KID: () => TLV_NODE_KID,
|
|
4807
|
+
TLV_NONCE: () => TLV_NONCE,
|
|
4808
|
+
TLV_OFFSET: () => TLV_OFFSET,
|
|
4809
|
+
TLV_OK: () => TLV_OK,
|
|
4810
|
+
TLV_PID: () => TLV_PID,
|
|
4811
|
+
TLV_PREV_HASH: () => TLV_PREV_HASH,
|
|
4812
|
+
TLV_PROOF_REF: () => TLV_PROOF_REF,
|
|
4813
|
+
TLV_PROOF_TYPE: () => TLV_PROOF_TYPE,
|
|
4814
|
+
TLV_REALM: () => TLV_REALM,
|
|
4815
|
+
TLV_RECEIPT_HASH: () => TLV_RECEIPT_HASH,
|
|
4816
|
+
TLV_RID: () => TLV_RID,
|
|
4817
|
+
TLV_SHA256_CHUNK: () => TLV_SHA256_CHUNK,
|
|
4818
|
+
TLV_TRACE_ID: () => TLV_TRACE_ID,
|
|
4819
|
+
TLV_TS: () => TLV_TS,
|
|
4820
|
+
TLV_UPLOAD_ID: () => TLV_UPLOAD_ID,
|
|
4821
|
+
computeReceiptHash: () => computeReceiptHash,
|
|
4822
|
+
computeSignaturePayload: () => computeSignaturePayload,
|
|
4823
|
+
decodeArray: () => decodeArray,
|
|
4824
|
+
decodeFrame: () => decodeFrame,
|
|
4825
|
+
decodeObject: () => decodeObject,
|
|
4826
|
+
decodeTLVs: () => decodeTLVs,
|
|
4827
|
+
decodeTLVsList: () => decodeTLVsList,
|
|
4828
|
+
decodeVarint: () => decodeVarint,
|
|
4829
|
+
encodeFrame: () => encodeFrame,
|
|
4830
|
+
encodeTLVs: () => encodeTLVs,
|
|
4831
|
+
encodeVarint: () => encodeVarint,
|
|
4832
|
+
generateEd25519KeyPair: () => generateEd25519KeyPair,
|
|
4833
|
+
getSignTarget: () => getSignTarget,
|
|
4834
|
+
sha256: () => sha2564,
|
|
4835
|
+
signFrame: () => signFrame,
|
|
4836
|
+
varintLength: () => varintLength,
|
|
4837
|
+
verifyFrameSignature: () => verifyFrameSignature
|
|
4838
|
+
});
|
|
4839
|
+
|
|
4840
|
+
// src/crypto/index.ts
|
|
4841
|
+
var crypto_exports = {};
|
|
4842
|
+
__export(crypto_exports, {
|
|
4843
|
+
ProofVerificationService: () => ProofVerificationService,
|
|
4844
|
+
b64urlDecode: () => b64urlDecode,
|
|
4845
|
+
b64urlDecodeString: () => b64urlDecodeString,
|
|
4846
|
+
b64urlEncode: () => b64urlEncode,
|
|
4847
|
+
b64urlEncodeString: () => b64urlEncodeString,
|
|
4848
|
+
canonicalJson: () => canonicalJson,
|
|
4849
|
+
canonicalJsonExcluding: () => canonicalJsonExcluding
|
|
4850
|
+
});
|
|
4851
|
+
|
|
4852
|
+
// src/crypto/proof-verification.service.ts
|
|
4853
|
+
import { Injectable as Injectable8, Logger as Logger7 } from "@nestjs/common";
|
|
4854
|
+
import * as crypto4 from "crypto";
|
|
4855
|
+
import * as nacl from "tweetnacl";
|
|
4856
|
+
var ProofVerificationService = class {
|
|
4857
|
+
constructor() {
|
|
4858
|
+
this.logger = new Logger7(ProofVerificationService.name);
|
|
4859
|
+
// Cache of registered device public keys (deviceId -> pubKey)
|
|
4860
|
+
this.deviceKeys = /* @__PURE__ */ new Map();
|
|
4861
|
+
// Cache of trusted mTLS certificate fingerprints
|
|
4862
|
+
this.trustedCerts = /* @__PURE__ */ new Map();
|
|
4863
|
+
}
|
|
4864
|
+
/**
|
|
4865
|
+
* Verifies an authentication proof based on its type.
|
|
4866
|
+
*
|
|
4867
|
+
* **Supported Types:**
|
|
4868
|
+
* - 1 (CAPSULE): Delegated to `verifyCapsuleProof`
|
|
4869
|
+
* - 2 (JWT): Verified by `verifyJWTProof`
|
|
4870
|
+
* - 3 (MTLS_ID): Verified by `verifyMTLSProof`
|
|
4871
|
+
* - 4 (DEVICE_SE): Verified by `verifyDeviceSEProof`
|
|
4872
|
+
*
|
|
4873
|
+
* @param {ProofType} proofType - The numeric AXIS proof type
|
|
4874
|
+
* @param {Uint8Array} proofRef - The binary reference or token for the proof
|
|
4875
|
+
* @param {Object} context - Additional metadata required for specific proof types
|
|
4876
|
+
* @param {Uint8Array} [context.signTarget] - The canonical bytes that were signed (for Ed25519)
|
|
4877
|
+
* @param {Uint8Array} [context.signature] - The signature to verify (for Ed25519)
|
|
4878
|
+
* @param {MTLSContext} [context.mtls] - mTLS certificate data
|
|
4879
|
+
* @param {DeviceSEContext} [context.deviceSE] - Device Secure Element information
|
|
4880
|
+
* @returns {Promise<ProofVerificationResult>} The outcome of the verification
|
|
4881
|
+
*/
|
|
4882
|
+
async verifyProof(proofType, proofRef, context) {
|
|
4883
|
+
switch (proofType) {
|
|
4884
|
+
case 1:
|
|
4885
|
+
return this.verifyCapsuleProof(proofRef);
|
|
4886
|
+
case 2:
|
|
4887
|
+
return this.verifyJWTProof(proofRef);
|
|
4888
|
+
case 3:
|
|
4889
|
+
return this.verifyMTLSProof(context.mtls);
|
|
4890
|
+
case 4:
|
|
4891
|
+
return this.verifyDeviceSEProof(
|
|
4892
|
+
context.signTarget,
|
|
4893
|
+
context.signature,
|
|
4894
|
+
context.deviceSE
|
|
4895
|
+
);
|
|
4896
|
+
default:
|
|
4897
|
+
return { valid: false, error: `Unknown proof type: ${proofType}` };
|
|
4898
|
+
}
|
|
4899
|
+
}
|
|
4900
|
+
/**
|
|
4901
|
+
* Verify CAPSULE proof (delegated to CapsuleService)
|
|
4902
|
+
*/
|
|
4903
|
+
async verifyCapsuleProof(proofRef) {
|
|
4904
|
+
const capsuleId = new TextDecoder().decode(proofRef);
|
|
4905
|
+
return {
|
|
4906
|
+
valid: true,
|
|
4907
|
+
metadata: { capsuleId, requiresCapsuleValidation: true }
|
|
4908
|
+
};
|
|
4909
|
+
}
|
|
4910
|
+
/**
|
|
4911
|
+
* Verifies a JSON Web Token (JWT) proof.
|
|
4912
|
+
*
|
|
4913
|
+
* **Validation Logic:**
|
|
4914
|
+
* 1. Decodes the token string.
|
|
4915
|
+
* 2. Checks for valid 3-part JWT structure.
|
|
4916
|
+
* 3. Validates `exp` (expiration) and `nbf` (not before) claims.
|
|
4917
|
+
* 4. Extracts `actor_id` or `sub` as the identity.
|
|
4918
|
+
*
|
|
4919
|
+
* @param {Uint8Array} proofRef - Binary representation of the JWT string
|
|
4920
|
+
* @returns {Promise<ProofVerificationResult>} Result including the actor identifier
|
|
4921
|
+
*/
|
|
4922
|
+
async verifyJWTProof(proofRef) {
|
|
4923
|
+
try {
|
|
4924
|
+
const token = new TextDecoder().decode(proofRef);
|
|
4925
|
+
const parts = token.split(".");
|
|
4926
|
+
if (parts.length !== 3) {
|
|
4927
|
+
return { valid: false, error: "Invalid JWT format" };
|
|
4928
|
+
}
|
|
4929
|
+
const header = JSON.parse(Buffer.from(parts[0], "base64url").toString());
|
|
4930
|
+
const payload = JSON.parse(Buffer.from(parts[1], "base64url").toString());
|
|
4931
|
+
if (payload.exp && Date.now() / 1e3 > payload.exp) {
|
|
4932
|
+
return { valid: false, error: "JWT expired" };
|
|
4933
|
+
}
|
|
4934
|
+
if (payload.nbf && Date.now() / 1e3 < payload.nbf) {
|
|
4935
|
+
return { valid: false, error: "JWT not yet valid" };
|
|
4936
|
+
}
|
|
4937
|
+
return {
|
|
4938
|
+
valid: true,
|
|
4939
|
+
actorId: payload.sub || payload.actor_id,
|
|
4940
|
+
metadata: { iss: payload.iss, scope: payload.scope }
|
|
4941
|
+
};
|
|
4942
|
+
} catch (e) {
|
|
4943
|
+
const message = e instanceof Error ? e.message : "Unknown error";
|
|
4944
|
+
return { valid: false, error: `JWT parse error: ${message}` };
|
|
4945
|
+
}
|
|
3524
4946
|
}
|
|
3525
4947
|
/**
|
|
3526
|
-
*
|
|
3527
|
-
*
|
|
3528
|
-
* @returns {AxisSensor[]} A sorted array of sensors
|
|
4948
|
+
* Verify mTLS client certificate proof
|
|
3529
4949
|
*/
|
|
3530
|
-
|
|
3531
|
-
|
|
3532
|
-
|
|
3533
|
-
|
|
4950
|
+
async verifyMTLSProof(mtls) {
|
|
4951
|
+
if (!mtls) {
|
|
4952
|
+
return { valid: false, error: "No mTLS context provided" };
|
|
4953
|
+
}
|
|
4954
|
+
if (!mtls.verified) {
|
|
4955
|
+
return { valid: false, error: "mTLS not verified by TLS terminator" };
|
|
4956
|
+
}
|
|
4957
|
+
if (mtls.clientCertFingerprint) {
|
|
4958
|
+
const trusted = this.trustedCerts.get(mtls.clientCertFingerprint);
|
|
4959
|
+
if (trusted) {
|
|
4960
|
+
return {
|
|
4961
|
+
valid: true,
|
|
4962
|
+
actorId: trusted.actorId,
|
|
4963
|
+
metadata: {
|
|
4964
|
+
fingerprint: mtls.clientCertFingerprint,
|
|
4965
|
+
subject: mtls.clientCertSubject
|
|
4966
|
+
}
|
|
4967
|
+
};
|
|
4968
|
+
}
|
|
4969
|
+
}
|
|
4970
|
+
if (mtls.clientCertSubject) {
|
|
4971
|
+
const cnMatch = mtls.clientCertSubject.match(/CN=([^,]+)/);
|
|
4972
|
+
if (cnMatch) {
|
|
4973
|
+
return {
|
|
4974
|
+
valid: true,
|
|
4975
|
+
actorId: cnMatch[1],
|
|
4976
|
+
metadata: {
|
|
4977
|
+
subject: mtls.clientCertSubject,
|
|
4978
|
+
issuer: mtls.clientCertIssuer
|
|
4979
|
+
}
|
|
4980
|
+
};
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
return { valid: false, error: "Could not extract actor from certificate" };
|
|
3534
4984
|
}
|
|
3535
4985
|
/**
|
|
3536
|
-
*
|
|
3537
|
-
* These sensors run in middleware on raw bytes before frame decoding.
|
|
3538
|
-
*
|
|
3539
|
-
* @returns {AxisPreSensor[]} Pre-decode sensors sorted by order
|
|
4986
|
+
* Verify Device Secure Element signature
|
|
3540
4987
|
*/
|
|
3541
|
-
|
|
3542
|
-
|
|
4988
|
+
async verifyDeviceSEProof(signTarget, signature, deviceSE) {
|
|
4989
|
+
if (!deviceSE || !signTarget || !signature) {
|
|
4990
|
+
return { valid: false, error: "Missing Device SE context" };
|
|
4991
|
+
}
|
|
4992
|
+
let publicKey = deviceSE.publicKey;
|
|
4993
|
+
const registeredKey = this.deviceKeys.get(deviceSE.deviceId);
|
|
4994
|
+
if (registeredKey) {
|
|
4995
|
+
publicKey = registeredKey;
|
|
4996
|
+
}
|
|
4997
|
+
if (!publicKey || publicKey.length !== 32) {
|
|
4998
|
+
return {
|
|
4999
|
+
valid: false,
|
|
5000
|
+
error: "Invalid or unregistered device public key"
|
|
5001
|
+
};
|
|
5002
|
+
}
|
|
5003
|
+
try {
|
|
5004
|
+
const valid = nacl.sign.detached.verify(signTarget, signature, publicKey);
|
|
5005
|
+
if (!valid) {
|
|
5006
|
+
return { valid: false, error: "Device signature verification failed" };
|
|
5007
|
+
}
|
|
5008
|
+
return {
|
|
5009
|
+
valid: true,
|
|
5010
|
+
actorId: deviceSE.deviceId,
|
|
5011
|
+
metadata: { deviceId: deviceSE.deviceId, proofType: "DEVICE_SE" }
|
|
5012
|
+
};
|
|
5013
|
+
} catch (e) {
|
|
5014
|
+
const message = e instanceof Error ? e.message : "Unknown error";
|
|
5015
|
+
return {
|
|
5016
|
+
valid: false,
|
|
5017
|
+
error: `Signature verification error: ${message}`
|
|
5018
|
+
};
|
|
5019
|
+
}
|
|
3543
5020
|
}
|
|
3544
5021
|
/**
|
|
3545
|
-
*
|
|
3546
|
-
*
|
|
5022
|
+
* Registers a public key for a trusted device.
|
|
5023
|
+
* This key will be used for future `DEVICE_SE` proof verifications.
|
|
3547
5024
|
*
|
|
3548
|
-
* @
|
|
5025
|
+
* @param {string} deviceId - Unique identifier for the device
|
|
5026
|
+
* @param {Uint8Array} publicKey - 32-byte Ed25519 public key
|
|
5027
|
+
* @throws {Error} If the public key is not 32 bytes
|
|
3549
5028
|
*/
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
5029
|
+
registerDeviceKey(deviceId, publicKey) {
|
|
5030
|
+
if (publicKey.length !== 32) {
|
|
5031
|
+
throw new Error("Device public key must be 32 bytes (Ed25519)");
|
|
5032
|
+
}
|
|
5033
|
+
this.deviceKeys.set(deviceId, publicKey);
|
|
5034
|
+
this.logger.log(`Registered device key for ${deviceId}`);
|
|
3554
5035
|
}
|
|
3555
5036
|
/**
|
|
3556
|
-
*
|
|
3557
|
-
*
|
|
3558
|
-
* @private
|
|
3559
|
-
* @param {AxisSensor} sensor - The sensor to check
|
|
3560
|
-
* @returns {boolean} True if sensor is pre-decode
|
|
5037
|
+
* Unregister a device
|
|
3561
5038
|
*/
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
return phase === "PRE_DECODE" || (sensor.order ?? 999) < 40;
|
|
5039
|
+
unregisterDevice(deviceId) {
|
|
5040
|
+
return this.deviceKeys.delete(deviceId);
|
|
3565
5041
|
}
|
|
3566
5042
|
/**
|
|
3567
|
-
*
|
|
5043
|
+
* Registers a trusted mTLS certificate fingerprint and associates it with an actor.
|
|
3568
5044
|
*
|
|
3569
|
-
* @
|
|
3570
|
-
* @param {
|
|
3571
|
-
* @returns {boolean} True if sensor is post-decode
|
|
5045
|
+
* @param {string} fingerprint - SHA-256 fingerprint of the client certificate
|
|
5046
|
+
* @param {string} actorId - The actor to associate with this certificate
|
|
3572
5047
|
*/
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
5048
|
+
registerMTLSCert(fingerprint, actorId) {
|
|
5049
|
+
this.trustedCerts.set(fingerprint, { actorId, issuedAt: Date.now() });
|
|
5050
|
+
this.logger.log(`Registered mTLS cert ${fingerprint} for actor ${actorId}`);
|
|
3576
5051
|
}
|
|
3577
5052
|
/**
|
|
3578
|
-
*
|
|
3579
|
-
* Useful for diagnostics and monitoring.
|
|
3580
|
-
*
|
|
3581
|
-
* @returns {{preDecodeCount: number, postDecodeCount: number}}
|
|
5053
|
+
* Revoke an mTLS certificate
|
|
3582
5054
|
*/
|
|
3583
|
-
|
|
3584
|
-
return
|
|
3585
|
-
preDecodeCount: this.getPreDecodeSensors().length,
|
|
3586
|
-
postDecodeCount: this.getPostDecodeSensors().length
|
|
3587
|
-
};
|
|
5055
|
+
revokeMTLSCert(fingerprint) {
|
|
5056
|
+
return this.trustedCerts.delete(fingerprint);
|
|
3588
5057
|
}
|
|
3589
5058
|
/**
|
|
3590
|
-
*
|
|
3591
|
-
* Useful for testing.
|
|
3592
|
-
*
|
|
3593
|
-
* @internal
|
|
5059
|
+
* Calculate certificate fingerprint (SHA-256)
|
|
3594
5060
|
*/
|
|
3595
|
-
|
|
3596
|
-
|
|
5061
|
+
static calculateFingerprint(certPem) {
|
|
5062
|
+
const der = Buffer.from(
|
|
5063
|
+
certPem.replace(/-----BEGIN CERTIFICATE-----/, "").replace(/-----END CERTIFICATE-----/, "").replace(/\s/g, ""),
|
|
5064
|
+
"base64"
|
|
5065
|
+
);
|
|
5066
|
+
return crypto4.createHash("sha256").update(der).digest("hex");
|
|
3597
5067
|
}
|
|
3598
5068
|
};
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
],
|
|
5069
|
+
ProofVerificationService = __decorateClass([
|
|
5070
|
+
Injectable8()
|
|
5071
|
+
], ProofVerificationService);
|
|
5072
|
+
|
|
5073
|
+
// src/decorators/index.ts
|
|
5074
|
+
var decorators_exports = {};
|
|
5075
|
+
__export(decorators_exports, {
|
|
5076
|
+
AxisContext: () => AxisContext,
|
|
5077
|
+
AxisDemoPubkey: () => AxisDemoPubkey,
|
|
5078
|
+
AxisFrame: () => AxisFrame3,
|
|
5079
|
+
AxisIp: () => AxisIp,
|
|
5080
|
+
AxisRaw: () => AxisRaw,
|
|
5081
|
+
HANDLER_METADATA_KEY: () => HANDLER_METADATA_KEY,
|
|
5082
|
+
Handler: () => Handler,
|
|
5083
|
+
INTENT_BODY_KEY: () => INTENT_BODY_KEY,
|
|
5084
|
+
INTENT_METADATA_KEY: () => INTENT_METADATA_KEY,
|
|
5085
|
+
INTENT_ROUTES_KEY: () => INTENT_ROUTES_KEY,
|
|
5086
|
+
INTENT_SENSORS_KEY: () => INTENT_SENSORS_KEY,
|
|
5087
|
+
Intent: () => Intent,
|
|
5088
|
+
IntentBody: () => IntentBody,
|
|
5089
|
+
IntentSensors: () => IntentSensors,
|
|
5090
|
+
SENSOR_METADATA_KEY: () => SENSOR_METADATA_KEY,
|
|
5091
|
+
Sensor: () => Sensor,
|
|
5092
|
+
TLV_FIELDS_KEY: () => TLV_FIELDS_KEY,
|
|
5093
|
+
TLV_VALIDATORS_KEY: () => TLV_VALIDATORS_KEY,
|
|
5094
|
+
TlvEnum: () => TlvEnum,
|
|
5095
|
+
TlvField: () => TlvField,
|
|
5096
|
+
TlvMinLen: () => TlvMinLen,
|
|
5097
|
+
TlvRange: () => TlvRange,
|
|
5098
|
+
TlvUtf8Pattern: () => TlvUtf8Pattern,
|
|
5099
|
+
TlvValidate: () => TlvValidate,
|
|
5100
|
+
buildDtoDecoder: () => buildDtoDecoder,
|
|
5101
|
+
extractDtoSchema: () => extractDtoSchema
|
|
5102
|
+
});
|
|
5103
|
+
|
|
5104
|
+
// src/engine/index.ts
|
|
5105
|
+
var engine_exports = {};
|
|
5106
|
+
__export(engine_exports, {
|
|
5107
|
+
BAND: () => BAND,
|
|
5108
|
+
HandlerDiscoveryService: () => HandlerDiscoveryService,
|
|
5109
|
+
IntentRouter: () => IntentRouter,
|
|
5110
|
+
PRE_DECODE_BOUNDARY: () => PRE_DECODE_BOUNDARY,
|
|
5111
|
+
SensorDiscoveryService: () => SensorDiscoveryService,
|
|
5112
|
+
SensorRegistry: () => SensorRegistry,
|
|
5113
|
+
createObservation: () => createObservation,
|
|
5114
|
+
endStage: () => endStage,
|
|
5115
|
+
finalizeObservation: () => finalizeObservation,
|
|
5116
|
+
observation: () => observation_exports,
|
|
5117
|
+
recordSensor: () => recordSensor,
|
|
5118
|
+
startStage: () => startStage
|
|
5119
|
+
});
|
|
3602
5120
|
|
|
3603
5121
|
// src/engine/observation/index.ts
|
|
3604
5122
|
var observation_exports = {};
|
|
@@ -3983,7 +5501,7 @@ var AxisErrorZ = z2.object({
|
|
|
3983
5501
|
});
|
|
3984
5502
|
|
|
3985
5503
|
// src/schemas/body-profile.validator.ts
|
|
3986
|
-
import { Injectable as
|
|
5504
|
+
import { Injectable as Injectable9, Logger as Logger8 } from "@nestjs/common";
|
|
3987
5505
|
var BodyProfile2 = /* @__PURE__ */ ((BodyProfile3) => {
|
|
3988
5506
|
BodyProfile3[BodyProfile3["RAW"] = 0] = "RAW";
|
|
3989
5507
|
BodyProfile3[BodyProfile3["TLV_MAP"] = 1] = "TLV_MAP";
|
|
@@ -3993,7 +5511,7 @@ var BodyProfile2 = /* @__PURE__ */ ((BodyProfile3) => {
|
|
|
3993
5511
|
})(BodyProfile2 || {});
|
|
3994
5512
|
var BodyProfileValidator = class {
|
|
3995
5513
|
constructor() {
|
|
3996
|
-
this.logger = new
|
|
5514
|
+
this.logger = new Logger8(BodyProfileValidator.name);
|
|
3997
5515
|
}
|
|
3998
5516
|
/**
|
|
3999
5517
|
* Validate body matches declared profile
|
|
@@ -4109,12 +5627,13 @@ var BodyProfileValidator = class {
|
|
|
4109
5627
|
}
|
|
4110
5628
|
};
|
|
4111
5629
|
BodyProfileValidator = __decorateClass([
|
|
4112
|
-
|
|
5630
|
+
Injectable9()
|
|
4113
5631
|
], BodyProfileValidator);
|
|
4114
5632
|
|
|
4115
5633
|
// src/security/index.ts
|
|
4116
5634
|
var security_exports = {};
|
|
4117
5635
|
__export(security_exports, {
|
|
5636
|
+
AxisSensorChainService: () => AxisSensorChainService,
|
|
4118
5637
|
CAPABILITIES: () => CAPABILITIES,
|
|
4119
5638
|
INTENT_REQUIREMENTS: () => INTENT_REQUIREMENTS,
|
|
4120
5639
|
PROOF_CAPABILITIES: () => PROOF_CAPABILITIES,
|
|
@@ -4147,7 +5666,7 @@ __export(sensors_exports, {
|
|
|
4147
5666
|
});
|
|
4148
5667
|
|
|
4149
5668
|
// src/sensors/access-profile-resolver.sensor.ts
|
|
4150
|
-
import { Injectable as
|
|
5669
|
+
import { Injectable as Injectable10 } from "@nestjs/common";
|
|
4151
5670
|
var AccessProfileResolverSensor = class {
|
|
4152
5671
|
constructor() {
|
|
4153
5672
|
/** AxisSensor identifier */
|
|
@@ -4173,11 +5692,11 @@ var AccessProfileResolverSensor = class {
|
|
|
4173
5692
|
};
|
|
4174
5693
|
AccessProfileResolverSensor = __decorateClass([
|
|
4175
5694
|
Sensor(),
|
|
4176
|
-
|
|
5695
|
+
Injectable10()
|
|
4177
5696
|
], AccessProfileResolverSensor);
|
|
4178
5697
|
|
|
4179
5698
|
// src/sensors/body-budget.sensor.ts
|
|
4180
|
-
import { Injectable as
|
|
5699
|
+
import { Injectable as Injectable11 } from "@nestjs/common";
|
|
4181
5700
|
var BodyBudgetSensor = class {
|
|
4182
5701
|
constructor() {
|
|
4183
5702
|
/** AxisSensor identifier */
|
|
@@ -4251,14 +5770,14 @@ var BodyBudgetSensor = class {
|
|
|
4251
5770
|
};
|
|
4252
5771
|
BodyBudgetSensor = __decorateClass([
|
|
4253
5772
|
Sensor(),
|
|
4254
|
-
|
|
5773
|
+
Injectable11()
|
|
4255
5774
|
], BodyBudgetSensor);
|
|
4256
5775
|
|
|
4257
5776
|
// src/sensors/capability-enforcement.sensor.ts
|
|
4258
|
-
import { Injectable as
|
|
5777
|
+
import { Injectable as Injectable12, Logger as Logger9 } from "@nestjs/common";
|
|
4259
5778
|
var CapabilityEnforcementSensor = class {
|
|
4260
5779
|
constructor() {
|
|
4261
|
-
this.logger = new
|
|
5780
|
+
this.logger = new Logger9(CapabilityEnforcementSensor.name);
|
|
4262
5781
|
/** AxisSensor identifier for logging and registry */
|
|
4263
5782
|
this.name = "CapabilityEnforcementSensor";
|
|
4264
5783
|
/**
|
|
@@ -4352,11 +5871,11 @@ var CapabilityEnforcementSensor = class {
|
|
|
4352
5871
|
};
|
|
4353
5872
|
CapabilityEnforcementSensor = __decorateClass([
|
|
4354
5873
|
Sensor(),
|
|
4355
|
-
|
|
5874
|
+
Injectable12()
|
|
4356
5875
|
], CapabilityEnforcementSensor);
|
|
4357
5876
|
|
|
4358
5877
|
// src/sensors/chunk-hash.sensor.ts
|
|
4359
|
-
import { Injectable as
|
|
5878
|
+
import { Injectable as Injectable13 } from "@nestjs/common";
|
|
4360
5879
|
import { createHash as createHash7 } from "crypto";
|
|
4361
5880
|
var ChunkHashSensor = class {
|
|
4362
5881
|
constructor() {
|
|
@@ -4429,15 +5948,15 @@ var ChunkHashSensor = class {
|
|
|
4429
5948
|
};
|
|
4430
5949
|
ChunkHashSensor = __decorateClass([
|
|
4431
5950
|
Sensor(),
|
|
4432
|
-
|
|
5951
|
+
Injectable13()
|
|
4433
5952
|
], ChunkHashSensor);
|
|
4434
5953
|
|
|
4435
5954
|
// src/sensors/entropy.sensor.ts
|
|
4436
|
-
import { Injectable as
|
|
4437
|
-
import * as
|
|
5955
|
+
import { Injectable as Injectable14, Logger as Logger10 } from "@nestjs/common";
|
|
5956
|
+
import * as crypto5 from "crypto";
|
|
4438
5957
|
var EntropySensor = class {
|
|
4439
5958
|
constructor() {
|
|
4440
|
-
this.logger = new
|
|
5959
|
+
this.logger = new Logger10(EntropySensor.name);
|
|
4441
5960
|
/**
|
|
4442
5961
|
* Minimum acceptable entropy in bits per byte.
|
|
4443
5962
|
*
|
|
@@ -4602,19 +6121,19 @@ var EntropySensor = class {
|
|
|
4602
6121
|
* @returns {Uint8Array} Cryptographically secure random bytes
|
|
4603
6122
|
*/
|
|
4604
6123
|
static generateSecureRandom(length) {
|
|
4605
|
-
return new Uint8Array(
|
|
6124
|
+
return new Uint8Array(crypto5.randomBytes(length));
|
|
4606
6125
|
}
|
|
4607
6126
|
};
|
|
4608
6127
|
EntropySensor = __decorateClass([
|
|
4609
6128
|
Sensor(),
|
|
4610
|
-
|
|
6129
|
+
Injectable14()
|
|
4611
6130
|
], EntropySensor);
|
|
4612
6131
|
|
|
4613
6132
|
// src/sensors/execution-timeout.sensor.ts
|
|
4614
|
-
import { Injectable as
|
|
6133
|
+
import { Injectable as Injectable15, Logger as Logger11 } from "@nestjs/common";
|
|
4615
6134
|
var ExecutionTimeoutSensor = class {
|
|
4616
6135
|
constructor() {
|
|
4617
|
-
this.logger = new
|
|
6136
|
+
this.logger = new Logger11(ExecutionTimeoutSensor.name);
|
|
4618
6137
|
/** AxisSensor identifier */
|
|
4619
6138
|
this.name = "ExecutionTimeoutSensor";
|
|
4620
6139
|
/**
|
|
@@ -4692,11 +6211,11 @@ var ExecutionTimeoutSensor = class {
|
|
|
4692
6211
|
};
|
|
4693
6212
|
ExecutionTimeoutSensor = __decorateClass([
|
|
4694
6213
|
Sensor(),
|
|
4695
|
-
|
|
6214
|
+
Injectable15()
|
|
4696
6215
|
], ExecutionTimeoutSensor);
|
|
4697
6216
|
|
|
4698
6217
|
// src/sensors/frame-budget.sensor.ts
|
|
4699
|
-
import { Injectable as
|
|
6218
|
+
import { Injectable as Injectable16 } from "@nestjs/common";
|
|
4700
6219
|
var FrameBudgetSensor = class {
|
|
4701
6220
|
constructor(config) {
|
|
4702
6221
|
this.config = config;
|
|
@@ -4755,11 +6274,11 @@ var FrameBudgetSensor = class {
|
|
|
4755
6274
|
};
|
|
4756
6275
|
FrameBudgetSensor = __decorateClass([
|
|
4757
6276
|
Sensor({ phase: "PRE_DECODE" }),
|
|
4758
|
-
|
|
6277
|
+
Injectable16()
|
|
4759
6278
|
], FrameBudgetSensor);
|
|
4760
6279
|
|
|
4761
6280
|
// src/sensors/frame-header-sanity.sensor.ts
|
|
4762
|
-
import { Injectable as
|
|
6281
|
+
import { Injectable as Injectable17 } from "@nestjs/common";
|
|
4763
6282
|
var FrameHeaderSanitySensor = class {
|
|
4764
6283
|
constructor() {
|
|
4765
6284
|
this.name = "FrameHeaderSanitySensor";
|
|
@@ -4803,12 +6322,12 @@ var FrameHeaderSanitySensor = class {
|
|
|
4803
6322
|
}
|
|
4804
6323
|
};
|
|
4805
6324
|
FrameHeaderSanitySensor = __decorateClass([
|
|
4806
|
-
|
|
6325
|
+
Injectable17(),
|
|
4807
6326
|
Sensor({ phase: "PRE_DECODE" })
|
|
4808
6327
|
], FrameHeaderSanitySensor);
|
|
4809
6328
|
|
|
4810
6329
|
// src/sensors/header-tlv-limit.sensor.ts
|
|
4811
|
-
import { Injectable as
|
|
6330
|
+
import { Injectable as Injectable18 } from "@nestjs/common";
|
|
4812
6331
|
var HeaderTLVLimitSensor = class {
|
|
4813
6332
|
constructor() {
|
|
4814
6333
|
this.name = "HeaderTLVLimitSensor";
|
|
@@ -4840,12 +6359,12 @@ var HeaderTLVLimitSensor = class {
|
|
|
4840
6359
|
}
|
|
4841
6360
|
};
|
|
4842
6361
|
HeaderTLVLimitSensor = __decorateClass([
|
|
4843
|
-
|
|
6362
|
+
Injectable18(),
|
|
4844
6363
|
Sensor()
|
|
4845
6364
|
], HeaderTLVLimitSensor);
|
|
4846
6365
|
|
|
4847
6366
|
// src/sensors/intent-allowlist.sensor.ts
|
|
4848
|
-
import { Injectable as
|
|
6367
|
+
import { Injectable as Injectable19 } from "@nestjs/common";
|
|
4849
6368
|
var PUBLIC_INTENT_ALLOWLIST = [
|
|
4850
6369
|
"public.",
|
|
4851
6370
|
"schema.",
|
|
@@ -4880,12 +6399,12 @@ var IntentAllowlistSensor = class {
|
|
|
4880
6399
|
}
|
|
4881
6400
|
};
|
|
4882
6401
|
IntentAllowlistSensor = __decorateClass([
|
|
4883
|
-
|
|
6402
|
+
Injectable19(),
|
|
4884
6403
|
Sensor()
|
|
4885
6404
|
], IntentAllowlistSensor);
|
|
4886
6405
|
|
|
4887
6406
|
// src/sensors/intent-registry.sensor.ts
|
|
4888
|
-
import { Injectable as
|
|
6407
|
+
import { Injectable as Injectable20 } from "@nestjs/common";
|
|
4889
6408
|
var IntentRegistrySensor = class {
|
|
4890
6409
|
constructor(router) {
|
|
4891
6410
|
this.router = router;
|
|
@@ -4908,12 +6427,12 @@ var IntentRegistrySensor = class {
|
|
|
4908
6427
|
}
|
|
4909
6428
|
};
|
|
4910
6429
|
IntentRegistrySensor = __decorateClass([
|
|
4911
|
-
|
|
6430
|
+
Injectable20(),
|
|
4912
6431
|
Sensor({ phase: "POST_DECODE" })
|
|
4913
6432
|
], IntentRegistrySensor);
|
|
4914
6433
|
|
|
4915
6434
|
// src/sensors/proof-presence.sensor.ts
|
|
4916
|
-
import { Injectable as
|
|
6435
|
+
import { Injectable as Injectable21 } from "@nestjs/common";
|
|
4917
6436
|
var ProofPresenceSensor = class {
|
|
4918
6437
|
constructor() {
|
|
4919
6438
|
this.name = "ProofPresenceSensor";
|
|
@@ -4961,11 +6480,11 @@ var ProofPresenceSensor = class {
|
|
|
4961
6480
|
};
|
|
4962
6481
|
ProofPresenceSensor = __decorateClass([
|
|
4963
6482
|
Sensor(),
|
|
4964
|
-
|
|
6483
|
+
Injectable21()
|
|
4965
6484
|
], ProofPresenceSensor);
|
|
4966
6485
|
|
|
4967
6486
|
// src/sensors/protocol-strict.sensor.ts
|
|
4968
|
-
import { Injectable as
|
|
6487
|
+
import { Injectable as Injectable22, Logger as Logger12 } from "@nestjs/common";
|
|
4969
6488
|
var VALID_FLAGS = [
|
|
4970
6489
|
0,
|
|
4971
6490
|
// No flags
|
|
@@ -4983,7 +6502,7 @@ var VALID_FLAGS = [
|
|
|
4983
6502
|
var ProtocolStrictSensor = class {
|
|
4984
6503
|
constructor(config) {
|
|
4985
6504
|
this.config = config;
|
|
4986
|
-
this.logger = new
|
|
6505
|
+
this.logger = new Logger12(ProtocolStrictSensor.name);
|
|
4987
6506
|
/** Sensor identifier for logging and registry */
|
|
4988
6507
|
this.name = "ProtocolStrictSensor";
|
|
4989
6508
|
/**
|
|
@@ -5236,11 +6755,11 @@ var ProtocolStrictSensor = class {
|
|
|
5236
6755
|
};
|
|
5237
6756
|
ProtocolStrictSensor = __decorateClass([
|
|
5238
6757
|
Sensor({ phase: "PRE_DECODE" }),
|
|
5239
|
-
|
|
6758
|
+
Injectable22()
|
|
5240
6759
|
], ProtocolStrictSensor);
|
|
5241
6760
|
|
|
5242
6761
|
// src/sensors/receipt-policy.sensor.ts
|
|
5243
|
-
import { Injectable as
|
|
6762
|
+
import { Injectable as Injectable23 } from "@nestjs/common";
|
|
5244
6763
|
var ReceiptPolicySensor = class {
|
|
5245
6764
|
constructor() {
|
|
5246
6765
|
this.name = "ReceiptPolicySensor";
|
|
@@ -5254,12 +6773,12 @@ var ReceiptPolicySensor = class {
|
|
|
5254
6773
|
}
|
|
5255
6774
|
};
|
|
5256
6775
|
ReceiptPolicySensor = __decorateClass([
|
|
5257
|
-
|
|
6776
|
+
Injectable23(),
|
|
5258
6777
|
Sensor()
|
|
5259
6778
|
], ReceiptPolicySensor);
|
|
5260
6779
|
|
|
5261
6780
|
// src/sensors/schema-validation.sensor.ts
|
|
5262
|
-
import { Injectable as
|
|
6781
|
+
import { Injectable as Injectable24 } from "@nestjs/common";
|
|
5263
6782
|
function readU64be(b) {
|
|
5264
6783
|
if (b.length !== 8)
|
|
5265
6784
|
throw new AxisError("SCHEMA_TYPE_MISMATCH", "u64 must be 8 bytes", 400);
|
|
@@ -5434,11 +6953,11 @@ var SchemaValidationSensor = class {
|
|
|
5434
6953
|
};
|
|
5435
6954
|
SchemaValidationSensor = __decorateClass([
|
|
5436
6955
|
Sensor(),
|
|
5437
|
-
|
|
6956
|
+
Injectable24()
|
|
5438
6957
|
], SchemaValidationSensor);
|
|
5439
6958
|
|
|
5440
6959
|
// src/sensors/stream-scope.sensor.ts
|
|
5441
|
-
import { Injectable as
|
|
6960
|
+
import { Injectable as Injectable25 } from "@nestjs/common";
|
|
5442
6961
|
var StreamScopeSensor = class {
|
|
5443
6962
|
constructor() {
|
|
5444
6963
|
/** Sensor identifier */
|
|
@@ -5484,11 +7003,11 @@ var StreamScopeSensor = class {
|
|
|
5484
7003
|
};
|
|
5485
7004
|
StreamScopeSensor = __decorateClass([
|
|
5486
7005
|
Sensor(),
|
|
5487
|
-
|
|
7006
|
+
Injectable25()
|
|
5488
7007
|
], StreamScopeSensor);
|
|
5489
7008
|
|
|
5490
7009
|
// src/sensors/tlv-parse.sensor.ts
|
|
5491
|
-
import { Injectable as
|
|
7010
|
+
import { Injectable as Injectable26 } from "@nestjs/common";
|
|
5492
7011
|
var TLVParseSensor = class {
|
|
5493
7012
|
constructor() {
|
|
5494
7013
|
this.name = "TLVParseSensor";
|
|
@@ -5590,11 +7109,11 @@ var TLVParseSensor = class {
|
|
|
5590
7109
|
};
|
|
5591
7110
|
TLVParseSensor = __decorateClass([
|
|
5592
7111
|
Sensor(),
|
|
5593
|
-
|
|
7112
|
+
Injectable26()
|
|
5594
7113
|
], TLVParseSensor);
|
|
5595
7114
|
|
|
5596
7115
|
// src/sensors/varint-hardening.sensor.ts
|
|
5597
|
-
import { Injectable as
|
|
7116
|
+
import { Injectable as Injectable27 } from "@nestjs/common";
|
|
5598
7117
|
var VarintHardeningSensor = class {
|
|
5599
7118
|
constructor() {
|
|
5600
7119
|
/** Sensor identifier */
|
|
@@ -5657,7 +7176,7 @@ var VarintHardeningSensor = class {
|
|
|
5657
7176
|
};
|
|
5658
7177
|
VarintHardeningSensor = __decorateClass([
|
|
5659
7178
|
Sensor({ phase: "PRE_DECODE" }),
|
|
5660
|
-
|
|
7179
|
+
Injectable27()
|
|
5661
7180
|
], VarintHardeningSensor);
|
|
5662
7181
|
|
|
5663
7182
|
// src/utils/index.ts
|
|
@@ -5728,16 +7247,26 @@ export {
|
|
|
5728
7247
|
AXIS_UPLOAD_SESSION_STORE,
|
|
5729
7248
|
AXIS_VERSION,
|
|
5730
7249
|
ats1_exports as Ats1Codec,
|
|
7250
|
+
AxisContext,
|
|
7251
|
+
AxisDemoPubkey,
|
|
7252
|
+
AxisError,
|
|
5731
7253
|
AxisFilesDownloadHandler,
|
|
5732
7254
|
AxisFilesFinalizeHandler,
|
|
5733
7255
|
AxisFrameZ,
|
|
5734
7256
|
AxisIdDto,
|
|
7257
|
+
AxisIp,
|
|
5735
7258
|
T as AxisPacketTags,
|
|
5736
7259
|
AxisPartialType,
|
|
7260
|
+
AxisRaw,
|
|
5737
7261
|
AxisResponseDto,
|
|
7262
|
+
AxisSensorChainService,
|
|
5738
7263
|
AxisTlvDto,
|
|
7264
|
+
BAND,
|
|
5739
7265
|
BodyProfile,
|
|
5740
7266
|
CAPABILITIES,
|
|
7267
|
+
CCE_ERROR,
|
|
7268
|
+
CCE_PROTOCOL_VERSION,
|
|
7269
|
+
CceError,
|
|
5741
7270
|
ContractViolationError,
|
|
5742
7271
|
DEFAULT_CONTRACTS,
|
|
5743
7272
|
DEFAULT_TIMEOUT,
|
|
@@ -5753,7 +7282,10 @@ export {
|
|
|
5753
7282
|
FLAG_CHAIN_REQ,
|
|
5754
7283
|
FLAG_HAS_WITNESS,
|
|
5755
7284
|
HANDLER_METADATA_KEY,
|
|
7285
|
+
HANDLER_SENSORS_KEY,
|
|
5756
7286
|
Handler,
|
|
7287
|
+
HandlerDiscoveryService,
|
|
7288
|
+
HandlerSensors,
|
|
5757
7289
|
INTENT_BODY_KEY,
|
|
5758
7290
|
INTENT_METADATA_KEY,
|
|
5759
7291
|
INTENT_REQUIREMENTS,
|
|
@@ -5780,6 +7312,7 @@ export {
|
|
|
5780
7312
|
NCERT_PUB,
|
|
5781
7313
|
NCERT_SCOPE,
|
|
5782
7314
|
NCERT_SIG,
|
|
7315
|
+
PRE_DECODE_BOUNDARY,
|
|
5783
7316
|
PROOF_CAPABILITIES,
|
|
5784
7317
|
PROOF_CAPSULE,
|
|
5785
7318
|
PROOF_JWT,
|
|
@@ -5794,11 +7327,15 @@ export {
|
|
|
5794
7327
|
RESPONSE_TAG_UPDATED_AT,
|
|
5795
7328
|
RESPONSE_TAG_UPDATED_BY,
|
|
5796
7329
|
RiskDecision,
|
|
7330
|
+
SENSOR_METADATA_KEY,
|
|
5797
7331
|
Schema2002_PasskeyLoginOptionsRes,
|
|
5798
7332
|
Schema2011_PasskeyLoginVerifyReq,
|
|
5799
7333
|
Schema2012_PasskeyLoginVerifyRes,
|
|
5800
7334
|
Schema2021_PasskeyRegisterOptionsReq,
|
|
7335
|
+
Sensor,
|
|
5801
7336
|
SensorDecisions,
|
|
7337
|
+
SensorDiscoveryService,
|
|
7338
|
+
SensorRegistry,
|
|
5802
7339
|
TLV,
|
|
5803
7340
|
TLV_ACTOR_ID,
|
|
5804
7341
|
TLV_AUD,
|
|
@@ -5856,10 +7393,12 @@ export {
|
|
|
5856
7393
|
canonicalJson,
|
|
5857
7394
|
canonicalJsonExcluding,
|
|
5858
7395
|
canonicalizeObservation,
|
|
7396
|
+
cce_exports as cce,
|
|
5859
7397
|
classifyIntent,
|
|
5860
7398
|
computeReceiptHash,
|
|
5861
7399
|
computeSignaturePayload,
|
|
5862
7400
|
core_exports as core,
|
|
7401
|
+
createObservation,
|
|
5863
7402
|
crypto_exports as crypto,
|
|
5864
7403
|
decodeArray,
|
|
5865
7404
|
decodeAxis1Frame,
|
|
@@ -5876,8 +7415,11 @@ export {
|
|
|
5876
7415
|
encodeQueueMessage,
|
|
5877
7416
|
encodeTLVs,
|
|
5878
7417
|
encodeVarint,
|
|
7418
|
+
endStage,
|
|
5879
7419
|
engine_exports as engine,
|
|
7420
|
+
executeCcePipeline,
|
|
5880
7421
|
extractDtoSchema,
|
|
7422
|
+
finalizeObservation,
|
|
5881
7423
|
generateEd25519KeyPair,
|
|
5882
7424
|
getSignTarget,
|
|
5883
7425
|
hasScope,
|
|
@@ -5896,14 +7438,16 @@ export {
|
|
|
5896
7438
|
parseAutoClaimEntries,
|
|
5897
7439
|
parseScope,
|
|
5898
7440
|
parseStreamEntries,
|
|
7441
|
+
recordSensor,
|
|
5899
7442
|
resolveTimeout,
|
|
5900
7443
|
schemas_exports as schemas,
|
|
5901
7444
|
security_exports as security,
|
|
5902
7445
|
sensitivityName,
|
|
5903
7446
|
sensors_exports as sensors,
|
|
5904
|
-
sha256,
|
|
7447
|
+
sha2564 as sha256,
|
|
5905
7448
|
signFrame,
|
|
5906
7449
|
stableJsonStringify,
|
|
7450
|
+
startStage,
|
|
5907
7451
|
tlv,
|
|
5908
7452
|
u64be,
|
|
5909
7453
|
unpackPasskeyLoginOptionsReq,
|