@tinycloud/courier 0.4.2-beta.2 → 0.5.0-beta.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/README.md +29 -9
- package/dist/commands.js +90 -5
- package/dist/commands.js.map +1 -1
- package/dist/errors.d.ts +20 -0
- package/dist/errors.js +14 -0
- package/dist/errors.js.map +1 -1
- package/dist/grant-refusal.d.ts +9 -0
- package/dist/grant-refusal.js +24 -0
- package/dist/grant-refusal.js.map +1 -0
- package/dist/grant-request.d.ts +85 -0
- package/dist/grant-request.js +436 -0
- package/dist/grant-request.js.map +1 -0
- package/dist/grant.d.ts +14 -1
- package/dist/grant.js +64 -11
- package/dist/grant.js.map +1 -1
- package/dist/main.d.ts +2 -1
- package/dist/main.js +21 -5
- package/dist/main.js.map +1 -1
- package/dist/profile.d.ts +2 -0
- package/dist/profile.js +16 -1
- package/dist/profile.js.map +1 -1
- package/package.json +4 -4
- package/skills/courier/SKILL.md +23 -3
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { ackApprovalResult, checkApprovalResultBinding, collectApprovalResult, createApprovalRequest, DEFAULT_LINKS_API_ORIGIN, discoverApprovalResult, generateRelayKey, isApprovalClientError, isLinkError, openRelayResult, signerFromJwk, } from '@tinycloud/share-envelope/links';
|
|
5
|
+
import { canonicalJson } from './canonical.js';
|
|
6
|
+
import { cmd } from './program.js';
|
|
7
|
+
import { CourierError } from './errors.js';
|
|
8
|
+
import { AGENT_GRANT, AGENT_GRANT_EXPIRY } from './keys.js';
|
|
9
|
+
import { profileDir, writeSecure } from './profile.js';
|
|
10
|
+
import { assertBoundToKey, installGrant, isClockRefusal, isPermanentRefusal, parseGrantPayload, resolveOpenKeyApiHost } from './grant.js';
|
|
11
|
+
import { withRefusalNotice } from './grant-refusal.js';
|
|
12
|
+
import { bareDid, CLOCK_SKEW_MS, durationMs, siweTimes } from './authority.js';
|
|
13
|
+
/**
|
|
14
|
+
* The OpenKey short-link approval flow (the same one `tc onboard` uses): `init --request` creates a sealed approval
|
|
15
|
+
* request at the links API and saves it here; `init --wait` polls OpenKey for the result with the agent key's signed
|
|
16
|
+
* proof, installs the grant, and only then acknowledges it. Every step is resumable from `approval-pending.json`.
|
|
17
|
+
*/
|
|
18
|
+
const PENDING_FILE = 'approval-pending.json';
|
|
19
|
+
export const DEFAULT_WAIT_MS = 60_000;
|
|
20
|
+
export const MAX_WAIT_MS = 9 * 60_000;
|
|
21
|
+
/**
|
|
22
|
+
* The wait for a pending agents space after an approval arrives ends this long after the --timeout deadline (never less than
|
|
23
|
+
* MIN_SPACE_WAIT_MS), so a default `init --wait` stays inside an agent's 2-minute tool-call limit. The grant is saved and
|
|
24
|
+
* acknowledged before that wait, so running out of it costs nothing: `init --resume` finishes.
|
|
25
|
+
*/
|
|
26
|
+
const DAY_MS = 86_400_000;
|
|
27
|
+
const SPACE_GRACE_MS = 5_000;
|
|
28
|
+
const MIN_SPACE_WAIT_MS = 1_000;
|
|
29
|
+
const MAX_SPACE_WAIT_MS = 150_000;
|
|
30
|
+
/** An acknowledgement that cannot be sent quickly is retried by the next `init --wait`; it never holds the command up. */
|
|
31
|
+
const ACK_TIMEOUT_MS = 5_000;
|
|
32
|
+
/** installGrant failures that no retry can fix: the approved result itself is wrong, so the request is dropped. */
|
|
33
|
+
const REFUSED_CODES = { 'bad-grant': true, 'grant-too-broad': true, 'grant-incomplete': true, 'grant-expired': true, 'grant-too-long': true };
|
|
34
|
+
export function readPending() {
|
|
35
|
+
const file = path.join(profileDir(), PENDING_FILE);
|
|
36
|
+
if (!fs.existsSync(file))
|
|
37
|
+
return { kind: 'none' };
|
|
38
|
+
const dirMode = fs.statSync(profileDir()).mode & 0o777;
|
|
39
|
+
if ((dirMode & 0o077) !== 0) {
|
|
40
|
+
return { kind: 'unreadable', reason: `${profileDir()} has mode ${dirMode.toString(8)}`, fix: `chmod 700 ${profileDir()}` };
|
|
41
|
+
}
|
|
42
|
+
const mode = fs.statSync(file).mode & 0o777;
|
|
43
|
+
if ((mode & 0o077) !== 0)
|
|
44
|
+
return { kind: 'unreadable', reason: `${file} has mode ${mode.toString(8)}, not 600`, fix: `chmod 600 ${file}` };
|
|
45
|
+
let text;
|
|
46
|
+
try {
|
|
47
|
+
text = fs.readFileSync(file, 'utf8');
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
return { kind: 'unreadable', reason: `${file} cannot be read (${error.message})`, fix: `chmod 600 ${file}` };
|
|
51
|
+
}
|
|
52
|
+
let pending;
|
|
53
|
+
try {
|
|
54
|
+
pending = JSON.parse(text);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
return { kind: 'corrupt', reason: error.message };
|
|
58
|
+
}
|
|
59
|
+
if (pending && typeof pending.version === 'number' && pending.version > 1) {
|
|
60
|
+
// Written by a newer Courier: not corrupt, and not ours to set aside. Use that Courier, or move the file away by hand.
|
|
61
|
+
return { kind: 'unreadable', reason: `${file} was written by a newer Courier (record version ${pending.version})`, fix: `mv ${file} ${file}.newer` };
|
|
62
|
+
}
|
|
63
|
+
if (!pending || pending.version !== 1 || !pending.request || typeof pending.requestId !== 'string' || typeof pending.bodyCid !== 'string'
|
|
64
|
+
|| typeof pending.approvalUrl !== 'string' || typeof pending.relayPrivateKey !== 'string' || typeof pending.ackId !== 'string') {
|
|
65
|
+
return { kind: 'corrupt', reason: 'unexpected contents' };
|
|
66
|
+
}
|
|
67
|
+
return { kind: 'ok', pending };
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Stops (without changing anything) when a saved approval request exists but cannot be read. Call it before a writer changes any
|
|
71
|
+
* other state, so a key, grant or profile is never replaced while the approval it belongs to is unreachable.
|
|
72
|
+
*/
|
|
73
|
+
export function assertPendingReadable() {
|
|
74
|
+
const read = readPending();
|
|
75
|
+
if (read.kind === 'unreadable')
|
|
76
|
+
throw unreadableError(read);
|
|
77
|
+
}
|
|
78
|
+
function unreadableError(read) {
|
|
79
|
+
return new CourierError('approval-unreadable', `The saved approval request cannot be used: ${read.reason}. It may hold an approval the owner already gave, so it was not touched and nothing else was changed. Fix it with \`${read.fix}\`, then run \`${cmd('init --wait')}\` again.`);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* The saved request for READ-ONLY and cleanup callers. A record that cannot be read is reported on stderr and treated as no record, so
|
|
83
|
+
* it never fails a command that already installed a grant or blocks `--rotate-key`. Callers that WRITE the record use
|
|
84
|
+
* `loadPendingForWrite`, which never lets an unreadable record be overwritten.
|
|
85
|
+
*/
|
|
86
|
+
export function loadPending() {
|
|
87
|
+
const read = readPending();
|
|
88
|
+
if (read.kind === 'ok')
|
|
89
|
+
return read.pending;
|
|
90
|
+
if (read.kind !== 'none') {
|
|
91
|
+
console.error(`warning: ignoring the saved approval request ${PENDING_FILE} in ${profileDir()} (${read.reason}).`);
|
|
92
|
+
}
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The saved request for a caller that is about to write one. A record that exists but cannot be read stops the command with the file
|
|
97
|
+
* named and how to fix it: the approval in it may be intact (it comes back after the fix). Only a record that is readable and corrupt
|
|
98
|
+
* is set aside, as `approval-pending.json.corrupt-<time>` (0600), and the command goes on without it.
|
|
99
|
+
*/
|
|
100
|
+
function loadPendingForWrite() {
|
|
101
|
+
const read = readPending();
|
|
102
|
+
if (read.kind === 'ok')
|
|
103
|
+
return read.pending;
|
|
104
|
+
if (read.kind === 'unreadable') {
|
|
105
|
+
throw unreadableError(read);
|
|
106
|
+
}
|
|
107
|
+
if (read.kind === 'corrupt') {
|
|
108
|
+
const file = path.join(profileDir(), PENDING_FILE);
|
|
109
|
+
const aside = `${file}.corrupt-${new Date().toISOString().replace(/[:.]/g, '-')}`;
|
|
110
|
+
fs.renameSync(file, aside);
|
|
111
|
+
fs.chmodSync(aside, 0o600);
|
|
112
|
+
console.error(`warning: ${PENDING_FILE} is corrupt (${read.reason}); it was moved to ${aside} and will be replaced by a new request.`);
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
function savePending(pending) {
|
|
117
|
+
writeSecure(path.join(profileDir(), PENDING_FILE), pending);
|
|
118
|
+
}
|
|
119
|
+
export function clearPending() {
|
|
120
|
+
try {
|
|
121
|
+
fs.unlinkSync(path.join(profileDir(), PENDING_FILE));
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
if (error.code !== 'ENOENT')
|
|
125
|
+
throw error;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function configuredOrigin(value, label) {
|
|
129
|
+
let url;
|
|
130
|
+
try {
|
|
131
|
+
url = new URL(value);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
throw new CourierError('usage', `${label} must be an origin, such as https://openkey.so.`);
|
|
135
|
+
}
|
|
136
|
+
const loopback = ['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname);
|
|
137
|
+
if (url.pathname !== '/' || url.search || url.hash || url.username || url.password || (url.protocol !== 'https:' && !(url.protocol === 'http:' && loopback))) {
|
|
138
|
+
throw new CourierError('usage', `${label} must be an HTTPS origin (or a loopback HTTP origin).`);
|
|
139
|
+
}
|
|
140
|
+
return url.origin;
|
|
141
|
+
}
|
|
142
|
+
function requesterJwk(key) {
|
|
143
|
+
const { kty, crv, x, d } = key.jwk;
|
|
144
|
+
if (kty !== 'OKP' || crv !== 'Ed25519' || typeof x !== 'string' || typeof d !== 'string') {
|
|
145
|
+
throw new CourierError('bad-profile', `The agent key in ${profileDir()} is not an Ed25519 key.`);
|
|
146
|
+
}
|
|
147
|
+
return { kty, crv, x, d };
|
|
148
|
+
}
|
|
149
|
+
function wanted(profile, key, expiry, openkeyApiHost) {
|
|
150
|
+
const jwk = requesterJwk(key);
|
|
151
|
+
const signer = signerFromJwk(jwk);
|
|
152
|
+
if (signer.did !== bareDid(key.did))
|
|
153
|
+
throw new CourierError('bad-profile', 'The agent key file does not match its did:key.');
|
|
154
|
+
const lifetimeMs = durationMs(expiry ?? AGENT_GRANT_EXPIRY);
|
|
155
|
+
if (!lifetimeMs)
|
|
156
|
+
throw new CourierError('usage', `Invalid --expiry ${expiry}.`);
|
|
157
|
+
const openkeyOrigin = configuredOrigin(profile.openkeyHost, 'The OpenKey host');
|
|
158
|
+
return {
|
|
159
|
+
jwk, signer, lifetime: Math.floor(lifetimeMs / 1000), explicitLifetime: expiry !== undefined, openkeyOrigin,
|
|
160
|
+
apiOrigin: configuredOrigin(resolveOpenKeyApiHost({ flag: openkeyApiHost, env: process.env.COURIER_OPENKEY_API_HOST, openkeyHost: openkeyOrigin }), 'The OpenKey API host'),
|
|
161
|
+
linkApiOrigin: configuredOrigin(process.env.TC_LINKS_API_ORIGIN ?? DEFAULT_LINKS_API_ORIGIN, 'The links API origin'),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
/** Everything in the request except the relay key (fresh per request) and the lifetime (compared only when asked for). */
|
|
165
|
+
function requestSpec(profile, want) {
|
|
166
|
+
return {
|
|
167
|
+
issuer: want.signer.did, requestVersion: 1, targetDid: want.signer.did,
|
|
168
|
+
// The schema is strict: the public key members only, never `d`.
|
|
169
|
+
targetPublicJwk: { kty: 'OKP', crv: 'Ed25519', x: want.jwk.x },
|
|
170
|
+
nodeOrigin: profile.host, permissions: AGENT_GRANT.map((entry) => ({ ...entry, actions: [...entry.actions] })),
|
|
171
|
+
reason: 'Grant the Courier agent key restricted access to this owner space. It cannot write owner approvals or orders.',
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/** The saved request is the one this run would make: same canonical request (permissions, target, reason, host) and origins. */
|
|
175
|
+
function matches(pending, profile, want) {
|
|
176
|
+
const { resultEncryptionPublicJwk: _relay, grantLifetimeSeconds, ...saved } = pending.request;
|
|
177
|
+
return canonicalJson(saved) === canonicalJson(requestSpec(profile, want))
|
|
178
|
+
&& (!want.explicitLifetime || grantLifetimeSeconds === want.lifetime)
|
|
179
|
+
&& pending.openkeyOrigin === want.openkeyOrigin && pending.apiOrigin === want.apiOrigin && pending.linkApiOrigin === want.linkApiOrigin;
|
|
180
|
+
}
|
|
181
|
+
/** The saved request already holds something that cannot be made again: a reference to an approved result, the result itself, or an installed grant. */
|
|
182
|
+
export const holdsApproval = (pending) => pending.resultRef !== undefined || pending.resultEnvelope !== undefined || pending.committed === true;
|
|
183
|
+
/**
|
|
184
|
+
* OpenKey keeps an approved result for this long after the approval: production APPROVAL_RESULT_RETENTION_SECONDS=600,
|
|
185
|
+
* docker-compose.prod.yml:28 (OpenKey repo). The constant follows the DEPLOYED value.
|
|
186
|
+
*/
|
|
187
|
+
const RESULT_RETENTION_MS = 600_000;
|
|
188
|
+
/** Clock difference tolerated between this machine and OpenKey when judging the end of that window. */
|
|
189
|
+
const EXPIRY_SKEW_MS = 60_000;
|
|
190
|
+
/** The request's own expiry has passed and nothing was ever collected for it. */
|
|
191
|
+
const requestLapsed = (pending) => !holdsApproval(pending) && Date.parse(pending.requestExpiresAt) <= Date.now();
|
|
192
|
+
/**
|
|
193
|
+
* A lapsed, unapproved request may still have been approved just before it expired: OpenKey serves the result for
|
|
194
|
+
* RESULT_RETENTION_MS after the approval. So it is asked ONCE (the normal discover) before the record is dropped:
|
|
195
|
+
* a result is saved (`approved`), OpenKey still calling it open is `open`, an expired answer is `expired`. Past the whole window
|
|
196
|
+
* (expiry + retention + skew) no approval can exist any more: `expired` without a call. OpenKey being unreachable inside the window
|
|
197
|
+
* keeps the record (`approval-unavailable`).
|
|
198
|
+
*/
|
|
199
|
+
async function settleLapsed(pending, key) {
|
|
200
|
+
if (Date.now() >= Date.parse(pending.requestExpiresAt) + RESULT_RETENTION_MS + EXPIRY_SKEW_MS)
|
|
201
|
+
return 'expired';
|
|
202
|
+
try {
|
|
203
|
+
const found = await discoverApprovalResult(requesterState(pending, key));
|
|
204
|
+
if (found.status === 'pending')
|
|
205
|
+
return 'open';
|
|
206
|
+
pending.resultRef = found.resultRef;
|
|
207
|
+
pending.resultExpiresAt = found.expiresAt;
|
|
208
|
+
savePending(pending);
|
|
209
|
+
return 'approved';
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
if (!isApprovalClientError(error))
|
|
213
|
+
throw error;
|
|
214
|
+
if (error.code === 'request_expired' || error.code === 'not_found')
|
|
215
|
+
return 'expired';
|
|
216
|
+
if (error.code === 'network' || error.code === 'unavailable') {
|
|
217
|
+
throw new CourierError('approval-unavailable', `OpenKey could not be asked whether this expired request was approved (${error.message}). Nothing was lost: the saved request is kept. Run \`${cmd('init --wait')}\` again once OpenKey is reachable.`);
|
|
218
|
+
}
|
|
219
|
+
throw collectFailure(error, false);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
async function createPending(profile, want) {
|
|
223
|
+
const relay = generateRelayKey();
|
|
224
|
+
const request = { ...requestSpec(profile, want), grantLifetimeSeconds: want.lifetime, resultEncryptionPublicJwk: relay.publicJwk };
|
|
225
|
+
let created;
|
|
226
|
+
try {
|
|
227
|
+
created = await createApprovalRequest({ request, issuerKey: want.signer, apiOrigin: want.linkApiOrigin, openkeyOrigin: want.openkeyOrigin });
|
|
228
|
+
}
|
|
229
|
+
catch (error) {
|
|
230
|
+
if (!isLinkError(error))
|
|
231
|
+
throw error;
|
|
232
|
+
throw new CourierError('link-unavailable', `Could not create the OpenKey approval link (${error.code}). Check the network and run \`${cmd('init --request')}\` again.`);
|
|
233
|
+
}
|
|
234
|
+
const pending = {
|
|
235
|
+
version: 1, request, requestId: created.id, bodyCid: created.bodyCid, approvalUrl: created.link, requestExpiresAt: created.expiresAt,
|
|
236
|
+
record: created.record, apiOrigin: want.apiOrigin, linkApiOrigin: want.linkApiOrigin, openkeyOrigin: want.openkeyOrigin,
|
|
237
|
+
relayPrivateKey: relay.privateKey, ackId: randomUUID(),
|
|
238
|
+
};
|
|
239
|
+
savePending(pending); // saved before the link is shown: a link that was shown can always be resumed
|
|
240
|
+
return pending;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* `init --request`: the saved request when it is still the same and open, else a new one. A saved request that already holds an
|
|
244
|
+
* approval (a result reference, the encrypted result, or an installed grant awaiting its acknowledgement) is NEVER replaced:
|
|
245
|
+
* replacing it would discard an approval the owner already gave.
|
|
246
|
+
*/
|
|
247
|
+
export async function requestApproval(profile, key, expiry, options = {}) {
|
|
248
|
+
const want = wanted(profile, key, expiry, options.openkeyApiHost);
|
|
249
|
+
const existing = loadPendingForWrite();
|
|
250
|
+
if (existing && existing.request.issuer === want.signer.did) {
|
|
251
|
+
if (!holdsApproval(existing) && requestLapsed(existing) && matches(existing, profile, want)) {
|
|
252
|
+
const settled = await settleLapsed(existing, key);
|
|
253
|
+
if (settled === 'open')
|
|
254
|
+
return existing;
|
|
255
|
+
if (settled === 'expired')
|
|
256
|
+
clearPending();
|
|
257
|
+
}
|
|
258
|
+
if (holdsApproval(existing)) {
|
|
259
|
+
throw new CourierError('usage', `Approval request ${existing.requestId} has already been approved by the owner. Run \`${cmd('init --wait')}\` to finish it first; \`${cmd('init --request')}\` can ask for another approval after that. To discard that approval instead, run \`${cmd('init --rotate-key --request')}\`: it replaces the agent key, CLEARS every pairing (peers must be re-paired by hand), deletes grant.json and puts the profile back to awaiting-grant, so there is no working grant until the owner approves.`);
|
|
260
|
+
}
|
|
261
|
+
if (matches(existing, profile, want) && !requestLapsed(existing))
|
|
262
|
+
return existing;
|
|
263
|
+
}
|
|
264
|
+
return createPending(profile, want);
|
|
265
|
+
}
|
|
266
|
+
function expiredError() {
|
|
267
|
+
return new CourierError('approval-expired', `This approval request expired before it was approved. Run \`${cmd('init --request')}\` for a new link.`);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* `init --wait`: resumes the saved request for this key, or makes a new one. A request that holds an approval is resumed whatever
|
|
271
|
+
* flags this run has; an unapproved one is replaced only when it differs from what this run asks for. A lapsed unapproved request
|
|
272
|
+
* is asked about once (see settleLapsed) and dropped and reported only when OpenKey too says it is expired.
|
|
273
|
+
*/
|
|
274
|
+
export async function waitApproval(profile, key, expiry, options = {}) {
|
|
275
|
+
const want = wanted(profile, key, expiry, options.openkeyApiHost);
|
|
276
|
+
const existing = loadPendingForWrite();
|
|
277
|
+
if (existing && existing.request.issuer === want.signer.did) {
|
|
278
|
+
if (holdsApproval(existing))
|
|
279
|
+
return { pending: existing, resumed: true };
|
|
280
|
+
if (matches(existing, profile, want)) {
|
|
281
|
+
if (requestLapsed(existing)) {
|
|
282
|
+
if (await settleLapsed(existing, key) === 'expired') {
|
|
283
|
+
clearPending();
|
|
284
|
+
throw expiredError();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return { pending: existing, resumed: true };
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
return { pending: await createPending(profile, want), resumed: false };
|
|
291
|
+
}
|
|
292
|
+
function resultGoneError() {
|
|
293
|
+
return new CourierError('approval-result-expired', `OpenKey no longer holds the approved result: it keeps one for only 10 minutes, and this one was not collected in time, so nothing was installed. Run \`${cmd('init --request')}\` and approve the new link, then run \`${cmd('init --wait')}\` right away.`);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* What a failed collection means for the saved request. Permanent outcomes (expired request, expired or consumed result) drop it so
|
|
297
|
+
* `init --request` is not blocked; anything that a retry can fix (a rejected proof, one malformed reply, OpenKey down) keeps it and
|
|
298
|
+
* its relay key. `resultSeen` is whether the result reference was already saved, i.e. whether the failing call was the fetch.
|
|
299
|
+
*/
|
|
300
|
+
function collectFailure(error, resultSeen) {
|
|
301
|
+
switch (error.code) {
|
|
302
|
+
case 'request_expired':
|
|
303
|
+
clearPending();
|
|
304
|
+
return expiredError();
|
|
305
|
+
case 'not_found':
|
|
306
|
+
clearPending();
|
|
307
|
+
return resultSeen ? resultGoneError() : expiredError();
|
|
308
|
+
case 'result_expired':
|
|
309
|
+
clearPending();
|
|
310
|
+
return resultGoneError();
|
|
311
|
+
case 'acknowledged':
|
|
312
|
+
clearPending(); // nothing local to finish from, and a kept record would block `init --request`
|
|
313
|
+
return new CourierError('approval-consumed', `OpenKey says this approval was already collected, so it cannot be fetched again. If this machine has no grant, run \`${cmd('init --request')}\` and approve the new link.`);
|
|
314
|
+
case 'request_binding':
|
|
315
|
+
return new CourierError('approval-rejected', `OpenKey rejected this machine's proof or the request binding (check the system clock). The saved request is kept: run \`${cmd('init --wait')}\` again.`);
|
|
316
|
+
default:
|
|
317
|
+
return new CourierError('approval-unavailable', `OpenKey could not be asked for the result (${error.message}). Nothing was lost: run \`${cmd('init --wait')}\` again.`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
function requesterState(pending, key) {
|
|
321
|
+
return { requestId: pending.requestId, bodyCid: pending.bodyCid, record: pending.record, apiOrigin: pending.apiOrigin, signingKey: requesterJwk(key) };
|
|
322
|
+
}
|
|
323
|
+
/** Decrypt the saved result and check it answers this request and this key. Throws after dropping the request if it does not. */
|
|
324
|
+
async function verifiedPayload(profile, pending, key) {
|
|
325
|
+
let delegationCid;
|
|
326
|
+
try {
|
|
327
|
+
const opened = await openRelayResult(pending.resultEnvelope, pending.requestId, pending.relayPrivateKey);
|
|
328
|
+
const claimedCid = opened.delegation?.delegationCid;
|
|
329
|
+
delegationCid = typeof claimedCid === 'string' && claimedCid !== '' ? claimedCid : undefined;
|
|
330
|
+
const checked = checkApprovalResultBinding(opened, { requestId: pending.requestId, bodyCid: pending.bodyCid, request: pending.request });
|
|
331
|
+
const payload = parseGrantPayload(checked.delegation, key);
|
|
332
|
+
assertBoundToKey(checked.delegation, key);
|
|
333
|
+
if (`did:pkh:eip155:${payload.chainId}:${payload.address}`.toLowerCase() !== checked.ownerDid.toLowerCase()) {
|
|
334
|
+
throw new CourierError('bad-grant', 'The approved result names a different owner than its delegation.');
|
|
335
|
+
}
|
|
336
|
+
const times = siweTimes(payload.siwe);
|
|
337
|
+
if (times.expiresAt?.toISOString() !== checked.delegationExpiresAt) {
|
|
338
|
+
throw new CourierError('bad-grant', 'The approved result expiry differs from the signed delegation expiry.');
|
|
339
|
+
}
|
|
340
|
+
// The grant may not outlast what was asked for (OpenKey lets the owner choose less, never more).
|
|
341
|
+
if (times.issuedAt && times.expiresAt.getTime() - times.issuedAt.getTime() > pending.request.grantLifetimeSeconds * 1000 + CLOCK_SKEW_MS) {
|
|
342
|
+
throw new CourierError('grant-too-long', `The approved grant is valid for ${+((times.expiresAt.getTime() - times.issuedAt.getTime()) / DAY_MS).toFixed(2)} days, but this request asked for at most ${+(pending.request.grantLifetimeSeconds * 1000 / DAY_MS).toFixed(2)} days.`);
|
|
343
|
+
}
|
|
344
|
+
// A renewal stays with the owner that holds the grant: with no code to paste back, whoever approves the link first would win.
|
|
345
|
+
if (profile.ownerDid && checked.ownerDid.toLowerCase() !== profile.ownerDid.toLowerCase()) {
|
|
346
|
+
throw new CourierError('approval-result-invalid', `This agent is bound to owner ${profile.ownerDid}, but a different owner (${checked.ownerDid}) approved the request. Send the link only to the owner, privately. If the owner changed on purpose, run \`${cmd('init --rotate-key --request')}\` it replaces the agent key, clears every pairing (peers must be re-paired by hand) and deletes grant.json.`);
|
|
347
|
+
}
|
|
348
|
+
return payload;
|
|
349
|
+
}
|
|
350
|
+
catch (error) {
|
|
351
|
+
clearPending();
|
|
352
|
+
throw withRefusalNotice(isApprovalClientError(error) ? new CourierError('approval-result-invalid', `The approved result was refused. ${error.message}`) : error, delegationCid);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
/** Acknowledge a saved grant. A failure is reported, never fatal: the grant is installed and the saved request keeps the ack to retry. */
|
|
356
|
+
async function acknowledge(pending, key) {
|
|
357
|
+
if (!pending.resultRef) {
|
|
358
|
+
clearPending();
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
try {
|
|
362
|
+
await ackApprovalResult(requesterState(pending, key), pending.resultRef, pending.ackId, { timeoutMs: ACK_TIMEOUT_MS });
|
|
363
|
+
clearPending();
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
if (!isApprovalClientError(error))
|
|
367
|
+
throw error;
|
|
368
|
+
if (error.code === 'ack_conflict') {
|
|
369
|
+
// OpenKey holds another acknowledgement for this result: nothing more can be sent, and a kept record would block `init --request`.
|
|
370
|
+
clearPending();
|
|
371
|
+
console.error('The grant is installed. OpenKey already holds a different acknowledgement for this approval, so there is nothing left to send.');
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
console.error(`The grant is installed, but OpenKey did not confirm the acknowledgement (${error.message}). This is harmless (OpenKey discards the result within 10 minutes); run \`${cmd('init --wait')}\` to retry it.`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* Collect, verify and install the approved grant, then acknowledge it. Returns `deadline` when the owner has not
|
|
379
|
+
* approved by `options.deadline` (the request stays saved). Nothing is acknowledged before the grant and profile
|
|
380
|
+
* are durably saved; every earlier step is resumable from the saved request alone.
|
|
381
|
+
*/
|
|
382
|
+
export async function completeApproval(profile, key, pending, options) {
|
|
383
|
+
if (!pending.committed) {
|
|
384
|
+
if (pending.resultEnvelope === undefined) {
|
|
385
|
+
let collected;
|
|
386
|
+
try {
|
|
387
|
+
collected = await collectApprovalResult(requesterState(pending, key), {
|
|
388
|
+
deadline: options.deadline,
|
|
389
|
+
...(pending.resultRef && pending.resultExpiresAt ? { known: { resultRef: pending.resultRef, expiresAt: pending.resultExpiresAt } } : {}),
|
|
390
|
+
onDiscovered: (found) => {
|
|
391
|
+
pending.resultRef = found.resultRef;
|
|
392
|
+
pending.resultExpiresAt = found.expiresAt;
|
|
393
|
+
savePending(pending);
|
|
394
|
+
},
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
catch (error) {
|
|
398
|
+
if (!isApprovalClientError(error))
|
|
399
|
+
throw error;
|
|
400
|
+
throw collectFailure(error, pending.resultRef !== undefined);
|
|
401
|
+
}
|
|
402
|
+
if (collected.status === 'deadline')
|
|
403
|
+
return 'deadline';
|
|
404
|
+
pending.resultEnvelope = collected.relay;
|
|
405
|
+
savePending(pending); // the encrypted result is on disk before any install work
|
|
406
|
+
}
|
|
407
|
+
const payload = await verifiedPayload(profile, pending, key);
|
|
408
|
+
const spaceTimeoutMs = Math.min(MAX_SPACE_WAIT_MS, Math.max(MIN_SPACE_WAIT_MS, options.deadline + SPACE_GRACE_MS - Date.now()));
|
|
409
|
+
let spaceError;
|
|
410
|
+
try {
|
|
411
|
+
await installGrant(profile, key, payload, { spaceTimeoutMs });
|
|
412
|
+
}
|
|
413
|
+
catch (error) {
|
|
414
|
+
if (error instanceof CourierError && error.code === 'no-space')
|
|
415
|
+
spaceError = error; // grant and profile are saved
|
|
416
|
+
else if (isClockRefusal(error) && !isPermanentRefusal(error, payload.siwe)) {
|
|
417
|
+
// Refused because of THIS machine's clock (issued "in the future", no future expiry): the approval is fine and is kept.
|
|
418
|
+
throw new CourierError(error.code, `${error.message}\nThe system clock may be wrong. Nothing was installed and the saved approval is kept (it is not something to revoke): check the system clock, then run \`${cmd('init --wait')}\` again.`);
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
if (error instanceof CourierError && REFUSED_CODES[error.code])
|
|
422
|
+
clearPending();
|
|
423
|
+
throw withRefusalNotice(error, payload.delegationCid);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
pending.committed = true;
|
|
427
|
+
savePending(pending);
|
|
428
|
+
await acknowledge(pending, key);
|
|
429
|
+
if (spaceError)
|
|
430
|
+
throw spaceError;
|
|
431
|
+
return 'done';
|
|
432
|
+
}
|
|
433
|
+
await acknowledge(pending, key);
|
|
434
|
+
return 'done';
|
|
435
|
+
}
|
|
436
|
+
//# sourceMappingURL=grant-request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grant-request.js","sourceRoot":"","sources":["../src/grant-request.ts"],"names":[],"mappings":"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"}
|
package/dist/grant.d.ts
CHANGED
|
@@ -41,6 +41,8 @@ export declare function resolveOpenKeyApiHost(options: {
|
|
|
41
41
|
env?: string;
|
|
42
42
|
openkeyHost: string;
|
|
43
43
|
}): string;
|
|
44
|
+
/** Same binding checks as `tc`'s delegationFromInput: the redeemed delegation must be for this agent key. */
|
|
45
|
+
export declare function assertBoundToKey(delegation: unknown, key: Pick<AgentKey, 'did' | 'jwk'>): void;
|
|
44
46
|
/**
|
|
45
47
|
* Parse a grant from what the human pasted or OpenKey posted: an OpenKey short
|
|
46
48
|
* `XXXX-XXXX` code (redeemed at `apiHost`), JSON, or base64 JSON.
|
|
@@ -61,7 +63,18 @@ export declare function waitForSpaceReady(probe: () => Promise<boolean>, options
|
|
|
61
63
|
}): Promise<boolean>;
|
|
62
64
|
export declare function pendingSpaceError(profile: Profile): CourierError;
|
|
63
65
|
export declare function noSpaceError(profile: Profile): CourierError;
|
|
64
|
-
|
|
66
|
+
/** Whether a failed install of a saved delegation can never succeed on a retry with a correct clock. */
|
|
67
|
+
export declare function isClockRefusal(error: unknown): boolean;
|
|
68
|
+
export declare function isPermanentRefusal(error: unknown, siwe: string): boolean;
|
|
69
|
+
/** `spaceTimeoutMs` bounds the wait for OpenKey to host a pending agents space (default 150 s); `init --wait` passes what its --timeout leaves. */
|
|
70
|
+
export declare function installGrant(profile: Profile, key: AgentKey, payload: GrantPayload, options?: {
|
|
71
|
+
spaceTimeoutMs?: number;
|
|
72
|
+
}): Promise<void>;
|
|
73
|
+
/** `installGrant` for a grant that came from outside (an approval result, a code, a file): a refusal carries the TC-2308 notice. */
|
|
74
|
+
export declare function installRefusing(profile: Profile, key: AgentKey, payload: GrantPayload, options?: {
|
|
75
|
+
spaceTimeoutMs?: number;
|
|
76
|
+
viaCode?: boolean;
|
|
77
|
+
}): Promise<void>;
|
|
65
78
|
export declare function resumeGrant(profile: Profile, key: AgentKey): Promise<void>;
|
|
66
79
|
/**
|
|
67
80
|
* `init --resume` for a profile left `awaiting-grant` by a kill: finish from the redeemed delegation saved
|