@axorum/client 0.0.0-stage → 1.1.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/LICENSE +202 -0
- package/README.md +537 -2
- package/dist/agent-uri.d.ts +33 -0
- package/dist/agent-uri.d.ts.map +1 -0
- package/dist/agent-uri.js +231 -0
- package/dist/agent-uri.js.map +1 -0
- package/dist/authorize.d.ts +671 -0
- package/dist/authorize.d.ts.map +1 -0
- package/dist/authorize.js +947 -0
- package/dist/authorize.js.map +1 -0
- package/dist/capabilities.d.ts +30 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +40 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/chart.d.ts +74 -0
- package/dist/chart.d.ts.map +1 -0
- package/dist/chart.js +107 -0
- package/dist/chart.js.map +1 -0
- package/dist/client.d.ts +645 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +1303 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +646 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +928 -0
- package/dist/errors.js.map +1 -0
- package/dist/failover.d.ts +197 -0
- package/dist/failover.d.ts.map +1 -0
- package/dist/failover.js +289 -0
- package/dist/failover.js.map +1 -0
- package/dist/freshness.d.ts +65 -0
- package/dist/freshness.d.ts.map +1 -0
- package/dist/freshness.js +148 -0
- package/dist/freshness.js.map +1 -0
- package/dist/generated/agent-plane.d.ts +1865 -0
- package/dist/generated/agent-plane.d.ts.map +1 -0
- package/dist/generated/agent-plane.js +19 -0
- package/dist/generated/agent-plane.js.map +1 -0
- package/dist/idempotency.d.ts +160 -0
- package/dist/idempotency.d.ts.map +1 -0
- package/dist/idempotency.js +208 -0
- package/dist/idempotency.js.map +1 -0
- package/dist/index.d.ts +90 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/intent.d.ts +163 -0
- package/dist/intent.d.ts.map +1 -0
- package/dist/intent.js +82 -0
- package/dist/intent.js.map +1 -0
- package/dist/json.d.ts +49 -0
- package/dist/json.d.ts.map +1 -0
- package/dist/json.js +259 -0
- package/dist/json.js.map +1 -0
- package/dist/key.d.ts +64 -0
- package/dist/key.d.ts.map +1 -0
- package/dist/key.js +71 -0
- package/dist/key.js.map +1 -0
- package/dist/payment.d.ts +172 -0
- package/dist/payment.d.ts.map +1 -0
- package/dist/payment.js +178 -0
- package/dist/payment.js.map +1 -0
- package/dist/refusal.d.ts +121 -0
- package/dist/refusal.d.ts.map +1 -0
- package/dist/refusal.js +176 -0
- package/dist/refusal.js.map +1 -0
- package/dist/retry.d.ts +215 -0
- package/dist/retry.d.ts.map +1 -0
- package/dist/retry.js +297 -0
- package/dist/retry.js.map +1 -0
- package/dist/typeid.d.ts +64 -0
- package/dist/typeid.d.ts.map +1 -0
- package/dist/typeid.js +119 -0
- package/dist/typeid.js.map +1 -0
- package/dist/types.d.ts +245 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -3
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Whether an attestation will still be valid for as long as a submission may take.
|
|
3
|
+
*
|
|
4
|
+
* The service checks one thing about time: `now < exp`, with no leeway. A token that
|
|
5
|
+
* expires while a submission is being re-sent is refused on the late attempt, possibly
|
|
6
|
+
* after an earlier one committed. So `authorize` bounds each submission, every send and
|
|
7
|
+
* every wait between sends, by a deadline {@link ATTESTATION_CLOCK_ALLOWANCE_MS} before
|
|
8
|
+
* the token's `exp` ({@link submissionDeadline}); a wait that would reach it ends the
|
|
9
|
+
* re-sends. The call's own budget ({@link AUTHORIZE_DEADLINE_MS}) bounds the submission
|
|
10
|
+
* too: it ends at whichever of the two comes first. Before it sends, it checks that at
|
|
11
|
+
* least {@link ATTESTATION_MIN_REMAINING_MS} is left, and asks for a fresh token when less
|
|
12
|
+
* is.
|
|
13
|
+
*
|
|
14
|
+
* The payload is read, never verified: the signature is the service's to check.
|
|
15
|
+
*
|
|
16
|
+
* @packageDocumentation
|
|
17
|
+
*/
|
|
18
|
+
import { AUTHORIZE_DEADLINE_MS } from "./retry.js";
|
|
19
|
+
/**
|
|
20
|
+
* How long before a token's `exp` a submission stops sending: room for the clocks of
|
|
21
|
+
* the issuer, this process and the service to disagree, since the service allows none.
|
|
22
|
+
*/
|
|
23
|
+
export const ATTESTATION_CLOCK_ALLOWANCE_MS = 30_000;
|
|
24
|
+
/**
|
|
25
|
+
* How long a token must still be valid when a submission starts (45 s): the whole
|
|
26
|
+
* {@link AUTHORIZE_DEADLINE_MS} plus the {@link ATTESTATION_CLOCK_ALLOWANCE_MS}. The
|
|
27
|
+
* submission's deadline is the earlier of the call's and the token's `exp` less the
|
|
28
|
+
* allowance ({@link submissionDeadline}), so a token that passes this check never cuts a
|
|
29
|
+
* submission shorter than the call's own budget does.
|
|
30
|
+
*/
|
|
31
|
+
export const ATTESTATION_MIN_REMAINING_MS = AUTHORIZE_DEADLINE_MS + ATTESTATION_CLOCK_ALLOWANCE_MS;
|
|
32
|
+
/**
|
|
33
|
+
* The deadline of a submission whose attestation expires at `expMs` (epoch
|
|
34
|
+
* milliseconds): `expMs` less {@link ATTESTATION_CLOCK_ALLOWANCE_MS}, read against the
|
|
35
|
+
* wall clock once (`wallNowMs`) and returned on the monotonic clock `monoNowMs` is read
|
|
36
|
+
* from, so a wall-clock step does not move it. `undefined` when that point has passed,
|
|
37
|
+
* and nothing may be sent. Pure.
|
|
38
|
+
*/
|
|
39
|
+
export function submissionDeadline(expMs, wallNowMs, monoNowMs) {
|
|
40
|
+
const left = expMs - ATTESTATION_CLOCK_ALLOWANCE_MS - wallNowMs;
|
|
41
|
+
return left > 0 ? monoNowMs + left : undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Why a token without a readable `exp` is refused here rather than sent: the service
|
|
45
|
+
* refuses it too. Its `agent-uri-attestation` declares `AttestationClaims.exp` a required
|
|
46
|
+
* date-time, so such a token fails to decode in `verify_for_uri` and is answered `403
|
|
47
|
+
* attestation` before its expiry is ever checked.
|
|
48
|
+
*/
|
|
49
|
+
const SERVICE_EXP_RULE = ", and the service refuses such a token: it reads exp as a required date-time " +
|
|
50
|
+
"(agent-uri-attestation's AttestationClaims.exp), so the token fails to decode before its " +
|
|
51
|
+
"expiry is ever checked. Its issuer must set one";
|
|
52
|
+
/**
|
|
53
|
+
* The token's `exp` in epoch milliseconds, or why its claims cannot be read. Pure; never
|
|
54
|
+
* verifies the signature.
|
|
55
|
+
*/
|
|
56
|
+
export function attestationExpiryMs(token) {
|
|
57
|
+
const claims = readClaims(token);
|
|
58
|
+
if (typeof claims === "string") {
|
|
59
|
+
return claims;
|
|
60
|
+
}
|
|
61
|
+
const exp = claims["exp"];
|
|
62
|
+
if (typeof exp !== "string") {
|
|
63
|
+
return `the attestation's claims carry no exp date-time${SERVICE_EXP_RULE}`;
|
|
64
|
+
}
|
|
65
|
+
return parseRfc3339Ms(exp) ?? `the attestation's exp is not an RFC 3339 date-time (${exp})${SERVICE_EXP_RULE}`;
|
|
66
|
+
}
|
|
67
|
+
/** The length of an Ed25519 signature, which ends every v4.public payload. */
|
|
68
|
+
const SIGNATURE_BYTES = 64;
|
|
69
|
+
/**
|
|
70
|
+
* Whether `token` is valid for at least `minRemainingMs` after `nowMs`, compared in whole
|
|
71
|
+
* milliseconds (digits of `exp` below a millisecond truncate). Pure; the same rule as the
|
|
72
|
+
* Rust SDK, pinned by `spec/fixtures/attestation-freshness-v1.json`.
|
|
73
|
+
*/
|
|
74
|
+
export function attestationFreshness(token, nowMs, minRemainingMs) {
|
|
75
|
+
const expMs = attestationExpiryMs(token);
|
|
76
|
+
if (typeof expMs === "string") {
|
|
77
|
+
return { state: "unreadable", problem: expMs };
|
|
78
|
+
}
|
|
79
|
+
const expiresAt = formatUtcMs(expMs);
|
|
80
|
+
return expMs - nowMs >= minRemainingMs ? { state: "fresh", expiresAt } : { state: "expiring", expiresAt };
|
|
81
|
+
}
|
|
82
|
+
/** The token's claims object, or why it cannot be read. Pure. */
|
|
83
|
+
function readClaims(token) {
|
|
84
|
+
const parts = token.split(".");
|
|
85
|
+
if (parts.length < 3 || parts.length > 4 || parts[0] !== "v4" || parts[1] !== "public") {
|
|
86
|
+
return "the attestation is not a PASETO v4.public token";
|
|
87
|
+
}
|
|
88
|
+
const payload = decodeBase64Url(parts[2]);
|
|
89
|
+
if (payload === undefined) {
|
|
90
|
+
return "the attestation's payload is not base64url";
|
|
91
|
+
}
|
|
92
|
+
if (payload.length <= SIGNATURE_BYTES) {
|
|
93
|
+
return "the attestation's payload is too short to carry claims and a signature";
|
|
94
|
+
}
|
|
95
|
+
let claims;
|
|
96
|
+
try {
|
|
97
|
+
claims = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(0, payload.length - SIGNATURE_BYTES)));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return "the attestation's claims are not JSON";
|
|
101
|
+
}
|
|
102
|
+
if (typeof claims !== "object" || claims === null || Array.isArray(claims)) {
|
|
103
|
+
return "the attestation's claims are not a JSON object";
|
|
104
|
+
}
|
|
105
|
+
return claims;
|
|
106
|
+
}
|
|
107
|
+
/** Unpadded base64url, strictly: the alphabet only, no padding, canonical length. Pure. */
|
|
108
|
+
function decodeBase64Url(text) {
|
|
109
|
+
if (text.length === 0 || text.length % 4 === 1 || !/^[A-Za-z0-9_-]+$/.test(text)) {
|
|
110
|
+
return undefined;
|
|
111
|
+
}
|
|
112
|
+
const standard = text.replaceAll("-", "+").replaceAll("_", "/");
|
|
113
|
+
const binary = atob(standard + "=".repeat((4 - (standard.length % 4)) % 4));
|
|
114
|
+
return Uint8Array.from(binary, (char) => char.charCodeAt(0));
|
|
115
|
+
}
|
|
116
|
+
const RFC3339 = /^(\d{4})-(\d{2})-(\d{2})[Tt ](\d{2}):(\d{2}):(\d{2})(?:\.(\d+))?(?:([Zz])|([+-])(\d{2}):(\d{2}))$/;
|
|
117
|
+
/** Milliseconds since the epoch for an RFC 3339 date-time, or `undefined`. Pure. */
|
|
118
|
+
export function parseRfc3339Ms(text) {
|
|
119
|
+
const match = RFC3339.exec(text);
|
|
120
|
+
if (match === null) {
|
|
121
|
+
return undefined;
|
|
122
|
+
}
|
|
123
|
+
const [year, month, day, hour, minute, second] = match.slice(1, 7).map(Number);
|
|
124
|
+
const leap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
|
|
125
|
+
const days = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31][month - 1];
|
|
126
|
+
if (days === undefined || day < 1 || day > days || hour > 23 || minute > 59 || second > 59) {
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
let offsetMinutes = 0;
|
|
130
|
+
if (match[9] !== undefined) {
|
|
131
|
+
const offsetHours = Number(match[10]);
|
|
132
|
+
const offsetMins = Number(match[11]);
|
|
133
|
+
if (offsetHours > 23 || offsetMins > 59) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
offsetMinutes = (match[9] === "-" ? -1 : 1) * (offsetHours * 60 + offsetMins);
|
|
137
|
+
}
|
|
138
|
+
const millis = Number((match[7] ?? "").padEnd(3, "0").slice(0, 3));
|
|
139
|
+
const date = new Date(0);
|
|
140
|
+
date.setUTCFullYear(year, month - 1, day);
|
|
141
|
+
date.setUTCHours(hour, minute, second, millis);
|
|
142
|
+
return date.getTime() - offsetMinutes * 60_000;
|
|
143
|
+
}
|
|
144
|
+
/** `YYYY-MM-DDTHH:MM:SS[.mmm]Z`, the milliseconds only when not zero. Pure. */
|
|
145
|
+
export function formatUtcMs(ms) {
|
|
146
|
+
return new Date(ms).toISOString().replace(".000Z", "Z");
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=freshness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freshness.js","sourceRoot":"","sources":["../src/freshness.ts"],"names":[],"mappings":"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"}
|