@nextera.one/axis-server-sdk 2.2.8 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{index-CZ3RXsBC.d.mts → index-Bng8utj8.d.mts} +8 -4
- package/dist/{index-DEh3s2yx.d.ts → index-DJbM2lNM.d.ts} +8 -4
- package/dist/index.d.mts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.js +499 -467
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +499 -467
- package/dist/index.mjs.map +1 -1
- package/dist/sensors/index.d.mts +3 -3
- package/dist/sensors/index.d.ts +3 -3
- package/dist/sensors/index.js +497 -467
- package/dist/sensors/index.js.map +1 -1
- package/dist/sensors/index.mjs +497 -467
- package/dist/sensors/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -244,6 +244,16 @@ function AxisPublic() {
|
|
|
244
244
|
return target;
|
|
245
245
|
};
|
|
246
246
|
}
|
|
247
|
+
function AxisAuthorized() {
|
|
248
|
+
return (target, propertyKey, descriptor) => {
|
|
249
|
+
if (descriptor) {
|
|
250
|
+
Reflect.defineMetadata(AXIS_AUTHORIZED_KEY, true, target, propertyKey);
|
|
251
|
+
return descriptor;
|
|
252
|
+
}
|
|
253
|
+
Reflect.defineMetadata(AXIS_AUTHORIZED_KEY, true, target);
|
|
254
|
+
return target;
|
|
255
|
+
};
|
|
256
|
+
}
|
|
247
257
|
function AxisAnonymous() {
|
|
248
258
|
return (target, propertyKey, descriptor) => {
|
|
249
259
|
if (descriptor) {
|
|
@@ -260,7 +270,7 @@ function AxisRateLimit(config) {
|
|
|
260
270
|
return descriptor;
|
|
261
271
|
};
|
|
262
272
|
}
|
|
263
|
-
var AXIS_META_KEY, SENSITIVITY_METADATA_KEY, CONTRACT_METADATA_KEY, REQUIRED_PROOF_METADATA_KEY, AXIS_PUBLIC_KEY, AXIS_ANONYMOUS_KEY, AXIS_RATE_LIMIT_KEY;
|
|
273
|
+
var AXIS_META_KEY, SENSITIVITY_METADATA_KEY, CONTRACT_METADATA_KEY, REQUIRED_PROOF_METADATA_KEY, AXIS_PUBLIC_KEY, AXIS_ANONYMOUS_KEY, AXIS_AUTHORIZED_KEY, AXIS_RATE_LIMIT_KEY;
|
|
264
274
|
var init_intent_policy_decorator = __esm({
|
|
265
275
|
"src/decorators/intent-policy.decorator.ts"() {
|
|
266
276
|
AXIS_META_KEY = "axis:axis";
|
|
@@ -269,6 +279,7 @@ var init_intent_policy_decorator = __esm({
|
|
|
269
279
|
REQUIRED_PROOF_METADATA_KEY = "axis:required_proof";
|
|
270
280
|
AXIS_PUBLIC_KEY = "axis:public";
|
|
271
281
|
AXIS_ANONYMOUS_KEY = "axis:anonymous";
|
|
282
|
+
AXIS_AUTHORIZED_KEY = "axis:authorized";
|
|
272
283
|
AXIS_RATE_LIMIT_KEY = "axis:rateLimit";
|
|
273
284
|
}
|
|
274
285
|
});
|
|
@@ -1471,199 +1482,464 @@ var init_axis_chain_executor = __esm({
|
|
|
1471
1482
|
}
|
|
1472
1483
|
});
|
|
1473
1484
|
|
|
1474
|
-
// src/
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
CCE_PROTOCOL_VERSION = "cce-v1";
|
|
1479
|
-
CCE_DERIVATION = {
|
|
1480
|
-
/** Request execution context */
|
|
1481
|
-
REQUEST: "axis:cce:req:v1",
|
|
1482
|
-
/** Response execution context */
|
|
1483
|
-
RESPONSE: "axis:cce:resp:v1",
|
|
1484
|
-
/** Witness binding context */
|
|
1485
|
-
WITNESS: "axis:cce:witness:v1"
|
|
1486
|
-
};
|
|
1487
|
-
CCE_AES_KEY_BYTES = 32;
|
|
1488
|
-
CCE_IV_BYTES = 12;
|
|
1489
|
-
CCE_NONCE_BYTES = 32;
|
|
1490
|
-
CCE_ERROR = {
|
|
1491
|
-
// Envelope errors
|
|
1492
|
-
INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
|
|
1493
|
-
UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
|
|
1494
|
-
MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
|
|
1495
|
-
MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
|
|
1496
|
-
// Signature errors
|
|
1497
|
-
CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
|
|
1498
|
-
CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
|
|
1499
|
-
// Capsule errors
|
|
1500
|
-
CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
|
|
1501
|
-
CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
|
|
1502
|
-
CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
|
|
1503
|
-
CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
|
|
1504
|
-
CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
|
|
1505
|
-
CAPSULE_NOT_VERIFIED: "CCE_CAPSULE_NOT_VERIFIED",
|
|
1506
|
-
// Binding errors
|
|
1507
|
-
AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
|
|
1508
|
-
INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
|
|
1509
|
-
TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
|
|
1510
|
-
TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
|
|
1511
|
-
// Replay / nonce errors
|
|
1512
|
-
REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
|
|
1513
|
-
NONCE_REUSED: "CCE_NONCE_REUSED",
|
|
1514
|
-
// Decryption errors
|
|
1515
|
-
DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
|
|
1516
|
-
KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
|
|
1517
|
-
AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
|
|
1518
|
-
PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
|
|
1519
|
-
// Schema / validation errors
|
|
1520
|
-
PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
|
|
1521
|
-
INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
|
|
1522
|
-
// Policy errors
|
|
1523
|
-
POLICY_DENIED: "CCE_POLICY_DENIED",
|
|
1524
|
-
CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
|
|
1525
|
-
// Handler errors
|
|
1526
|
-
HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
|
|
1527
|
-
HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
|
|
1528
|
-
HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
|
|
1529
|
-
// Response errors
|
|
1530
|
-
RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
|
|
1531
|
-
};
|
|
1532
|
-
CceError = class extends Error {
|
|
1533
|
-
constructor(code, message, metadata) {
|
|
1534
|
-
super(`[${code}] ${message}`);
|
|
1535
|
-
this.code = code;
|
|
1536
|
-
this.metadata = metadata;
|
|
1537
|
-
this.name = "CceError";
|
|
1538
|
-
}
|
|
1539
|
-
/** Whether this error is safe to expose to the client */
|
|
1540
|
-
get clientSafe() {
|
|
1541
|
-
const internal = [
|
|
1542
|
-
CCE_ERROR.DECRYPTION_FAILED,
|
|
1543
|
-
CCE_ERROR.KEY_UNWRAP_FAILED,
|
|
1544
|
-
CCE_ERROR.AEAD_TAG_MISMATCH,
|
|
1545
|
-
CCE_ERROR.HANDLER_EXECUTION_FAILED,
|
|
1546
|
-
CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
|
|
1547
|
-
];
|
|
1548
|
-
return !internal.includes(this.code);
|
|
1549
|
-
}
|
|
1550
|
-
/** Get client-safe representation */
|
|
1551
|
-
toClientError() {
|
|
1552
|
-
if (this.clientSafe) {
|
|
1553
|
-
return { code: this.code, message: this.message };
|
|
1554
|
-
}
|
|
1555
|
-
return {
|
|
1556
|
-
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
1557
|
-
message: "Request processing failed"
|
|
1558
|
-
};
|
|
1559
|
-
}
|
|
1560
|
-
};
|
|
1485
|
+
// src/security/scopes.ts
|
|
1486
|
+
function hasScope(scopes, required) {
|
|
1487
|
+
if (!Array.isArray(scopes) || scopes.length === 0) {
|
|
1488
|
+
return false;
|
|
1561
1489
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
// src/cce/cce-derivation.service.ts
|
|
1565
|
-
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
1566
|
-
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
1567
|
-
import { sha256 } from "@noble/hashes/sha2.js";
|
|
1568
|
-
function buildSalt(capsuleId, capsuleNonce, requestNonce) {
|
|
1569
|
-
const encoder = new TextEncoder();
|
|
1570
|
-
const data = encoder.encode(
|
|
1571
|
-
capsuleId + "|" + capsuleNonce + "|" + requestNonce
|
|
1572
|
-
);
|
|
1573
|
-
return sha256(data);
|
|
1574
|
-
}
|
|
1575
|
-
function buildInfo(contextPrefix, capsule, extraNonce) {
|
|
1576
|
-
const encoder = new TextEncoder();
|
|
1577
|
-
const parts = [
|
|
1578
|
-
contextPrefix,
|
|
1579
|
-
capsule.sub,
|
|
1580
|
-
capsule.kid,
|
|
1581
|
-
capsule.intent,
|
|
1582
|
-
capsule.aud,
|
|
1583
|
-
String(capsule.tps_from),
|
|
1584
|
-
String(capsule.tps_to),
|
|
1585
|
-
capsule.policy_hash ?? "",
|
|
1586
|
-
capsule.ver
|
|
1587
|
-
];
|
|
1588
|
-
if (extraNonce) {
|
|
1589
|
-
parts.push(extraNonce);
|
|
1490
|
+
if (scopes.includes(required)) {
|
|
1491
|
+
return true;
|
|
1590
1492
|
}
|
|
1591
|
-
|
|
1493
|
+
const [resource, id] = required.split(":");
|
|
1494
|
+
if (resource && id) {
|
|
1495
|
+
const wildcard = `${resource}:*`;
|
|
1496
|
+
if (scopes.includes(wildcard)) {
|
|
1497
|
+
return true;
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return false;
|
|
1592
1501
|
}
|
|
1593
|
-
function
|
|
1594
|
-
const
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
input.capsule.capsule_nonce,
|
|
1598
|
-
input.requestNonce
|
|
1599
|
-
);
|
|
1600
|
-
const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
|
|
1601
|
-
return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
1502
|
+
function parseScope(scope) {
|
|
1503
|
+
const parts = scope.split(":");
|
|
1504
|
+
if (parts.length !== 2) return null;
|
|
1505
|
+
return { resource: parts[0], id: parts[1] };
|
|
1602
1506
|
}
|
|
1603
|
-
function
|
|
1604
|
-
const
|
|
1605
|
-
|
|
1606
|
-
executionKey.fill(0);
|
|
1607
|
-
return {
|
|
1608
|
-
execution_key_hash: keyHash,
|
|
1609
|
-
request_id: requestId,
|
|
1610
|
-
capsule_id: input.capsule.capsule_id,
|
|
1611
|
-
sub: input.capsule.sub,
|
|
1612
|
-
kid: input.capsule.kid,
|
|
1613
|
-
intent: input.capsule.intent,
|
|
1614
|
-
aud: input.capsule.aud,
|
|
1615
|
-
tps_from: input.capsule.tps_from,
|
|
1616
|
-
tps_to: input.capsule.tps_to,
|
|
1617
|
-
policy_hash: input.capsule.policy_hash,
|
|
1618
|
-
derived_at: Math.floor(Date.now() / 1e3),
|
|
1619
|
-
valid: true
|
|
1620
|
-
};
|
|
1507
|
+
function canAccessResource(scopes, resourceType, resourceId) {
|
|
1508
|
+
const required = `${resourceType}:${resourceId}`;
|
|
1509
|
+
return hasScope(scopes, required);
|
|
1621
1510
|
}
|
|
1622
|
-
var
|
|
1623
|
-
"src/
|
|
1624
|
-
init_cce_types();
|
|
1511
|
+
var init_scopes = __esm({
|
|
1512
|
+
"src/security/scopes.ts"() {
|
|
1625
1513
|
}
|
|
1626
1514
|
});
|
|
1627
1515
|
|
|
1628
|
-
// src/
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
function aesGcmEncrypt(key, plaintext, aad) {
|
|
1633
|
-
if (key.length !== CCE_AES_KEY_BYTES) {
|
|
1634
|
-
throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
|
|
1635
|
-
}
|
|
1636
|
-
const iv = randomBytes(CCE_IV_BYTES);
|
|
1637
|
-
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
1638
|
-
if (aad) {
|
|
1639
|
-
cipher.setAAD(aad);
|
|
1516
|
+
// src/security/inline-capsule.ts
|
|
1517
|
+
function normalizeInlineCapsule(input) {
|
|
1518
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
1519
|
+
return null;
|
|
1640
1520
|
}
|
|
1641
|
-
const
|
|
1642
|
-
const
|
|
1521
|
+
const raw = input;
|
|
1522
|
+
const scopes = normalizeStringList(raw.scopes ?? raw.scope);
|
|
1643
1523
|
return {
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1524
|
+
id: normalizeScalar(raw.id),
|
|
1525
|
+
actorId: normalizeScalar(raw.actorId),
|
|
1526
|
+
intents: normalizeStringList(raw.intents),
|
|
1527
|
+
issuedAt: normalizeTimestamp(raw.issuedAt ?? raw.iat),
|
|
1528
|
+
expiresAt: normalizeTimestamp(raw.expiresAt ?? raw.exp),
|
|
1529
|
+
realm: normalizeScalar(raw.realm),
|
|
1530
|
+
node: normalizeScalar(raw.node),
|
|
1531
|
+
scopes,
|
|
1532
|
+
raw
|
|
1647
1533
|
};
|
|
1648
1534
|
}
|
|
1649
|
-
function
|
|
1650
|
-
|
|
1535
|
+
function inlineCapsuleAllowsIntent(capsule, intent) {
|
|
1536
|
+
if (!capsule.intents || capsule.intents.length === 0) {
|
|
1537
|
+
return false;
|
|
1538
|
+
}
|
|
1539
|
+
for (const pattern of capsule.intents) {
|
|
1540
|
+
if (pattern === "*" || pattern === intent) {
|
|
1541
|
+
return true;
|
|
1542
|
+
}
|
|
1543
|
+
if (pattern.endsWith(".*")) {
|
|
1544
|
+
const prefix = pattern.slice(0, -1);
|
|
1545
|
+
if (intent.startsWith(prefix)) {
|
|
1546
|
+
return true;
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
return false;
|
|
1651
1551
|
}
|
|
1652
|
-
function
|
|
1653
|
-
|
|
1552
|
+
function isInlineCapsuleExpired(capsule, clockSkewMs = 3e4) {
|
|
1553
|
+
if (capsule.expiresAt === void 0) {
|
|
1554
|
+
return false;
|
|
1555
|
+
}
|
|
1556
|
+
return BigInt(Date.now()) > capsule.expiresAt + BigInt(clockSkewMs);
|
|
1654
1557
|
}
|
|
1655
|
-
function
|
|
1656
|
-
return
|
|
1558
|
+
function resolvePolicyScopes(scopes, context) {
|
|
1559
|
+
return scopes.map(
|
|
1560
|
+
(scope) => scope.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
|
|
1561
|
+
const resolved = resolveTemplateExpression(expression.trim(), context);
|
|
1562
|
+
if (resolved === void 0 || resolved === null || resolved === "") {
|
|
1563
|
+
throw new Error(`CAPSULE_SCOPE_TEMPLATE_UNRESOLVED:${expression}`);
|
|
1564
|
+
}
|
|
1565
|
+
return String(resolved);
|
|
1566
|
+
})
|
|
1567
|
+
);
|
|
1657
1568
|
}
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1569
|
+
function inlineCapsuleSatisfiesScopes(capsule, requiredScopes, mode = "all") {
|
|
1570
|
+
if (!capsule.scopes || capsule.scopes.length === 0) {
|
|
1571
|
+
return false;
|
|
1661
1572
|
}
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1573
|
+
if (mode === "any") {
|
|
1574
|
+
return requiredScopes.some((scope) => hasScope(capsule.scopes, scope));
|
|
1575
|
+
}
|
|
1576
|
+
return requiredScopes.every((scope) => hasScope(capsule.scopes, scope));
|
|
1577
|
+
}
|
|
1578
|
+
function resolveTemplateExpression(expression, context) {
|
|
1579
|
+
if (expression === "intent") {
|
|
1580
|
+
return context.intent;
|
|
1581
|
+
}
|
|
1582
|
+
if (expression === "actorId") {
|
|
1583
|
+
return context.actorId;
|
|
1584
|
+
}
|
|
1585
|
+
if (expression === "chainId") {
|
|
1586
|
+
return context.chainId;
|
|
1587
|
+
}
|
|
1588
|
+
if (expression === "stepId") {
|
|
1589
|
+
return context.stepId;
|
|
1590
|
+
}
|
|
1591
|
+
if (expression.startsWith("body.")) {
|
|
1592
|
+
return getNestedValue(context.body, expression.slice(5));
|
|
1593
|
+
}
|
|
1594
|
+
return void 0;
|
|
1595
|
+
}
|
|
1596
|
+
function getNestedValue(value, path2) {
|
|
1597
|
+
if (!value || typeof value !== "object") {
|
|
1598
|
+
return void 0;
|
|
1599
|
+
}
|
|
1600
|
+
return path2.split(".").reduce((current, segment) => {
|
|
1601
|
+
if (!current || typeof current !== "object") {
|
|
1602
|
+
return void 0;
|
|
1603
|
+
}
|
|
1604
|
+
return current[segment];
|
|
1605
|
+
}, value);
|
|
1606
|
+
}
|
|
1607
|
+
function normalizeScalar(value) {
|
|
1608
|
+
if (typeof value === "string") {
|
|
1609
|
+
return value;
|
|
1610
|
+
}
|
|
1611
|
+
if (value instanceof Uint8Array) {
|
|
1612
|
+
return Buffer.from(value).toString("hex");
|
|
1613
|
+
}
|
|
1614
|
+
return void 0;
|
|
1615
|
+
}
|
|
1616
|
+
function normalizeStringList(value) {
|
|
1617
|
+
if (!value) {
|
|
1618
|
+
return void 0;
|
|
1619
|
+
}
|
|
1620
|
+
const list = Array.isArray(value) ? value : [value];
|
|
1621
|
+
const normalized = list.map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => !!entry && entry.trim().length > 0);
|
|
1622
|
+
return normalized.length > 0 ? Array.from(new Set(normalized)) : void 0;
|
|
1623
|
+
}
|
|
1624
|
+
function normalizeTimestamp(value) {
|
|
1625
|
+
if (typeof value === "bigint") {
|
|
1626
|
+
return value;
|
|
1627
|
+
}
|
|
1628
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1629
|
+
return BigInt(Math.trunc(value));
|
|
1630
|
+
}
|
|
1631
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
1632
|
+
try {
|
|
1633
|
+
return BigInt(value);
|
|
1634
|
+
} catch {
|
|
1635
|
+
return void 0;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
return void 0;
|
|
1639
|
+
}
|
|
1640
|
+
var init_inline_capsule = __esm({
|
|
1641
|
+
"src/security/inline-capsule.ts"() {
|
|
1642
|
+
init_scopes();
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
|
|
1646
|
+
// src/sensor/axis-sensor.ts
|
|
1647
|
+
function normalizeSensorDecision(sensorDecision) {
|
|
1648
|
+
if ("action" in sensorDecision) {
|
|
1649
|
+
switch (sensorDecision.action) {
|
|
1650
|
+
case "ALLOW":
|
|
1651
|
+
return {
|
|
1652
|
+
allow: true,
|
|
1653
|
+
riskScore: 0,
|
|
1654
|
+
reasons: [],
|
|
1655
|
+
meta: sensorDecision.meta
|
|
1656
|
+
};
|
|
1657
|
+
case "DENY":
|
|
1658
|
+
return {
|
|
1659
|
+
allow: false,
|
|
1660
|
+
riskScore: 100,
|
|
1661
|
+
reasons: [sensorDecision.code, sensorDecision.reason].filter(
|
|
1662
|
+
Boolean
|
|
1663
|
+
),
|
|
1664
|
+
meta: sensorDecision.meta,
|
|
1665
|
+
retryAfterMs: sensorDecision.retryAfterMs
|
|
1666
|
+
};
|
|
1667
|
+
case "THROTTLE":
|
|
1668
|
+
return {
|
|
1669
|
+
allow: false,
|
|
1670
|
+
riskScore: 50,
|
|
1671
|
+
reasons: ["RATE_LIMIT"],
|
|
1672
|
+
retryAfterMs: sensorDecision.retryAfterMs,
|
|
1673
|
+
meta: sensorDecision.meta
|
|
1674
|
+
};
|
|
1675
|
+
case "FLAG":
|
|
1676
|
+
return {
|
|
1677
|
+
allow: true,
|
|
1678
|
+
riskScore: sensorDecision.scoreDelta,
|
|
1679
|
+
reasons: sensorDecision.reasons,
|
|
1680
|
+
meta: sensorDecision.meta
|
|
1681
|
+
};
|
|
1682
|
+
}
|
|
1683
|
+
}
|
|
1684
|
+
return {
|
|
1685
|
+
allow: sensorDecision.allow,
|
|
1686
|
+
riskScore: sensorDecision.riskScore,
|
|
1687
|
+
reasons: sensorDecision.reasons,
|
|
1688
|
+
tags: sensorDecision.tags,
|
|
1689
|
+
meta: sensorDecision.meta,
|
|
1690
|
+
tighten: sensorDecision.tighten,
|
|
1691
|
+
retryAfterMs: sensorDecision.retryAfterMs
|
|
1692
|
+
};
|
|
1693
|
+
}
|
|
1694
|
+
var Decision, SensorDecisions;
|
|
1695
|
+
var init_axis_sensor = __esm({
|
|
1696
|
+
"src/sensor/axis-sensor.ts"() {
|
|
1697
|
+
Decision = /* @__PURE__ */ ((Decision2) => {
|
|
1698
|
+
Decision2["ALLOW"] = "ALLOW";
|
|
1699
|
+
Decision2["DENY"] = "DENY";
|
|
1700
|
+
Decision2["THROTTLE"] = "THROTTLE";
|
|
1701
|
+
Decision2["FLAG"] = "FLAG";
|
|
1702
|
+
return Decision2;
|
|
1703
|
+
})(Decision || {});
|
|
1704
|
+
SensorDecisions = {
|
|
1705
|
+
allow(meta, tags) {
|
|
1706
|
+
return {
|
|
1707
|
+
decision: "ALLOW" /* ALLOW */,
|
|
1708
|
+
allow: true,
|
|
1709
|
+
riskScore: 0,
|
|
1710
|
+
reasons: [],
|
|
1711
|
+
tags,
|
|
1712
|
+
meta
|
|
1713
|
+
};
|
|
1714
|
+
},
|
|
1715
|
+
deny(code, reason, meta) {
|
|
1716
|
+
return {
|
|
1717
|
+
decision: "DENY" /* DENY */,
|
|
1718
|
+
allow: false,
|
|
1719
|
+
riskScore: 100,
|
|
1720
|
+
code,
|
|
1721
|
+
reasons: [code, reason].filter(Boolean),
|
|
1722
|
+
meta
|
|
1723
|
+
};
|
|
1724
|
+
},
|
|
1725
|
+
throttle(retryAfterMs, meta) {
|
|
1726
|
+
return {
|
|
1727
|
+
decision: "THROTTLE" /* THROTTLE */,
|
|
1728
|
+
allow: false,
|
|
1729
|
+
riskScore: 50,
|
|
1730
|
+
retryAfterMs,
|
|
1731
|
+
code: "RATE_LIMIT",
|
|
1732
|
+
reasons: ["RATE_LIMIT"],
|
|
1733
|
+
meta
|
|
1734
|
+
};
|
|
1735
|
+
},
|
|
1736
|
+
flag(scoreDelta, reasons, meta) {
|
|
1737
|
+
return {
|
|
1738
|
+
decision: "FLAG" /* FLAG */,
|
|
1739
|
+
allow: true,
|
|
1740
|
+
riskScore: scoreDelta,
|
|
1741
|
+
scoreDelta,
|
|
1742
|
+
reasons,
|
|
1743
|
+
meta
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
});
|
|
1749
|
+
|
|
1750
|
+
// src/cce/cce.types.ts
|
|
1751
|
+
var CCE_PROTOCOL_VERSION, CCE_DERIVATION, CCE_AES_KEY_BYTES, CCE_IV_BYTES, CCE_NONCE_BYTES, CCE_ERROR, CceError;
|
|
1752
|
+
var init_cce_types = __esm({
|
|
1753
|
+
"src/cce/cce.types.ts"() {
|
|
1754
|
+
CCE_PROTOCOL_VERSION = "cce-v1";
|
|
1755
|
+
CCE_DERIVATION = {
|
|
1756
|
+
/** Request execution context */
|
|
1757
|
+
REQUEST: "axis:cce:req:v1",
|
|
1758
|
+
/** Response execution context */
|
|
1759
|
+
RESPONSE: "axis:cce:resp:v1",
|
|
1760
|
+
/** Witness binding context */
|
|
1761
|
+
WITNESS: "axis:cce:witness:v1"
|
|
1762
|
+
};
|
|
1763
|
+
CCE_AES_KEY_BYTES = 32;
|
|
1764
|
+
CCE_IV_BYTES = 12;
|
|
1765
|
+
CCE_NONCE_BYTES = 32;
|
|
1766
|
+
CCE_ERROR = {
|
|
1767
|
+
// Envelope errors
|
|
1768
|
+
INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
|
|
1769
|
+
UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
|
|
1770
|
+
MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
|
|
1771
|
+
MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
|
|
1772
|
+
// Signature errors
|
|
1773
|
+
CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
|
|
1774
|
+
CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
|
|
1775
|
+
// Capsule errors
|
|
1776
|
+
CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
|
|
1777
|
+
CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
|
|
1778
|
+
CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
|
|
1779
|
+
CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
|
|
1780
|
+
CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
|
|
1781
|
+
CAPSULE_NOT_VERIFIED: "CCE_CAPSULE_NOT_VERIFIED",
|
|
1782
|
+
// Binding errors
|
|
1783
|
+
AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
|
|
1784
|
+
INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
|
|
1785
|
+
TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
|
|
1786
|
+
TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
|
|
1787
|
+
// Replay / nonce errors
|
|
1788
|
+
REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
|
|
1789
|
+
NONCE_REUSED: "CCE_NONCE_REUSED",
|
|
1790
|
+
// Decryption errors
|
|
1791
|
+
DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
|
|
1792
|
+
KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
|
|
1793
|
+
AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
|
|
1794
|
+
PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
|
|
1795
|
+
// Schema / validation errors
|
|
1796
|
+
PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
|
|
1797
|
+
INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
|
|
1798
|
+
// Policy errors
|
|
1799
|
+
POLICY_DENIED: "CCE_POLICY_DENIED",
|
|
1800
|
+
CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
|
|
1801
|
+
// Handler errors
|
|
1802
|
+
HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
|
|
1803
|
+
HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
|
|
1804
|
+
HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
|
|
1805
|
+
// Response errors
|
|
1806
|
+
RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
|
|
1807
|
+
};
|
|
1808
|
+
CceError = class extends Error {
|
|
1809
|
+
constructor(code, message, metadata) {
|
|
1810
|
+
super(`[${code}] ${message}`);
|
|
1811
|
+
this.code = code;
|
|
1812
|
+
this.metadata = metadata;
|
|
1813
|
+
this.name = "CceError";
|
|
1814
|
+
}
|
|
1815
|
+
/** Whether this error is safe to expose to the client */
|
|
1816
|
+
get clientSafe() {
|
|
1817
|
+
const internal = [
|
|
1818
|
+
CCE_ERROR.DECRYPTION_FAILED,
|
|
1819
|
+
CCE_ERROR.KEY_UNWRAP_FAILED,
|
|
1820
|
+
CCE_ERROR.AEAD_TAG_MISMATCH,
|
|
1821
|
+
CCE_ERROR.HANDLER_EXECUTION_FAILED,
|
|
1822
|
+
CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
|
|
1823
|
+
];
|
|
1824
|
+
return !internal.includes(this.code);
|
|
1825
|
+
}
|
|
1826
|
+
/** Get client-safe representation */
|
|
1827
|
+
toClientError() {
|
|
1828
|
+
if (this.clientSafe) {
|
|
1829
|
+
return { code: this.code, message: this.message };
|
|
1830
|
+
}
|
|
1831
|
+
return {
|
|
1832
|
+
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
1833
|
+
message: "Request processing failed"
|
|
1834
|
+
};
|
|
1835
|
+
}
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
|
|
1840
|
+
// src/cce/cce-derivation.service.ts
|
|
1841
|
+
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
1842
|
+
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
1843
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
1844
|
+
function buildSalt(capsuleId, capsuleNonce, requestNonce) {
|
|
1845
|
+
const encoder = new TextEncoder();
|
|
1846
|
+
const data = encoder.encode(
|
|
1847
|
+
capsuleId + "|" + capsuleNonce + "|" + requestNonce
|
|
1848
|
+
);
|
|
1849
|
+
return sha256(data);
|
|
1850
|
+
}
|
|
1851
|
+
function buildInfo(contextPrefix, capsule, extraNonce) {
|
|
1852
|
+
const encoder = new TextEncoder();
|
|
1853
|
+
const parts = [
|
|
1854
|
+
contextPrefix,
|
|
1855
|
+
capsule.sub,
|
|
1856
|
+
capsule.kid,
|
|
1857
|
+
capsule.intent,
|
|
1858
|
+
capsule.aud,
|
|
1859
|
+
String(capsule.tps_from),
|
|
1860
|
+
String(capsule.tps_to),
|
|
1861
|
+
capsule.policy_hash ?? "",
|
|
1862
|
+
capsule.ver
|
|
1863
|
+
];
|
|
1864
|
+
if (extraNonce) {
|
|
1865
|
+
parts.push(extraNonce);
|
|
1866
|
+
}
|
|
1867
|
+
return encoder.encode(parts.join("|"));
|
|
1868
|
+
}
|
|
1869
|
+
function deriveRequestExecutionKey(input) {
|
|
1870
|
+
const ikm = hexToBytes(input.axisLocalSecret);
|
|
1871
|
+
const salt = buildSalt(
|
|
1872
|
+
input.capsule.capsule_id,
|
|
1873
|
+
input.capsule.capsule_nonce,
|
|
1874
|
+
input.requestNonce
|
|
1875
|
+
);
|
|
1876
|
+
const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
|
|
1877
|
+
return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
1878
|
+
}
|
|
1879
|
+
function buildExecutionContext(input, requestId) {
|
|
1880
|
+
const executionKey = deriveRequestExecutionKey(input);
|
|
1881
|
+
const keyHash = bytesToHex(sha256(executionKey));
|
|
1882
|
+
executionKey.fill(0);
|
|
1883
|
+
return {
|
|
1884
|
+
execution_key_hash: keyHash,
|
|
1885
|
+
request_id: requestId,
|
|
1886
|
+
capsule_id: input.capsule.capsule_id,
|
|
1887
|
+
sub: input.capsule.sub,
|
|
1888
|
+
kid: input.capsule.kid,
|
|
1889
|
+
intent: input.capsule.intent,
|
|
1890
|
+
aud: input.capsule.aud,
|
|
1891
|
+
tps_from: input.capsule.tps_from,
|
|
1892
|
+
tps_to: input.capsule.tps_to,
|
|
1893
|
+
policy_hash: input.capsule.policy_hash,
|
|
1894
|
+
derived_at: Math.floor(Date.now() / 1e3),
|
|
1895
|
+
valid: true
|
|
1896
|
+
};
|
|
1897
|
+
}
|
|
1898
|
+
var init_cce_derivation_service = __esm({
|
|
1899
|
+
"src/cce/cce-derivation.service.ts"() {
|
|
1900
|
+
init_cce_types();
|
|
1901
|
+
}
|
|
1902
|
+
});
|
|
1903
|
+
|
|
1904
|
+
// src/cce/cce-crypto.ts
|
|
1905
|
+
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
|
|
1906
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
|
|
1907
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
1908
|
+
function aesGcmEncrypt(key, plaintext, aad) {
|
|
1909
|
+
if (key.length !== CCE_AES_KEY_BYTES) {
|
|
1910
|
+
throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
|
|
1911
|
+
}
|
|
1912
|
+
const iv = randomBytes(CCE_IV_BYTES);
|
|
1913
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
1914
|
+
if (aad) {
|
|
1915
|
+
cipher.setAAD(aad);
|
|
1916
|
+
}
|
|
1917
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
1918
|
+
const tag = cipher.getAuthTag();
|
|
1919
|
+
return {
|
|
1920
|
+
iv: new Uint8Array(iv),
|
|
1921
|
+
ciphertext: new Uint8Array(encrypted),
|
|
1922
|
+
tag: new Uint8Array(tag)
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
function generateAesKey() {
|
|
1926
|
+
return new Uint8Array(randomBytes(CCE_AES_KEY_BYTES));
|
|
1927
|
+
}
|
|
1928
|
+
function base64UrlEncode(bytes2) {
|
|
1929
|
+
return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1930
|
+
}
|
|
1931
|
+
function hashPayload(payload) {
|
|
1932
|
+
return bytesToHex2(sha2562(payload));
|
|
1933
|
+
}
|
|
1934
|
+
var init_cce_crypto = __esm({
|
|
1935
|
+
"src/cce/cce-crypto.ts"() {
|
|
1936
|
+
init_cce_types();
|
|
1937
|
+
}
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
// src/cce/cce-response.service.ts
|
|
1941
|
+
import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils.js";
|
|
1942
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
1667
1943
|
async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
|
|
1668
1944
|
const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
|
|
1669
1945
|
const responseNonce = bytesToHex3(
|
|
@@ -1836,124 +2112,20 @@ function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
|
|
|
1836
2112
|
);
|
|
1837
2113
|
const witnessKey = hkdf2(sha2563, ikm, salt, info, 32);
|
|
1838
2114
|
const hash = bytesToHex4(sha2563(witnessKey));
|
|
1839
|
-
witnessKey.fill(0);
|
|
1840
|
-
return hash;
|
|
1841
|
-
}
|
|
1842
|
-
function hexToBytes2(hex) {
|
|
1843
|
-
const bytes2 = new Uint8Array(hex.length / 2);
|
|
1844
|
-
for (let i = 0; i < bytes2.length; i++) {
|
|
1845
|
-
bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
1846
|
-
}
|
|
1847
|
-
return bytes2;
|
|
1848
|
-
}
|
|
1849
|
-
var init_cce_witness_observer = __esm({
|
|
1850
|
-
"src/cce/cce-witness.observer.ts"() {
|
|
1851
|
-
init_cce_crypto();
|
|
1852
|
-
init_cce_types();
|
|
1853
|
-
}
|
|
1854
|
-
});
|
|
1855
|
-
|
|
1856
|
-
// src/sensor/axis-sensor.ts
|
|
1857
|
-
function normalizeSensorDecision(sensorDecision) {
|
|
1858
|
-
if ("action" in sensorDecision) {
|
|
1859
|
-
switch (sensorDecision.action) {
|
|
1860
|
-
case "ALLOW":
|
|
1861
|
-
return {
|
|
1862
|
-
allow: true,
|
|
1863
|
-
riskScore: 0,
|
|
1864
|
-
reasons: [],
|
|
1865
|
-
meta: sensorDecision.meta
|
|
1866
|
-
};
|
|
1867
|
-
case "DENY":
|
|
1868
|
-
return {
|
|
1869
|
-
allow: false,
|
|
1870
|
-
riskScore: 100,
|
|
1871
|
-
reasons: [sensorDecision.code, sensorDecision.reason].filter(
|
|
1872
|
-
Boolean
|
|
1873
|
-
),
|
|
1874
|
-
meta: sensorDecision.meta,
|
|
1875
|
-
retryAfterMs: sensorDecision.retryAfterMs
|
|
1876
|
-
};
|
|
1877
|
-
case "THROTTLE":
|
|
1878
|
-
return {
|
|
1879
|
-
allow: false,
|
|
1880
|
-
riskScore: 50,
|
|
1881
|
-
reasons: ["RATE_LIMIT"],
|
|
1882
|
-
retryAfterMs: sensorDecision.retryAfterMs,
|
|
1883
|
-
meta: sensorDecision.meta
|
|
1884
|
-
};
|
|
1885
|
-
case "FLAG":
|
|
1886
|
-
return {
|
|
1887
|
-
allow: true,
|
|
1888
|
-
riskScore: sensorDecision.scoreDelta,
|
|
1889
|
-
reasons: sensorDecision.reasons,
|
|
1890
|
-
meta: sensorDecision.meta
|
|
1891
|
-
};
|
|
1892
|
-
}
|
|
1893
|
-
}
|
|
1894
|
-
return {
|
|
1895
|
-
allow: sensorDecision.allow,
|
|
1896
|
-
riskScore: sensorDecision.riskScore,
|
|
1897
|
-
reasons: sensorDecision.reasons,
|
|
1898
|
-
tags: sensorDecision.tags,
|
|
1899
|
-
meta: sensorDecision.meta,
|
|
1900
|
-
tighten: sensorDecision.tighten,
|
|
1901
|
-
retryAfterMs: sensorDecision.retryAfterMs
|
|
1902
|
-
};
|
|
2115
|
+
witnessKey.fill(0);
|
|
2116
|
+
return hash;
|
|
1903
2117
|
}
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
allow(meta, tags) {
|
|
1916
|
-
return {
|
|
1917
|
-
decision: "ALLOW" /* ALLOW */,
|
|
1918
|
-
allow: true,
|
|
1919
|
-
riskScore: 0,
|
|
1920
|
-
reasons: [],
|
|
1921
|
-
tags,
|
|
1922
|
-
meta
|
|
1923
|
-
};
|
|
1924
|
-
},
|
|
1925
|
-
deny(code, reason, meta) {
|
|
1926
|
-
return {
|
|
1927
|
-
decision: "DENY" /* DENY */,
|
|
1928
|
-
allow: false,
|
|
1929
|
-
riskScore: 100,
|
|
1930
|
-
code,
|
|
1931
|
-
reasons: [code, reason].filter(Boolean),
|
|
1932
|
-
meta
|
|
1933
|
-
};
|
|
1934
|
-
},
|
|
1935
|
-
throttle(retryAfterMs, meta) {
|
|
1936
|
-
return {
|
|
1937
|
-
decision: "THROTTLE" /* THROTTLE */,
|
|
1938
|
-
allow: false,
|
|
1939
|
-
riskScore: 50,
|
|
1940
|
-
retryAfterMs,
|
|
1941
|
-
code: "RATE_LIMIT",
|
|
1942
|
-
reasons: ["RATE_LIMIT"],
|
|
1943
|
-
meta
|
|
1944
|
-
};
|
|
1945
|
-
},
|
|
1946
|
-
flag(scoreDelta, reasons, meta) {
|
|
1947
|
-
return {
|
|
1948
|
-
decision: "FLAG" /* FLAG */,
|
|
1949
|
-
allow: true,
|
|
1950
|
-
riskScore: scoreDelta,
|
|
1951
|
-
scoreDelta,
|
|
1952
|
-
reasons,
|
|
1953
|
-
meta
|
|
1954
|
-
};
|
|
1955
|
-
}
|
|
1956
|
-
};
|
|
2118
|
+
function hexToBytes2(hex) {
|
|
2119
|
+
const bytes2 = new Uint8Array(hex.length / 2);
|
|
2120
|
+
for (let i = 0; i < bytes2.length; i++) {
|
|
2121
|
+
bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
2122
|
+
}
|
|
2123
|
+
return bytes2;
|
|
2124
|
+
}
|
|
2125
|
+
var init_cce_witness_observer = __esm({
|
|
2126
|
+
"src/cce/cce-witness.observer.ts"() {
|
|
2127
|
+
init_cce_crypto();
|
|
2128
|
+
init_cce_types();
|
|
1957
2129
|
}
|
|
1958
2130
|
});
|
|
1959
2131
|
|
|
@@ -2205,167 +2377,6 @@ var init_axis_error = __esm({
|
|
|
2205
2377
|
}
|
|
2206
2378
|
});
|
|
2207
2379
|
|
|
2208
|
-
// src/security/scopes.ts
|
|
2209
|
-
function hasScope(scopes, required) {
|
|
2210
|
-
if (!Array.isArray(scopes) || scopes.length === 0) {
|
|
2211
|
-
return false;
|
|
2212
|
-
}
|
|
2213
|
-
if (scopes.includes(required)) {
|
|
2214
|
-
return true;
|
|
2215
|
-
}
|
|
2216
|
-
const [resource, id] = required.split(":");
|
|
2217
|
-
if (resource && id) {
|
|
2218
|
-
const wildcard = `${resource}:*`;
|
|
2219
|
-
if (scopes.includes(wildcard)) {
|
|
2220
|
-
return true;
|
|
2221
|
-
}
|
|
2222
|
-
}
|
|
2223
|
-
return false;
|
|
2224
|
-
}
|
|
2225
|
-
function parseScope(scope) {
|
|
2226
|
-
const parts = scope.split(":");
|
|
2227
|
-
if (parts.length !== 2) return null;
|
|
2228
|
-
return { resource: parts[0], id: parts[1] };
|
|
2229
|
-
}
|
|
2230
|
-
function canAccessResource(scopes, resourceType, resourceId) {
|
|
2231
|
-
const required = `${resourceType}:${resourceId}`;
|
|
2232
|
-
return hasScope(scopes, required);
|
|
2233
|
-
}
|
|
2234
|
-
var init_scopes = __esm({
|
|
2235
|
-
"src/security/scopes.ts"() {
|
|
2236
|
-
}
|
|
2237
|
-
});
|
|
2238
|
-
|
|
2239
|
-
// src/security/inline-capsule.ts
|
|
2240
|
-
function normalizeInlineCapsule(input) {
|
|
2241
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
2242
|
-
return null;
|
|
2243
|
-
}
|
|
2244
|
-
const raw = input;
|
|
2245
|
-
const scopes = normalizeStringList(raw.scopes ?? raw.scope);
|
|
2246
|
-
return {
|
|
2247
|
-
id: normalizeScalar(raw.id),
|
|
2248
|
-
actorId: normalizeScalar(raw.actorId),
|
|
2249
|
-
intents: normalizeStringList(raw.intents),
|
|
2250
|
-
issuedAt: normalizeTimestamp(raw.issuedAt ?? raw.iat),
|
|
2251
|
-
expiresAt: normalizeTimestamp(raw.expiresAt ?? raw.exp),
|
|
2252
|
-
realm: normalizeScalar(raw.realm),
|
|
2253
|
-
node: normalizeScalar(raw.node),
|
|
2254
|
-
scopes,
|
|
2255
|
-
raw
|
|
2256
|
-
};
|
|
2257
|
-
}
|
|
2258
|
-
function inlineCapsuleAllowsIntent(capsule, intent) {
|
|
2259
|
-
if (!capsule.intents || capsule.intents.length === 0) {
|
|
2260
|
-
return false;
|
|
2261
|
-
}
|
|
2262
|
-
for (const pattern of capsule.intents) {
|
|
2263
|
-
if (pattern === "*" || pattern === intent) {
|
|
2264
|
-
return true;
|
|
2265
|
-
}
|
|
2266
|
-
if (pattern.endsWith(".*")) {
|
|
2267
|
-
const prefix = pattern.slice(0, -1);
|
|
2268
|
-
if (intent.startsWith(prefix)) {
|
|
2269
|
-
return true;
|
|
2270
|
-
}
|
|
2271
|
-
}
|
|
2272
|
-
}
|
|
2273
|
-
return false;
|
|
2274
|
-
}
|
|
2275
|
-
function isInlineCapsuleExpired(capsule, clockSkewMs = 3e4) {
|
|
2276
|
-
if (capsule.expiresAt === void 0) {
|
|
2277
|
-
return false;
|
|
2278
|
-
}
|
|
2279
|
-
return BigInt(Date.now()) > capsule.expiresAt + BigInt(clockSkewMs);
|
|
2280
|
-
}
|
|
2281
|
-
function resolvePolicyScopes(scopes, context) {
|
|
2282
|
-
return scopes.map(
|
|
2283
|
-
(scope) => scope.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
|
|
2284
|
-
const resolved = resolveTemplateExpression(expression.trim(), context);
|
|
2285
|
-
if (resolved === void 0 || resolved === null || resolved === "") {
|
|
2286
|
-
throw new Error(`CAPSULE_SCOPE_TEMPLATE_UNRESOLVED:${expression}`);
|
|
2287
|
-
}
|
|
2288
|
-
return String(resolved);
|
|
2289
|
-
})
|
|
2290
|
-
);
|
|
2291
|
-
}
|
|
2292
|
-
function inlineCapsuleSatisfiesScopes(capsule, requiredScopes, mode = "all") {
|
|
2293
|
-
if (!capsule.scopes || capsule.scopes.length === 0) {
|
|
2294
|
-
return false;
|
|
2295
|
-
}
|
|
2296
|
-
if (mode === "any") {
|
|
2297
|
-
return requiredScopes.some((scope) => hasScope(capsule.scopes, scope));
|
|
2298
|
-
}
|
|
2299
|
-
return requiredScopes.every((scope) => hasScope(capsule.scopes, scope));
|
|
2300
|
-
}
|
|
2301
|
-
function resolveTemplateExpression(expression, context) {
|
|
2302
|
-
if (expression === "intent") {
|
|
2303
|
-
return context.intent;
|
|
2304
|
-
}
|
|
2305
|
-
if (expression === "actorId") {
|
|
2306
|
-
return context.actorId;
|
|
2307
|
-
}
|
|
2308
|
-
if (expression === "chainId") {
|
|
2309
|
-
return context.chainId;
|
|
2310
|
-
}
|
|
2311
|
-
if (expression === "stepId") {
|
|
2312
|
-
return context.stepId;
|
|
2313
|
-
}
|
|
2314
|
-
if (expression.startsWith("body.")) {
|
|
2315
|
-
return getNestedValue(context.body, expression.slice(5));
|
|
2316
|
-
}
|
|
2317
|
-
return void 0;
|
|
2318
|
-
}
|
|
2319
|
-
function getNestedValue(value, path2) {
|
|
2320
|
-
if (!value || typeof value !== "object") {
|
|
2321
|
-
return void 0;
|
|
2322
|
-
}
|
|
2323
|
-
return path2.split(".").reduce((current, segment) => {
|
|
2324
|
-
if (!current || typeof current !== "object") {
|
|
2325
|
-
return void 0;
|
|
2326
|
-
}
|
|
2327
|
-
return current[segment];
|
|
2328
|
-
}, value);
|
|
2329
|
-
}
|
|
2330
|
-
function normalizeScalar(value) {
|
|
2331
|
-
if (typeof value === "string") {
|
|
2332
|
-
return value;
|
|
2333
|
-
}
|
|
2334
|
-
if (value instanceof Uint8Array) {
|
|
2335
|
-
return Buffer.from(value).toString("hex");
|
|
2336
|
-
}
|
|
2337
|
-
return void 0;
|
|
2338
|
-
}
|
|
2339
|
-
function normalizeStringList(value) {
|
|
2340
|
-
if (!value) {
|
|
2341
|
-
return void 0;
|
|
2342
|
-
}
|
|
2343
|
-
const list = Array.isArray(value) ? value : [value];
|
|
2344
|
-
const normalized = list.map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => !!entry && entry.trim().length > 0);
|
|
2345
|
-
return normalized.length > 0 ? Array.from(new Set(normalized)) : void 0;
|
|
2346
|
-
}
|
|
2347
|
-
function normalizeTimestamp(value) {
|
|
2348
|
-
if (typeof value === "bigint") {
|
|
2349
|
-
return value;
|
|
2350
|
-
}
|
|
2351
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2352
|
-
return BigInt(Math.trunc(value));
|
|
2353
|
-
}
|
|
2354
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
2355
|
-
try {
|
|
2356
|
-
return BigInt(value);
|
|
2357
|
-
} catch {
|
|
2358
|
-
return void 0;
|
|
2359
|
-
}
|
|
2360
|
-
}
|
|
2361
|
-
return void 0;
|
|
2362
|
-
}
|
|
2363
|
-
var init_inline_capsule = __esm({
|
|
2364
|
-
"src/security/inline-capsule.ts"() {
|
|
2365
|
-
init_scopes();
|
|
2366
|
-
}
|
|
2367
|
-
});
|
|
2368
|
-
|
|
2369
2380
|
// src/engine/intent.router.ts
|
|
2370
2381
|
var intent_router_exports = {};
|
|
2371
2382
|
__export(intent_router_exports, {
|
|
@@ -2442,23 +2453,23 @@ function normalizeChainConfig(decoratorConfig, intentConfig) {
|
|
|
2442
2453
|
var import_dto_schema, _IntentRouter, IntentRouter;
|
|
2443
2454
|
var init_intent_router = __esm({
|
|
2444
2455
|
"src/engine/intent.router.ts"() {
|
|
2445
|
-
init_cce_pipeline();
|
|
2446
|
-
init_axis_error();
|
|
2447
|
-
init_constants();
|
|
2448
|
-
init_capsule_policy_decorator();
|
|
2449
|
-
init_chain_decorator();
|
|
2450
|
-
import_dto_schema = __toESM(require_dto_schema_util());
|
|
2451
2456
|
init_handler_sensors_decorator();
|
|
2452
|
-
|
|
2453
|
-
init_intent_body_decorator();
|
|
2454
|
-
init_intent_policy_decorator();
|
|
2457
|
+
init_capsule_policy_decorator();
|
|
2455
2458
|
init_intent_sensors_decorator();
|
|
2456
|
-
|
|
2459
|
+
init_intent_policy_decorator();
|
|
2460
|
+
init_intent_body_decorator();
|
|
2457
2461
|
init_observer_decorator();
|
|
2462
|
+
init_handler_decorator();
|
|
2463
|
+
init_intent_decorator();
|
|
2464
|
+
init_chain_decorator();
|
|
2465
|
+
import_dto_schema = __toESM(require_dto_schema_util());
|
|
2458
2466
|
init_inline_capsule();
|
|
2459
|
-
init_axis_sensor();
|
|
2460
2467
|
init_axis_execution_context();
|
|
2468
|
+
init_axis_sensor();
|
|
2461
2469
|
init_axis_logger();
|
|
2470
|
+
init_cce_pipeline();
|
|
2471
|
+
init_axis_error();
|
|
2472
|
+
init_constants();
|
|
2462
2473
|
_IntentRouter = class _IntentRouter {
|
|
2463
2474
|
constructor(dependencyResolver, observerDispatcher, sensorRegistry) {
|
|
2464
2475
|
this.logger = createAxisLogger(_IntentRouter.name);
|
|
@@ -2494,6 +2505,8 @@ var init_intent_router = __esm({
|
|
|
2494
2505
|
this.publicIntents = /* @__PURE__ */ new Set();
|
|
2495
2506
|
/** Intents flagged as anonymous-session accessible */
|
|
2496
2507
|
this.anonymousIntents = /* @__PURE__ */ new Set();
|
|
2508
|
+
/** Intents flagged as authorized-session accessible */
|
|
2509
|
+
this.authorizedIntents = /* @__PURE__ */ new Set();
|
|
2497
2510
|
/** Per-intent rate limit config */
|
|
2498
2511
|
this.intentRateLimits = /* @__PURE__ */ new Map();
|
|
2499
2512
|
/** CCE handler registry */
|
|
@@ -2920,6 +2933,18 @@ var init_intent_router = __esm({
|
|
|
2920
2933
|
if (isAnonMethod || isAnonClass) {
|
|
2921
2934
|
this.anonymousIntents.add(intent);
|
|
2922
2935
|
}
|
|
2936
|
+
const isAuthorizedMethod = Reflect.getMetadata(
|
|
2937
|
+
AXIS_AUTHORIZED_KEY,
|
|
2938
|
+
proto,
|
|
2939
|
+
methodName
|
|
2940
|
+
);
|
|
2941
|
+
const isAuthorizedClass = Reflect.getMetadata(
|
|
2942
|
+
AXIS_AUTHORIZED_KEY,
|
|
2943
|
+
proto.constructor
|
|
2944
|
+
);
|
|
2945
|
+
if (isAuthorizedMethod || isAuthorizedClass) {
|
|
2946
|
+
this.authorizedIntents.add(intent);
|
|
2947
|
+
}
|
|
2923
2948
|
const rateLimit = Reflect.getMetadata(
|
|
2924
2949
|
AXIS_RATE_LIMIT_KEY,
|
|
2925
2950
|
proto,
|
|
@@ -2945,6 +2970,9 @@ var init_intent_router = __esm({
|
|
|
2945
2970
|
isAnonymous(intent) {
|
|
2946
2971
|
return this.anonymousIntents.has(intent);
|
|
2947
2972
|
}
|
|
2973
|
+
isAuthorized(intent) {
|
|
2974
|
+
return this.authorizedIntents.has(intent);
|
|
2975
|
+
}
|
|
2948
2976
|
getRateLimit(intent) {
|
|
2949
2977
|
return this.intentRateLimits.get(intent);
|
|
2950
2978
|
}
|
|
@@ -12745,6 +12773,7 @@ __export(index_exports, {
|
|
|
12745
12773
|
ATS1_HDR: () => ATS1_HDR,
|
|
12746
12774
|
ATS1_SCHEMA: () => ATS1_SCHEMA,
|
|
12747
12775
|
AXIS_ANONYMOUS_KEY: () => AXIS_ANONYMOUS_KEY,
|
|
12776
|
+
AXIS_AUTHORIZED_KEY: () => AXIS_AUTHORIZED_KEY,
|
|
12748
12777
|
AXIS_EXECUTION_CONTEXT_KEY: () => AXIS_EXECUTION_CONTEXT_KEY,
|
|
12749
12778
|
AXIS_MAGIC: () => AXIS_MAGIC,
|
|
12750
12779
|
AXIS_META_KEY: () => AXIS_META_KEY,
|
|
@@ -12758,6 +12787,7 @@ __export(index_exports, {
|
|
|
12758
12787
|
Ats1Codec: () => ats1_exports,
|
|
12759
12788
|
Axis: () => Axis,
|
|
12760
12789
|
AxisAnonymous: () => AxisAnonymous,
|
|
12790
|
+
AxisAuthorized: () => AxisAuthorized,
|
|
12761
12791
|
AxisChainExecutor: () => AxisChainExecutor,
|
|
12762
12792
|
AxisError: () => AxisError,
|
|
12763
12793
|
AxisFrameZ: () => AxisFrameZ,
|
|
@@ -13146,6 +13176,7 @@ export {
|
|
|
13146
13176
|
ATS1_HDR,
|
|
13147
13177
|
ATS1_SCHEMA,
|
|
13148
13178
|
AXIS_ANONYMOUS_KEY,
|
|
13179
|
+
AXIS_AUTHORIZED_KEY,
|
|
13149
13180
|
AXIS_EXECUTION_CONTEXT_KEY,
|
|
13150
13181
|
AXIS_MAGIC,
|
|
13151
13182
|
AXIS_META_KEY,
|
|
@@ -13159,6 +13190,7 @@ export {
|
|
|
13159
13190
|
ats1_exports as Ats1Codec,
|
|
13160
13191
|
Axis,
|
|
13161
13192
|
AxisAnonymous,
|
|
13193
|
+
AxisAuthorized,
|
|
13162
13194
|
AxisChainExecutor,
|
|
13163
13195
|
AxisError,
|
|
13164
13196
|
AxisFrameZ,
|