@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/sensors/index.mjs
CHANGED
|
@@ -569,6 +569,16 @@ function AxisPublic() {
|
|
|
569
569
|
return target;
|
|
570
570
|
};
|
|
571
571
|
}
|
|
572
|
+
function AxisAuthorized() {
|
|
573
|
+
return (target, propertyKey, descriptor) => {
|
|
574
|
+
if (descriptor) {
|
|
575
|
+
Reflect.defineMetadata(AXIS_AUTHORIZED_KEY, true, target, propertyKey);
|
|
576
|
+
return descriptor;
|
|
577
|
+
}
|
|
578
|
+
Reflect.defineMetadata(AXIS_AUTHORIZED_KEY, true, target);
|
|
579
|
+
return target;
|
|
580
|
+
};
|
|
581
|
+
}
|
|
572
582
|
function AxisAnonymous() {
|
|
573
583
|
return (target, propertyKey, descriptor) => {
|
|
574
584
|
if (descriptor) {
|
|
@@ -585,7 +595,7 @@ function AxisRateLimit(config) {
|
|
|
585
595
|
return descriptor;
|
|
586
596
|
};
|
|
587
597
|
}
|
|
588
|
-
var AXIS_META_KEY, SENSITIVITY_METADATA_KEY, CONTRACT_METADATA_KEY, REQUIRED_PROOF_METADATA_KEY, AXIS_PUBLIC_KEY, AXIS_ANONYMOUS_KEY, AXIS_RATE_LIMIT_KEY;
|
|
598
|
+
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;
|
|
589
599
|
var init_intent_policy_decorator = __esm({
|
|
590
600
|
"src/decorators/intent-policy.decorator.ts"() {
|
|
591
601
|
AXIS_META_KEY = "axis:axis";
|
|
@@ -594,6 +604,7 @@ var init_intent_policy_decorator = __esm({
|
|
|
594
604
|
REQUIRED_PROOF_METADATA_KEY = "axis:required_proof";
|
|
595
605
|
AXIS_PUBLIC_KEY = "axis:public";
|
|
596
606
|
AXIS_ANONYMOUS_KEY = "axis:anonymous";
|
|
607
|
+
AXIS_AUTHORIZED_KEY = "axis:authorized";
|
|
597
608
|
AXIS_RATE_LIMIT_KEY = "axis:rateLimit";
|
|
598
609
|
}
|
|
599
610
|
});
|
|
@@ -1619,199 +1630,464 @@ var init_axis_chain_executor = __esm({
|
|
|
1619
1630
|
}
|
|
1620
1631
|
});
|
|
1621
1632
|
|
|
1622
|
-
// src/
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
CCE_PROTOCOL_VERSION = "cce-v1";
|
|
1627
|
-
CCE_DERIVATION = {
|
|
1628
|
-
/** Request execution context */
|
|
1629
|
-
REQUEST: "axis:cce:req:v1",
|
|
1630
|
-
/** Response execution context */
|
|
1631
|
-
RESPONSE: "axis:cce:resp:v1",
|
|
1632
|
-
/** Witness binding context */
|
|
1633
|
-
WITNESS: "axis:cce:witness:v1"
|
|
1634
|
-
};
|
|
1635
|
-
CCE_AES_KEY_BYTES = 32;
|
|
1636
|
-
CCE_IV_BYTES = 12;
|
|
1637
|
-
CCE_NONCE_BYTES = 32;
|
|
1638
|
-
CCE_ERROR = {
|
|
1639
|
-
// Envelope errors
|
|
1640
|
-
INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
|
|
1641
|
-
UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
|
|
1642
|
-
MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
|
|
1643
|
-
MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
|
|
1644
|
-
// Signature errors
|
|
1645
|
-
CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
|
|
1646
|
-
CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
|
|
1647
|
-
// Capsule errors
|
|
1648
|
-
CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
|
|
1649
|
-
CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
|
|
1650
|
-
CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
|
|
1651
|
-
CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
|
|
1652
|
-
CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
|
|
1653
|
-
CAPSULE_NOT_VERIFIED: "CCE_CAPSULE_NOT_VERIFIED",
|
|
1654
|
-
// Binding errors
|
|
1655
|
-
AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
|
|
1656
|
-
INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
|
|
1657
|
-
TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
|
|
1658
|
-
TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
|
|
1659
|
-
// Replay / nonce errors
|
|
1660
|
-
REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
|
|
1661
|
-
NONCE_REUSED: "CCE_NONCE_REUSED",
|
|
1662
|
-
// Decryption errors
|
|
1663
|
-
DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
|
|
1664
|
-
KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
|
|
1665
|
-
AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
|
|
1666
|
-
PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
|
|
1667
|
-
// Schema / validation errors
|
|
1668
|
-
PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
|
|
1669
|
-
INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
|
|
1670
|
-
// Policy errors
|
|
1671
|
-
POLICY_DENIED: "CCE_POLICY_DENIED",
|
|
1672
|
-
CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
|
|
1673
|
-
// Handler errors
|
|
1674
|
-
HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
|
|
1675
|
-
HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
|
|
1676
|
-
HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
|
|
1677
|
-
// Response errors
|
|
1678
|
-
RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
|
|
1679
|
-
};
|
|
1680
|
-
CceError = class extends Error {
|
|
1681
|
-
constructor(code, message, metadata) {
|
|
1682
|
-
super(`[${code}] ${message}`);
|
|
1683
|
-
this.code = code;
|
|
1684
|
-
this.metadata = metadata;
|
|
1685
|
-
this.name = "CceError";
|
|
1686
|
-
}
|
|
1687
|
-
/** Whether this error is safe to expose to the client */
|
|
1688
|
-
get clientSafe() {
|
|
1689
|
-
const internal = [
|
|
1690
|
-
CCE_ERROR.DECRYPTION_FAILED,
|
|
1691
|
-
CCE_ERROR.KEY_UNWRAP_FAILED,
|
|
1692
|
-
CCE_ERROR.AEAD_TAG_MISMATCH,
|
|
1693
|
-
CCE_ERROR.HANDLER_EXECUTION_FAILED,
|
|
1694
|
-
CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
|
|
1695
|
-
];
|
|
1696
|
-
return !internal.includes(this.code);
|
|
1697
|
-
}
|
|
1698
|
-
/** Get client-safe representation */
|
|
1699
|
-
toClientError() {
|
|
1700
|
-
if (this.clientSafe) {
|
|
1701
|
-
return { code: this.code, message: this.message };
|
|
1702
|
-
}
|
|
1703
|
-
return {
|
|
1704
|
-
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
1705
|
-
message: "Request processing failed"
|
|
1706
|
-
};
|
|
1707
|
-
}
|
|
1708
|
-
};
|
|
1633
|
+
// src/security/scopes.ts
|
|
1634
|
+
function hasScope(scopes, required) {
|
|
1635
|
+
if (!Array.isArray(scopes) || scopes.length === 0) {
|
|
1636
|
+
return false;
|
|
1709
1637
|
}
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
// src/cce/cce-derivation.service.ts
|
|
1713
|
-
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
1714
|
-
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
1715
|
-
import { sha256 } from "@noble/hashes/sha2.js";
|
|
1716
|
-
function buildSalt(capsuleId, capsuleNonce, requestNonce) {
|
|
1717
|
-
const encoder = new TextEncoder();
|
|
1718
|
-
const data = encoder.encode(
|
|
1719
|
-
capsuleId + "|" + capsuleNonce + "|" + requestNonce
|
|
1720
|
-
);
|
|
1721
|
-
return sha256(data);
|
|
1722
|
-
}
|
|
1723
|
-
function buildInfo(contextPrefix, capsule, extraNonce) {
|
|
1724
|
-
const encoder = new TextEncoder();
|
|
1725
|
-
const parts = [
|
|
1726
|
-
contextPrefix,
|
|
1727
|
-
capsule.sub,
|
|
1728
|
-
capsule.kid,
|
|
1729
|
-
capsule.intent,
|
|
1730
|
-
capsule.aud,
|
|
1731
|
-
String(capsule.tps_from),
|
|
1732
|
-
String(capsule.tps_to),
|
|
1733
|
-
capsule.policy_hash ?? "",
|
|
1734
|
-
capsule.ver
|
|
1735
|
-
];
|
|
1736
|
-
if (extraNonce) {
|
|
1737
|
-
parts.push(extraNonce);
|
|
1638
|
+
if (scopes.includes(required)) {
|
|
1639
|
+
return true;
|
|
1738
1640
|
}
|
|
1739
|
-
|
|
1641
|
+
const [resource, id] = required.split(":");
|
|
1642
|
+
if (resource && id) {
|
|
1643
|
+
const wildcard = `${resource}:*`;
|
|
1644
|
+
if (scopes.includes(wildcard)) {
|
|
1645
|
+
return true;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
return false;
|
|
1740
1649
|
}
|
|
1741
|
-
function
|
|
1742
|
-
const
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
input.capsule.capsule_nonce,
|
|
1746
|
-
input.requestNonce
|
|
1747
|
-
);
|
|
1748
|
-
const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
|
|
1749
|
-
return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
1650
|
+
function parseScope(scope) {
|
|
1651
|
+
const parts = scope.split(":");
|
|
1652
|
+
if (parts.length !== 2) return null;
|
|
1653
|
+
return { resource: parts[0], id: parts[1] };
|
|
1750
1654
|
}
|
|
1751
|
-
function
|
|
1752
|
-
const
|
|
1753
|
-
|
|
1754
|
-
executionKey.fill(0);
|
|
1755
|
-
return {
|
|
1756
|
-
execution_key_hash: keyHash,
|
|
1757
|
-
request_id: requestId,
|
|
1758
|
-
capsule_id: input.capsule.capsule_id,
|
|
1759
|
-
sub: input.capsule.sub,
|
|
1760
|
-
kid: input.capsule.kid,
|
|
1761
|
-
intent: input.capsule.intent,
|
|
1762
|
-
aud: input.capsule.aud,
|
|
1763
|
-
tps_from: input.capsule.tps_from,
|
|
1764
|
-
tps_to: input.capsule.tps_to,
|
|
1765
|
-
policy_hash: input.capsule.policy_hash,
|
|
1766
|
-
derived_at: Math.floor(Date.now() / 1e3),
|
|
1767
|
-
valid: true
|
|
1768
|
-
};
|
|
1655
|
+
function canAccessResource(scopes, resourceType, resourceId) {
|
|
1656
|
+
const required = `${resourceType}:${resourceId}`;
|
|
1657
|
+
return hasScope(scopes, required);
|
|
1769
1658
|
}
|
|
1770
|
-
var
|
|
1771
|
-
"src/
|
|
1772
|
-
init_cce_types();
|
|
1659
|
+
var init_scopes = __esm({
|
|
1660
|
+
"src/security/scopes.ts"() {
|
|
1773
1661
|
}
|
|
1774
1662
|
});
|
|
1775
1663
|
|
|
1776
|
-
// src/
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
function aesGcmEncrypt(key, plaintext, aad) {
|
|
1781
|
-
if (key.length !== CCE_AES_KEY_BYTES) {
|
|
1782
|
-
throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
|
|
1783
|
-
}
|
|
1784
|
-
const iv = randomBytes(CCE_IV_BYTES);
|
|
1785
|
-
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
1786
|
-
if (aad) {
|
|
1787
|
-
cipher.setAAD(aad);
|
|
1664
|
+
// src/security/inline-capsule.ts
|
|
1665
|
+
function normalizeInlineCapsule(input) {
|
|
1666
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
1667
|
+
return null;
|
|
1788
1668
|
}
|
|
1789
|
-
const
|
|
1790
|
-
const
|
|
1669
|
+
const raw = input;
|
|
1670
|
+
const scopes = normalizeStringList(raw.scopes ?? raw.scope);
|
|
1791
1671
|
return {
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1672
|
+
id: normalizeScalar(raw.id),
|
|
1673
|
+
actorId: normalizeScalar(raw.actorId),
|
|
1674
|
+
intents: normalizeStringList(raw.intents),
|
|
1675
|
+
issuedAt: normalizeTimestamp(raw.issuedAt ?? raw.iat),
|
|
1676
|
+
expiresAt: normalizeTimestamp(raw.expiresAt ?? raw.exp),
|
|
1677
|
+
realm: normalizeScalar(raw.realm),
|
|
1678
|
+
node: normalizeScalar(raw.node),
|
|
1679
|
+
scopes,
|
|
1680
|
+
raw
|
|
1795
1681
|
};
|
|
1796
1682
|
}
|
|
1797
|
-
function
|
|
1798
|
-
|
|
1683
|
+
function inlineCapsuleAllowsIntent(capsule, intent) {
|
|
1684
|
+
if (!capsule.intents || capsule.intents.length === 0) {
|
|
1685
|
+
return false;
|
|
1686
|
+
}
|
|
1687
|
+
for (const pattern of capsule.intents) {
|
|
1688
|
+
if (pattern === "*" || pattern === intent) {
|
|
1689
|
+
return true;
|
|
1690
|
+
}
|
|
1691
|
+
if (pattern.endsWith(".*")) {
|
|
1692
|
+
const prefix = pattern.slice(0, -1);
|
|
1693
|
+
if (intent.startsWith(prefix)) {
|
|
1694
|
+
return true;
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
return false;
|
|
1799
1699
|
}
|
|
1800
|
-
function
|
|
1801
|
-
|
|
1700
|
+
function isInlineCapsuleExpired(capsule, clockSkewMs = 3e4) {
|
|
1701
|
+
if (capsule.expiresAt === void 0) {
|
|
1702
|
+
return false;
|
|
1703
|
+
}
|
|
1704
|
+
return BigInt(Date.now()) > capsule.expiresAt + BigInt(clockSkewMs);
|
|
1802
1705
|
}
|
|
1803
|
-
function
|
|
1804
|
-
return
|
|
1706
|
+
function resolvePolicyScopes(scopes, context) {
|
|
1707
|
+
return scopes.map(
|
|
1708
|
+
(scope) => scope.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
|
|
1709
|
+
const resolved = resolveTemplateExpression(expression.trim(), context);
|
|
1710
|
+
if (resolved === void 0 || resolved === null || resolved === "") {
|
|
1711
|
+
throw new Error(`CAPSULE_SCOPE_TEMPLATE_UNRESOLVED:${expression}`);
|
|
1712
|
+
}
|
|
1713
|
+
return String(resolved);
|
|
1714
|
+
})
|
|
1715
|
+
);
|
|
1805
1716
|
}
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1717
|
+
function inlineCapsuleSatisfiesScopes(capsule, requiredScopes, mode = "all") {
|
|
1718
|
+
if (!capsule.scopes || capsule.scopes.length === 0) {
|
|
1719
|
+
return false;
|
|
1809
1720
|
}
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1721
|
+
if (mode === "any") {
|
|
1722
|
+
return requiredScopes.some((scope) => hasScope(capsule.scopes, scope));
|
|
1723
|
+
}
|
|
1724
|
+
return requiredScopes.every((scope) => hasScope(capsule.scopes, scope));
|
|
1725
|
+
}
|
|
1726
|
+
function resolveTemplateExpression(expression, context) {
|
|
1727
|
+
if (expression === "intent") {
|
|
1728
|
+
return context.intent;
|
|
1729
|
+
}
|
|
1730
|
+
if (expression === "actorId") {
|
|
1731
|
+
return context.actorId;
|
|
1732
|
+
}
|
|
1733
|
+
if (expression === "chainId") {
|
|
1734
|
+
return context.chainId;
|
|
1735
|
+
}
|
|
1736
|
+
if (expression === "stepId") {
|
|
1737
|
+
return context.stepId;
|
|
1738
|
+
}
|
|
1739
|
+
if (expression.startsWith("body.")) {
|
|
1740
|
+
return getNestedValue(context.body, expression.slice(5));
|
|
1741
|
+
}
|
|
1742
|
+
return void 0;
|
|
1743
|
+
}
|
|
1744
|
+
function getNestedValue(value, path2) {
|
|
1745
|
+
if (!value || typeof value !== "object") {
|
|
1746
|
+
return void 0;
|
|
1747
|
+
}
|
|
1748
|
+
return path2.split(".").reduce((current, segment) => {
|
|
1749
|
+
if (!current || typeof current !== "object") {
|
|
1750
|
+
return void 0;
|
|
1751
|
+
}
|
|
1752
|
+
return current[segment];
|
|
1753
|
+
}, value);
|
|
1754
|
+
}
|
|
1755
|
+
function normalizeScalar(value) {
|
|
1756
|
+
if (typeof value === "string") {
|
|
1757
|
+
return value;
|
|
1758
|
+
}
|
|
1759
|
+
if (value instanceof Uint8Array) {
|
|
1760
|
+
return Buffer.from(value).toString("hex");
|
|
1761
|
+
}
|
|
1762
|
+
return void 0;
|
|
1763
|
+
}
|
|
1764
|
+
function normalizeStringList(value) {
|
|
1765
|
+
if (!value) {
|
|
1766
|
+
return void 0;
|
|
1767
|
+
}
|
|
1768
|
+
const list = Array.isArray(value) ? value : [value];
|
|
1769
|
+
const normalized = list.map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => !!entry && entry.trim().length > 0);
|
|
1770
|
+
return normalized.length > 0 ? Array.from(new Set(normalized)) : void 0;
|
|
1771
|
+
}
|
|
1772
|
+
function normalizeTimestamp(value) {
|
|
1773
|
+
if (typeof value === "bigint") {
|
|
1774
|
+
return value;
|
|
1775
|
+
}
|
|
1776
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
1777
|
+
return BigInt(Math.trunc(value));
|
|
1778
|
+
}
|
|
1779
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
1780
|
+
try {
|
|
1781
|
+
return BigInt(value);
|
|
1782
|
+
} catch {
|
|
1783
|
+
return void 0;
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
return void 0;
|
|
1787
|
+
}
|
|
1788
|
+
var init_inline_capsule = __esm({
|
|
1789
|
+
"src/security/inline-capsule.ts"() {
|
|
1790
|
+
init_scopes();
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
1793
|
+
|
|
1794
|
+
// src/sensor/axis-sensor.ts
|
|
1795
|
+
function normalizeSensorDecision(sensorDecision) {
|
|
1796
|
+
if ("action" in sensorDecision) {
|
|
1797
|
+
switch (sensorDecision.action) {
|
|
1798
|
+
case "ALLOW":
|
|
1799
|
+
return {
|
|
1800
|
+
allow: true,
|
|
1801
|
+
riskScore: 0,
|
|
1802
|
+
reasons: [],
|
|
1803
|
+
meta: sensorDecision.meta
|
|
1804
|
+
};
|
|
1805
|
+
case "DENY":
|
|
1806
|
+
return {
|
|
1807
|
+
allow: false,
|
|
1808
|
+
riskScore: 100,
|
|
1809
|
+
reasons: [sensorDecision.code, sensorDecision.reason].filter(
|
|
1810
|
+
Boolean
|
|
1811
|
+
),
|
|
1812
|
+
meta: sensorDecision.meta,
|
|
1813
|
+
retryAfterMs: sensorDecision.retryAfterMs
|
|
1814
|
+
};
|
|
1815
|
+
case "THROTTLE":
|
|
1816
|
+
return {
|
|
1817
|
+
allow: false,
|
|
1818
|
+
riskScore: 50,
|
|
1819
|
+
reasons: ["RATE_LIMIT"],
|
|
1820
|
+
retryAfterMs: sensorDecision.retryAfterMs,
|
|
1821
|
+
meta: sensorDecision.meta
|
|
1822
|
+
};
|
|
1823
|
+
case "FLAG":
|
|
1824
|
+
return {
|
|
1825
|
+
allow: true,
|
|
1826
|
+
riskScore: sensorDecision.scoreDelta,
|
|
1827
|
+
reasons: sensorDecision.reasons,
|
|
1828
|
+
meta: sensorDecision.meta
|
|
1829
|
+
};
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
return {
|
|
1833
|
+
allow: sensorDecision.allow,
|
|
1834
|
+
riskScore: sensorDecision.riskScore,
|
|
1835
|
+
reasons: sensorDecision.reasons,
|
|
1836
|
+
tags: sensorDecision.tags,
|
|
1837
|
+
meta: sensorDecision.meta,
|
|
1838
|
+
tighten: sensorDecision.tighten,
|
|
1839
|
+
retryAfterMs: sensorDecision.retryAfterMs
|
|
1840
|
+
};
|
|
1841
|
+
}
|
|
1842
|
+
var Decision, SensorDecisions;
|
|
1843
|
+
var init_axis_sensor = __esm({
|
|
1844
|
+
"src/sensor/axis-sensor.ts"() {
|
|
1845
|
+
Decision = /* @__PURE__ */ ((Decision2) => {
|
|
1846
|
+
Decision2["ALLOW"] = "ALLOW";
|
|
1847
|
+
Decision2["DENY"] = "DENY";
|
|
1848
|
+
Decision2["THROTTLE"] = "THROTTLE";
|
|
1849
|
+
Decision2["FLAG"] = "FLAG";
|
|
1850
|
+
return Decision2;
|
|
1851
|
+
})(Decision || {});
|
|
1852
|
+
SensorDecisions = {
|
|
1853
|
+
allow(meta, tags) {
|
|
1854
|
+
return {
|
|
1855
|
+
decision: "ALLOW" /* ALLOW */,
|
|
1856
|
+
allow: true,
|
|
1857
|
+
riskScore: 0,
|
|
1858
|
+
reasons: [],
|
|
1859
|
+
tags,
|
|
1860
|
+
meta
|
|
1861
|
+
};
|
|
1862
|
+
},
|
|
1863
|
+
deny(code, reason, meta) {
|
|
1864
|
+
return {
|
|
1865
|
+
decision: "DENY" /* DENY */,
|
|
1866
|
+
allow: false,
|
|
1867
|
+
riskScore: 100,
|
|
1868
|
+
code,
|
|
1869
|
+
reasons: [code, reason].filter(Boolean),
|
|
1870
|
+
meta
|
|
1871
|
+
};
|
|
1872
|
+
},
|
|
1873
|
+
throttle(retryAfterMs, meta) {
|
|
1874
|
+
return {
|
|
1875
|
+
decision: "THROTTLE" /* THROTTLE */,
|
|
1876
|
+
allow: false,
|
|
1877
|
+
riskScore: 50,
|
|
1878
|
+
retryAfterMs,
|
|
1879
|
+
code: "RATE_LIMIT",
|
|
1880
|
+
reasons: ["RATE_LIMIT"],
|
|
1881
|
+
meta
|
|
1882
|
+
};
|
|
1883
|
+
},
|
|
1884
|
+
flag(scoreDelta, reasons, meta) {
|
|
1885
|
+
return {
|
|
1886
|
+
decision: "FLAG" /* FLAG */,
|
|
1887
|
+
allow: true,
|
|
1888
|
+
riskScore: scoreDelta,
|
|
1889
|
+
scoreDelta,
|
|
1890
|
+
reasons,
|
|
1891
|
+
meta
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
};
|
|
1895
|
+
}
|
|
1896
|
+
});
|
|
1897
|
+
|
|
1898
|
+
// src/cce/cce.types.ts
|
|
1899
|
+
var CCE_PROTOCOL_VERSION, CCE_DERIVATION, CCE_AES_KEY_BYTES, CCE_IV_BYTES, CCE_NONCE_BYTES, CCE_ERROR, CceError;
|
|
1900
|
+
var init_cce_types = __esm({
|
|
1901
|
+
"src/cce/cce.types.ts"() {
|
|
1902
|
+
CCE_PROTOCOL_VERSION = "cce-v1";
|
|
1903
|
+
CCE_DERIVATION = {
|
|
1904
|
+
/** Request execution context */
|
|
1905
|
+
REQUEST: "axis:cce:req:v1",
|
|
1906
|
+
/** Response execution context */
|
|
1907
|
+
RESPONSE: "axis:cce:resp:v1",
|
|
1908
|
+
/** Witness binding context */
|
|
1909
|
+
WITNESS: "axis:cce:witness:v1"
|
|
1910
|
+
};
|
|
1911
|
+
CCE_AES_KEY_BYTES = 32;
|
|
1912
|
+
CCE_IV_BYTES = 12;
|
|
1913
|
+
CCE_NONCE_BYTES = 32;
|
|
1914
|
+
CCE_ERROR = {
|
|
1915
|
+
// Envelope errors
|
|
1916
|
+
INVALID_ENVELOPE: "CCE_INVALID_ENVELOPE",
|
|
1917
|
+
UNSUPPORTED_VERSION: "CCE_UNSUPPORTED_VERSION",
|
|
1918
|
+
MISSING_CAPSULE: "CCE_MISSING_CAPSULE",
|
|
1919
|
+
MISSING_ENCRYPTED_KEY: "CCE_MISSING_ENCRYPTED_KEY",
|
|
1920
|
+
// Signature errors
|
|
1921
|
+
CLIENT_SIG_INVALID: "CCE_CLIENT_SIG_INVALID",
|
|
1922
|
+
CLIENT_KEY_NOT_FOUND: "CCE_CLIENT_KEY_NOT_FOUND",
|
|
1923
|
+
// Capsule errors
|
|
1924
|
+
CAPSULE_SIG_INVALID: "CCE_CAPSULE_SIG_INVALID",
|
|
1925
|
+
CAPSULE_EXPIRED: "CCE_CAPSULE_EXPIRED",
|
|
1926
|
+
CAPSULE_NOT_YET_VALID: "CCE_CAPSULE_NOT_YET_VALID",
|
|
1927
|
+
CAPSULE_REVOKED: "CCE_CAPSULE_REVOKED",
|
|
1928
|
+
CAPSULE_CONSUMED: "CCE_CAPSULE_CONSUMED",
|
|
1929
|
+
CAPSULE_NOT_VERIFIED: "CCE_CAPSULE_NOT_VERIFIED",
|
|
1930
|
+
// Binding errors
|
|
1931
|
+
AUDIENCE_MISMATCH: "CCE_AUDIENCE_MISMATCH",
|
|
1932
|
+
INTENT_MISMATCH: "CCE_INTENT_MISMATCH",
|
|
1933
|
+
TPS_WINDOW_EXPIRED: "CCE_TPS_WINDOW_EXPIRED",
|
|
1934
|
+
TPS_WINDOW_FUTURE: "CCE_TPS_WINDOW_FUTURE",
|
|
1935
|
+
// Replay / nonce errors
|
|
1936
|
+
REPLAY_DETECTED: "CCE_REPLAY_DETECTED",
|
|
1937
|
+
NONCE_REUSED: "CCE_NONCE_REUSED",
|
|
1938
|
+
// Decryption errors
|
|
1939
|
+
DECRYPTION_FAILED: "CCE_DECRYPTION_FAILED",
|
|
1940
|
+
KEY_UNWRAP_FAILED: "CCE_KEY_UNWRAP_FAILED",
|
|
1941
|
+
AEAD_TAG_MISMATCH: "CCE_AEAD_TAG_MISMATCH",
|
|
1942
|
+
PAYLOAD_TOO_LARGE: "CCE_PAYLOAD_TOO_LARGE",
|
|
1943
|
+
// Schema / validation errors
|
|
1944
|
+
PAYLOAD_SCHEMA_INVALID: "CCE_PAYLOAD_SCHEMA_INVALID",
|
|
1945
|
+
INTENT_SCHEMA_MISMATCH: "CCE_INTENT_SCHEMA_MISMATCH",
|
|
1946
|
+
// Policy errors
|
|
1947
|
+
POLICY_DENIED: "CCE_POLICY_DENIED",
|
|
1948
|
+
CONSTRAINT_VIOLATED: "CCE_CONSTRAINT_VIOLATED",
|
|
1949
|
+
// Handler errors
|
|
1950
|
+
HANDLER_NOT_FOUND: "CCE_HANDLER_NOT_FOUND",
|
|
1951
|
+
HANDLER_EXECUTION_FAILED: "CCE_HANDLER_EXECUTION_FAILED",
|
|
1952
|
+
HANDLER_TIMEOUT: "CCE_HANDLER_TIMEOUT",
|
|
1953
|
+
// Response errors
|
|
1954
|
+
RESPONSE_ENCRYPTION_FAILED: "CCE_RESPONSE_ENCRYPTION_FAILED"
|
|
1955
|
+
};
|
|
1956
|
+
CceError = class extends Error {
|
|
1957
|
+
constructor(code, message, metadata) {
|
|
1958
|
+
super(`[${code}] ${message}`);
|
|
1959
|
+
this.code = code;
|
|
1960
|
+
this.metadata = metadata;
|
|
1961
|
+
this.name = "CceError";
|
|
1962
|
+
}
|
|
1963
|
+
/** Whether this error is safe to expose to the client */
|
|
1964
|
+
get clientSafe() {
|
|
1965
|
+
const internal = [
|
|
1966
|
+
CCE_ERROR.DECRYPTION_FAILED,
|
|
1967
|
+
CCE_ERROR.KEY_UNWRAP_FAILED,
|
|
1968
|
+
CCE_ERROR.AEAD_TAG_MISMATCH,
|
|
1969
|
+
CCE_ERROR.HANDLER_EXECUTION_FAILED,
|
|
1970
|
+
CCE_ERROR.RESPONSE_ENCRYPTION_FAILED
|
|
1971
|
+
];
|
|
1972
|
+
return !internal.includes(this.code);
|
|
1973
|
+
}
|
|
1974
|
+
/** Get client-safe representation */
|
|
1975
|
+
toClientError() {
|
|
1976
|
+
if (this.clientSafe) {
|
|
1977
|
+
return { code: this.code, message: this.message };
|
|
1978
|
+
}
|
|
1979
|
+
return {
|
|
1980
|
+
code: CCE_ERROR.DECRYPTION_FAILED,
|
|
1981
|
+
message: "Request processing failed"
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
};
|
|
1985
|
+
}
|
|
1986
|
+
});
|
|
1987
|
+
|
|
1988
|
+
// src/cce/cce-derivation.service.ts
|
|
1989
|
+
import { bytesToHex, hexToBytes } from "@noble/hashes/utils.js";
|
|
1990
|
+
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
1991
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
1992
|
+
function buildSalt(capsuleId, capsuleNonce, requestNonce) {
|
|
1993
|
+
const encoder = new TextEncoder();
|
|
1994
|
+
const data = encoder.encode(
|
|
1995
|
+
capsuleId + "|" + capsuleNonce + "|" + requestNonce
|
|
1996
|
+
);
|
|
1997
|
+
return sha256(data);
|
|
1998
|
+
}
|
|
1999
|
+
function buildInfo(contextPrefix, capsule, extraNonce) {
|
|
2000
|
+
const encoder = new TextEncoder();
|
|
2001
|
+
const parts = [
|
|
2002
|
+
contextPrefix,
|
|
2003
|
+
capsule.sub,
|
|
2004
|
+
capsule.kid,
|
|
2005
|
+
capsule.intent,
|
|
2006
|
+
capsule.aud,
|
|
2007
|
+
String(capsule.tps_from),
|
|
2008
|
+
String(capsule.tps_to),
|
|
2009
|
+
capsule.policy_hash ?? "",
|
|
2010
|
+
capsule.ver
|
|
2011
|
+
];
|
|
2012
|
+
if (extraNonce) {
|
|
2013
|
+
parts.push(extraNonce);
|
|
2014
|
+
}
|
|
2015
|
+
return encoder.encode(parts.join("|"));
|
|
2016
|
+
}
|
|
2017
|
+
function deriveRequestExecutionKey(input) {
|
|
2018
|
+
const ikm = hexToBytes(input.axisLocalSecret);
|
|
2019
|
+
const salt = buildSalt(
|
|
2020
|
+
input.capsule.capsule_id,
|
|
2021
|
+
input.capsule.capsule_nonce,
|
|
2022
|
+
input.requestNonce
|
|
2023
|
+
);
|
|
2024
|
+
const info = buildInfo(CCE_DERIVATION.REQUEST, input.capsule);
|
|
2025
|
+
return hkdf(sha256, ikm, salt, info, CCE_AES_KEY_BYTES);
|
|
2026
|
+
}
|
|
2027
|
+
function buildExecutionContext(input, requestId) {
|
|
2028
|
+
const executionKey = deriveRequestExecutionKey(input);
|
|
2029
|
+
const keyHash = bytesToHex(sha256(executionKey));
|
|
2030
|
+
executionKey.fill(0);
|
|
2031
|
+
return {
|
|
2032
|
+
execution_key_hash: keyHash,
|
|
2033
|
+
request_id: requestId,
|
|
2034
|
+
capsule_id: input.capsule.capsule_id,
|
|
2035
|
+
sub: input.capsule.sub,
|
|
2036
|
+
kid: input.capsule.kid,
|
|
2037
|
+
intent: input.capsule.intent,
|
|
2038
|
+
aud: input.capsule.aud,
|
|
2039
|
+
tps_from: input.capsule.tps_from,
|
|
2040
|
+
tps_to: input.capsule.tps_to,
|
|
2041
|
+
policy_hash: input.capsule.policy_hash,
|
|
2042
|
+
derived_at: Math.floor(Date.now() / 1e3),
|
|
2043
|
+
valid: true
|
|
2044
|
+
};
|
|
2045
|
+
}
|
|
2046
|
+
var init_cce_derivation_service = __esm({
|
|
2047
|
+
"src/cce/cce-derivation.service.ts"() {
|
|
2048
|
+
init_cce_types();
|
|
2049
|
+
}
|
|
2050
|
+
});
|
|
2051
|
+
|
|
2052
|
+
// src/cce/cce-crypto.ts
|
|
2053
|
+
import { bytesToHex as bytesToHex2 } from "@noble/hashes/utils.js";
|
|
2054
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha2.js";
|
|
2055
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
2056
|
+
function aesGcmEncrypt(key, plaintext, aad) {
|
|
2057
|
+
if (key.length !== CCE_AES_KEY_BYTES) {
|
|
2058
|
+
throw new Error(`AES key must be ${CCE_AES_KEY_BYTES} bytes`);
|
|
2059
|
+
}
|
|
2060
|
+
const iv = randomBytes(CCE_IV_BYTES);
|
|
2061
|
+
const cipher = createCipheriv("aes-256-gcm", key, iv);
|
|
2062
|
+
if (aad) {
|
|
2063
|
+
cipher.setAAD(aad);
|
|
2064
|
+
}
|
|
2065
|
+
const encrypted = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
2066
|
+
const tag = cipher.getAuthTag();
|
|
2067
|
+
return {
|
|
2068
|
+
iv: new Uint8Array(iv),
|
|
2069
|
+
ciphertext: new Uint8Array(encrypted),
|
|
2070
|
+
tag: new Uint8Array(tag)
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
function generateAesKey() {
|
|
2074
|
+
return new Uint8Array(randomBytes(CCE_AES_KEY_BYTES));
|
|
2075
|
+
}
|
|
2076
|
+
function base64UrlEncode(bytes2) {
|
|
2077
|
+
return Buffer.from(bytes2).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
2078
|
+
}
|
|
2079
|
+
function hashPayload(payload) {
|
|
2080
|
+
return bytesToHex2(sha2562(payload));
|
|
2081
|
+
}
|
|
2082
|
+
var init_cce_crypto = __esm({
|
|
2083
|
+
"src/cce/cce-crypto.ts"() {
|
|
2084
|
+
init_cce_types();
|
|
2085
|
+
}
|
|
2086
|
+
});
|
|
2087
|
+
|
|
2088
|
+
// src/cce/cce-response.service.ts
|
|
2089
|
+
import { bytesToHex as bytesToHex3 } from "@noble/hashes/utils.js";
|
|
2090
|
+
import { randomBytes as randomBytes2 } from "crypto";
|
|
1815
2091
|
async function buildCceResponse(options, clientKeyEncryptor, axisSigner) {
|
|
1816
2092
|
const { request, capsule, status, body, clientPublicKeyHex, witnessRef } = options;
|
|
1817
2093
|
const responseNonce = bytesToHex3(
|
|
@@ -1984,124 +2260,20 @@ function computeExecutionContextHash(axisLocalSecret, capsule, requestNonce) {
|
|
|
1984
2260
|
);
|
|
1985
2261
|
const witnessKey = hkdf2(sha2563, ikm, salt, info, 32);
|
|
1986
2262
|
const hash = bytesToHex4(sha2563(witnessKey));
|
|
1987
|
-
witnessKey.fill(0);
|
|
1988
|
-
return hash;
|
|
1989
|
-
}
|
|
1990
|
-
function hexToBytes2(hex) {
|
|
1991
|
-
const bytes2 = new Uint8Array(hex.length / 2);
|
|
1992
|
-
for (let i = 0; i < bytes2.length; i++) {
|
|
1993
|
-
bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
1994
|
-
}
|
|
1995
|
-
return bytes2;
|
|
1996
|
-
}
|
|
1997
|
-
var init_cce_witness_observer = __esm({
|
|
1998
|
-
"src/cce/cce-witness.observer.ts"() {
|
|
1999
|
-
init_cce_crypto();
|
|
2000
|
-
init_cce_types();
|
|
2001
|
-
}
|
|
2002
|
-
});
|
|
2003
|
-
|
|
2004
|
-
// src/sensor/axis-sensor.ts
|
|
2005
|
-
function normalizeSensorDecision(sensorDecision) {
|
|
2006
|
-
if ("action" in sensorDecision) {
|
|
2007
|
-
switch (sensorDecision.action) {
|
|
2008
|
-
case "ALLOW":
|
|
2009
|
-
return {
|
|
2010
|
-
allow: true,
|
|
2011
|
-
riskScore: 0,
|
|
2012
|
-
reasons: [],
|
|
2013
|
-
meta: sensorDecision.meta
|
|
2014
|
-
};
|
|
2015
|
-
case "DENY":
|
|
2016
|
-
return {
|
|
2017
|
-
allow: false,
|
|
2018
|
-
riskScore: 100,
|
|
2019
|
-
reasons: [sensorDecision.code, sensorDecision.reason].filter(
|
|
2020
|
-
Boolean
|
|
2021
|
-
),
|
|
2022
|
-
meta: sensorDecision.meta,
|
|
2023
|
-
retryAfterMs: sensorDecision.retryAfterMs
|
|
2024
|
-
};
|
|
2025
|
-
case "THROTTLE":
|
|
2026
|
-
return {
|
|
2027
|
-
allow: false,
|
|
2028
|
-
riskScore: 50,
|
|
2029
|
-
reasons: ["RATE_LIMIT"],
|
|
2030
|
-
retryAfterMs: sensorDecision.retryAfterMs,
|
|
2031
|
-
meta: sensorDecision.meta
|
|
2032
|
-
};
|
|
2033
|
-
case "FLAG":
|
|
2034
|
-
return {
|
|
2035
|
-
allow: true,
|
|
2036
|
-
riskScore: sensorDecision.scoreDelta,
|
|
2037
|
-
reasons: sensorDecision.reasons,
|
|
2038
|
-
meta: sensorDecision.meta
|
|
2039
|
-
};
|
|
2040
|
-
}
|
|
2041
|
-
}
|
|
2042
|
-
return {
|
|
2043
|
-
allow: sensorDecision.allow,
|
|
2044
|
-
riskScore: sensorDecision.riskScore,
|
|
2045
|
-
reasons: sensorDecision.reasons,
|
|
2046
|
-
tags: sensorDecision.tags,
|
|
2047
|
-
meta: sensorDecision.meta,
|
|
2048
|
-
tighten: sensorDecision.tighten,
|
|
2049
|
-
retryAfterMs: sensorDecision.retryAfterMs
|
|
2050
|
-
};
|
|
2263
|
+
witnessKey.fill(0);
|
|
2264
|
+
return hash;
|
|
2051
2265
|
}
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
allow(meta, tags) {
|
|
2064
|
-
return {
|
|
2065
|
-
decision: "ALLOW" /* ALLOW */,
|
|
2066
|
-
allow: true,
|
|
2067
|
-
riskScore: 0,
|
|
2068
|
-
reasons: [],
|
|
2069
|
-
tags,
|
|
2070
|
-
meta
|
|
2071
|
-
};
|
|
2072
|
-
},
|
|
2073
|
-
deny(code, reason, meta) {
|
|
2074
|
-
return {
|
|
2075
|
-
decision: "DENY" /* DENY */,
|
|
2076
|
-
allow: false,
|
|
2077
|
-
riskScore: 100,
|
|
2078
|
-
code,
|
|
2079
|
-
reasons: [code, reason].filter(Boolean),
|
|
2080
|
-
meta
|
|
2081
|
-
};
|
|
2082
|
-
},
|
|
2083
|
-
throttle(retryAfterMs, meta) {
|
|
2084
|
-
return {
|
|
2085
|
-
decision: "THROTTLE" /* THROTTLE */,
|
|
2086
|
-
allow: false,
|
|
2087
|
-
riskScore: 50,
|
|
2088
|
-
retryAfterMs,
|
|
2089
|
-
code: "RATE_LIMIT",
|
|
2090
|
-
reasons: ["RATE_LIMIT"],
|
|
2091
|
-
meta
|
|
2092
|
-
};
|
|
2093
|
-
},
|
|
2094
|
-
flag(scoreDelta, reasons, meta) {
|
|
2095
|
-
return {
|
|
2096
|
-
decision: "FLAG" /* FLAG */,
|
|
2097
|
-
allow: true,
|
|
2098
|
-
riskScore: scoreDelta,
|
|
2099
|
-
scoreDelta,
|
|
2100
|
-
reasons,
|
|
2101
|
-
meta
|
|
2102
|
-
};
|
|
2103
|
-
}
|
|
2104
|
-
};
|
|
2266
|
+
function hexToBytes2(hex) {
|
|
2267
|
+
const bytes2 = new Uint8Array(hex.length / 2);
|
|
2268
|
+
for (let i = 0; i < bytes2.length; i++) {
|
|
2269
|
+
bytes2[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
|
|
2270
|
+
}
|
|
2271
|
+
return bytes2;
|
|
2272
|
+
}
|
|
2273
|
+
var init_cce_witness_observer = __esm({
|
|
2274
|
+
"src/cce/cce-witness.observer.ts"() {
|
|
2275
|
+
init_cce_crypto();
|
|
2276
|
+
init_cce_types();
|
|
2105
2277
|
}
|
|
2106
2278
|
});
|
|
2107
2279
|
|
|
@@ -2353,167 +2525,6 @@ var init_axis_error = __esm({
|
|
|
2353
2525
|
}
|
|
2354
2526
|
});
|
|
2355
2527
|
|
|
2356
|
-
// src/security/scopes.ts
|
|
2357
|
-
function hasScope(scopes, required) {
|
|
2358
|
-
if (!Array.isArray(scopes) || scopes.length === 0) {
|
|
2359
|
-
return false;
|
|
2360
|
-
}
|
|
2361
|
-
if (scopes.includes(required)) {
|
|
2362
|
-
return true;
|
|
2363
|
-
}
|
|
2364
|
-
const [resource, id] = required.split(":");
|
|
2365
|
-
if (resource && id) {
|
|
2366
|
-
const wildcard = `${resource}:*`;
|
|
2367
|
-
if (scopes.includes(wildcard)) {
|
|
2368
|
-
return true;
|
|
2369
|
-
}
|
|
2370
|
-
}
|
|
2371
|
-
return false;
|
|
2372
|
-
}
|
|
2373
|
-
function parseScope(scope) {
|
|
2374
|
-
const parts = scope.split(":");
|
|
2375
|
-
if (parts.length !== 2) return null;
|
|
2376
|
-
return { resource: parts[0], id: parts[1] };
|
|
2377
|
-
}
|
|
2378
|
-
function canAccessResource(scopes, resourceType, resourceId) {
|
|
2379
|
-
const required = `${resourceType}:${resourceId}`;
|
|
2380
|
-
return hasScope(scopes, required);
|
|
2381
|
-
}
|
|
2382
|
-
var init_scopes = __esm({
|
|
2383
|
-
"src/security/scopes.ts"() {
|
|
2384
|
-
}
|
|
2385
|
-
});
|
|
2386
|
-
|
|
2387
|
-
// src/security/inline-capsule.ts
|
|
2388
|
-
function normalizeInlineCapsule(input) {
|
|
2389
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) {
|
|
2390
|
-
return null;
|
|
2391
|
-
}
|
|
2392
|
-
const raw = input;
|
|
2393
|
-
const scopes = normalizeStringList(raw.scopes ?? raw.scope);
|
|
2394
|
-
return {
|
|
2395
|
-
id: normalizeScalar(raw.id),
|
|
2396
|
-
actorId: normalizeScalar(raw.actorId),
|
|
2397
|
-
intents: normalizeStringList(raw.intents),
|
|
2398
|
-
issuedAt: normalizeTimestamp(raw.issuedAt ?? raw.iat),
|
|
2399
|
-
expiresAt: normalizeTimestamp(raw.expiresAt ?? raw.exp),
|
|
2400
|
-
realm: normalizeScalar(raw.realm),
|
|
2401
|
-
node: normalizeScalar(raw.node),
|
|
2402
|
-
scopes,
|
|
2403
|
-
raw
|
|
2404
|
-
};
|
|
2405
|
-
}
|
|
2406
|
-
function inlineCapsuleAllowsIntent(capsule, intent) {
|
|
2407
|
-
if (!capsule.intents || capsule.intents.length === 0) {
|
|
2408
|
-
return false;
|
|
2409
|
-
}
|
|
2410
|
-
for (const pattern of capsule.intents) {
|
|
2411
|
-
if (pattern === "*" || pattern === intent) {
|
|
2412
|
-
return true;
|
|
2413
|
-
}
|
|
2414
|
-
if (pattern.endsWith(".*")) {
|
|
2415
|
-
const prefix = pattern.slice(0, -1);
|
|
2416
|
-
if (intent.startsWith(prefix)) {
|
|
2417
|
-
return true;
|
|
2418
|
-
}
|
|
2419
|
-
}
|
|
2420
|
-
}
|
|
2421
|
-
return false;
|
|
2422
|
-
}
|
|
2423
|
-
function isInlineCapsuleExpired(capsule, clockSkewMs = 3e4) {
|
|
2424
|
-
if (capsule.expiresAt === void 0) {
|
|
2425
|
-
return false;
|
|
2426
|
-
}
|
|
2427
|
-
return BigInt(Date.now()) > capsule.expiresAt + BigInt(clockSkewMs);
|
|
2428
|
-
}
|
|
2429
|
-
function resolvePolicyScopes(scopes, context) {
|
|
2430
|
-
return scopes.map(
|
|
2431
|
-
(scope) => scope.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
|
|
2432
|
-
const resolved = resolveTemplateExpression(expression.trim(), context);
|
|
2433
|
-
if (resolved === void 0 || resolved === null || resolved === "") {
|
|
2434
|
-
throw new Error(`CAPSULE_SCOPE_TEMPLATE_UNRESOLVED:${expression}`);
|
|
2435
|
-
}
|
|
2436
|
-
return String(resolved);
|
|
2437
|
-
})
|
|
2438
|
-
);
|
|
2439
|
-
}
|
|
2440
|
-
function inlineCapsuleSatisfiesScopes(capsule, requiredScopes, mode = "all") {
|
|
2441
|
-
if (!capsule.scopes || capsule.scopes.length === 0) {
|
|
2442
|
-
return false;
|
|
2443
|
-
}
|
|
2444
|
-
if (mode === "any") {
|
|
2445
|
-
return requiredScopes.some((scope) => hasScope(capsule.scopes, scope));
|
|
2446
|
-
}
|
|
2447
|
-
return requiredScopes.every((scope) => hasScope(capsule.scopes, scope));
|
|
2448
|
-
}
|
|
2449
|
-
function resolveTemplateExpression(expression, context) {
|
|
2450
|
-
if (expression === "intent") {
|
|
2451
|
-
return context.intent;
|
|
2452
|
-
}
|
|
2453
|
-
if (expression === "actorId") {
|
|
2454
|
-
return context.actorId;
|
|
2455
|
-
}
|
|
2456
|
-
if (expression === "chainId") {
|
|
2457
|
-
return context.chainId;
|
|
2458
|
-
}
|
|
2459
|
-
if (expression === "stepId") {
|
|
2460
|
-
return context.stepId;
|
|
2461
|
-
}
|
|
2462
|
-
if (expression.startsWith("body.")) {
|
|
2463
|
-
return getNestedValue(context.body, expression.slice(5));
|
|
2464
|
-
}
|
|
2465
|
-
return void 0;
|
|
2466
|
-
}
|
|
2467
|
-
function getNestedValue(value, path2) {
|
|
2468
|
-
if (!value || typeof value !== "object") {
|
|
2469
|
-
return void 0;
|
|
2470
|
-
}
|
|
2471
|
-
return path2.split(".").reduce((current, segment) => {
|
|
2472
|
-
if (!current || typeof current !== "object") {
|
|
2473
|
-
return void 0;
|
|
2474
|
-
}
|
|
2475
|
-
return current[segment];
|
|
2476
|
-
}, value);
|
|
2477
|
-
}
|
|
2478
|
-
function normalizeScalar(value) {
|
|
2479
|
-
if (typeof value === "string") {
|
|
2480
|
-
return value;
|
|
2481
|
-
}
|
|
2482
|
-
if (value instanceof Uint8Array) {
|
|
2483
|
-
return Buffer.from(value).toString("hex");
|
|
2484
|
-
}
|
|
2485
|
-
return void 0;
|
|
2486
|
-
}
|
|
2487
|
-
function normalizeStringList(value) {
|
|
2488
|
-
if (!value) {
|
|
2489
|
-
return void 0;
|
|
2490
|
-
}
|
|
2491
|
-
const list = Array.isArray(value) ? value : [value];
|
|
2492
|
-
const normalized = list.map((entry) => typeof entry === "string" ? entry : void 0).filter((entry) => !!entry && entry.trim().length > 0);
|
|
2493
|
-
return normalized.length > 0 ? Array.from(new Set(normalized)) : void 0;
|
|
2494
|
-
}
|
|
2495
|
-
function normalizeTimestamp(value) {
|
|
2496
|
-
if (typeof value === "bigint") {
|
|
2497
|
-
return value;
|
|
2498
|
-
}
|
|
2499
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2500
|
-
return BigInt(Math.trunc(value));
|
|
2501
|
-
}
|
|
2502
|
-
if (typeof value === "string" && value.trim().length > 0) {
|
|
2503
|
-
try {
|
|
2504
|
-
return BigInt(value);
|
|
2505
|
-
} catch {
|
|
2506
|
-
return void 0;
|
|
2507
|
-
}
|
|
2508
|
-
}
|
|
2509
|
-
return void 0;
|
|
2510
|
-
}
|
|
2511
|
-
var init_inline_capsule = __esm({
|
|
2512
|
-
"src/security/inline-capsule.ts"() {
|
|
2513
|
-
init_scopes();
|
|
2514
|
-
}
|
|
2515
|
-
});
|
|
2516
|
-
|
|
2517
2528
|
// src/engine/intent.router.ts
|
|
2518
2529
|
var intent_router_exports = {};
|
|
2519
2530
|
__export(intent_router_exports, {
|
|
@@ -2590,23 +2601,23 @@ function normalizeChainConfig(decoratorConfig, intentConfig) {
|
|
|
2590
2601
|
var import_dto_schema, _IntentRouter, IntentRouter;
|
|
2591
2602
|
var init_intent_router = __esm({
|
|
2592
2603
|
"src/engine/intent.router.ts"() {
|
|
2593
|
-
init_cce_pipeline();
|
|
2594
|
-
init_axis_error();
|
|
2595
|
-
init_constants();
|
|
2596
|
-
init_capsule_policy_decorator();
|
|
2597
|
-
init_chain_decorator();
|
|
2598
|
-
import_dto_schema = __toESM(require_dto_schema_util());
|
|
2599
2604
|
init_handler_sensors_decorator();
|
|
2600
|
-
|
|
2601
|
-
init_intent_body_decorator();
|
|
2602
|
-
init_intent_policy_decorator();
|
|
2605
|
+
init_capsule_policy_decorator();
|
|
2603
2606
|
init_intent_sensors_decorator();
|
|
2604
|
-
|
|
2607
|
+
init_intent_policy_decorator();
|
|
2608
|
+
init_intent_body_decorator();
|
|
2605
2609
|
init_observer_decorator();
|
|
2610
|
+
init_handler_decorator();
|
|
2611
|
+
init_intent_decorator();
|
|
2612
|
+
init_chain_decorator();
|
|
2613
|
+
import_dto_schema = __toESM(require_dto_schema_util());
|
|
2606
2614
|
init_inline_capsule();
|
|
2607
|
-
init_axis_sensor();
|
|
2608
2615
|
init_axis_execution_context();
|
|
2616
|
+
init_axis_sensor();
|
|
2609
2617
|
init_axis_logger();
|
|
2618
|
+
init_cce_pipeline();
|
|
2619
|
+
init_axis_error();
|
|
2620
|
+
init_constants();
|
|
2610
2621
|
_IntentRouter = class _IntentRouter {
|
|
2611
2622
|
constructor(dependencyResolver, observerDispatcher, sensorRegistry) {
|
|
2612
2623
|
this.logger = createAxisLogger(_IntentRouter.name);
|
|
@@ -2642,6 +2653,8 @@ var init_intent_router = __esm({
|
|
|
2642
2653
|
this.publicIntents = /* @__PURE__ */ new Set();
|
|
2643
2654
|
/** Intents flagged as anonymous-session accessible */
|
|
2644
2655
|
this.anonymousIntents = /* @__PURE__ */ new Set();
|
|
2656
|
+
/** Intents flagged as authorized-session accessible */
|
|
2657
|
+
this.authorizedIntents = /* @__PURE__ */ new Set();
|
|
2645
2658
|
/** Per-intent rate limit config */
|
|
2646
2659
|
this.intentRateLimits = /* @__PURE__ */ new Map();
|
|
2647
2660
|
/** CCE handler registry */
|
|
@@ -3068,6 +3081,18 @@ var init_intent_router = __esm({
|
|
|
3068
3081
|
if (isAnonMethod || isAnonClass) {
|
|
3069
3082
|
this.anonymousIntents.add(intent);
|
|
3070
3083
|
}
|
|
3084
|
+
const isAuthorizedMethod = Reflect.getMetadata(
|
|
3085
|
+
AXIS_AUTHORIZED_KEY,
|
|
3086
|
+
proto,
|
|
3087
|
+
methodName
|
|
3088
|
+
);
|
|
3089
|
+
const isAuthorizedClass = Reflect.getMetadata(
|
|
3090
|
+
AXIS_AUTHORIZED_KEY,
|
|
3091
|
+
proto.constructor
|
|
3092
|
+
);
|
|
3093
|
+
if (isAuthorizedMethod || isAuthorizedClass) {
|
|
3094
|
+
this.authorizedIntents.add(intent);
|
|
3095
|
+
}
|
|
3071
3096
|
const rateLimit = Reflect.getMetadata(
|
|
3072
3097
|
AXIS_RATE_LIMIT_KEY,
|
|
3073
3098
|
proto,
|
|
@@ -3093,6 +3118,9 @@ var init_intent_router = __esm({
|
|
|
3093
3118
|
isAnonymous(intent) {
|
|
3094
3119
|
return this.anonymousIntents.has(intent);
|
|
3095
3120
|
}
|
|
3121
|
+
isAuthorized(intent) {
|
|
3122
|
+
return this.authorizedIntents.has(intent);
|
|
3123
|
+
}
|
|
3096
3124
|
getRateLimit(intent) {
|
|
3097
3125
|
return this.intentRateLimits.get(intent);
|
|
3098
3126
|
}
|
|
@@ -10597,6 +10625,7 @@ __export(index_exports, {
|
|
|
10597
10625
|
ATS1_HDR: () => ATS1_HDR,
|
|
10598
10626
|
ATS1_SCHEMA: () => ATS1_SCHEMA,
|
|
10599
10627
|
AXIS_ANONYMOUS_KEY: () => AXIS_ANONYMOUS_KEY,
|
|
10628
|
+
AXIS_AUTHORIZED_KEY: () => AXIS_AUTHORIZED_KEY,
|
|
10600
10629
|
AXIS_EXECUTION_CONTEXT_KEY: () => AXIS_EXECUTION_CONTEXT_KEY,
|
|
10601
10630
|
AXIS_MAGIC: () => AXIS_MAGIC,
|
|
10602
10631
|
AXIS_META_KEY: () => AXIS_META_KEY,
|
|
@@ -10610,6 +10639,7 @@ __export(index_exports, {
|
|
|
10610
10639
|
Ats1Codec: () => ats1_exports,
|
|
10611
10640
|
Axis: () => Axis,
|
|
10612
10641
|
AxisAnonymous: () => AxisAnonymous,
|
|
10642
|
+
AxisAuthorized: () => AxisAuthorized,
|
|
10613
10643
|
AxisChainExecutor: () => AxisChainExecutor,
|
|
10614
10644
|
AxisError: () => AxisError,
|
|
10615
10645
|
AxisFrameZ: () => AxisFrameZ,
|