@tinycloud/courier 0.6.0-beta.17 → 0.6.0-beta.19
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/authority.d.ts +35 -0
- package/dist/authority.js +65 -0
- package/dist/authority.js.map +1 -1
- package/dist/commands.js +2 -1
- package/dist/commands.js.map +1 -1
- package/dist/email-invitation.d.ts +12 -6
- package/dist/email-invitation.js +31 -34
- package/dist/email-invitation.js.map +1 -1
- package/dist/flags.js +1 -0
- package/dist/flags.js.map +1 -1
- package/dist/invitation.d.ts +11 -3
- package/dist/invitation.js +62 -13
- package/dist/invitation.js.map +1 -1
- package/dist/invite-approval.d.ts +103 -0
- package/dist/invite-approval.js +271 -0
- package/dist/invite-approval.js.map +1 -0
- package/dist/invite-openkey.d.ts +14 -0
- package/dist/invite-openkey.js +184 -0
- package/dist/invite-openkey.js.map +1 -0
- package/dist/main.js +4 -1
- package/dist/main.js.map +1 -1
- package/dist/status.d.ts +23 -0
- package/dist/status.js +86 -0
- package/dist/status.js.map +1 -0
- package/package.json +5 -5
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ulid } from 'ulid';
|
|
4
|
+
import { activateValidatedRuntimeDelegation } from '@tinycloud/node-sdk';
|
|
5
|
+
import { assertApprovalRequestBinding, assertInvitationApprovalGrant, parseApprovalSiwe } from './authority.js';
|
|
6
|
+
import { CourierError } from './errors.js';
|
|
7
|
+
import { mkdirOwnerOnly, profileDir, writeSecure } from './profile.js';
|
|
8
|
+
const DAY_MS = 86_400_000;
|
|
9
|
+
const pendingDir = (home = profileDir()) => path.join(home, 'pending-invites');
|
|
10
|
+
const grantDir = (home = profileDir()) => path.join(home, 'invite-grants');
|
|
11
|
+
const ULID = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
12
|
+
function readJson(file) {
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
if (error.code === 'ENOENT')
|
|
18
|
+
return undefined;
|
|
19
|
+
throw new CourierError('bad-profile', `Invalid ${path.basename(file)}: ${error.message}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function secureWrite(dir, id, value) {
|
|
23
|
+
mkdirOwnerOnly(dir);
|
|
24
|
+
writeSecure(path.join(dir, `${id}.json`), value);
|
|
25
|
+
}
|
|
26
|
+
export function loadPendingInvite(invitationId, home = profileDir()) {
|
|
27
|
+
if (!ULID.test(invitationId))
|
|
28
|
+
return undefined;
|
|
29
|
+
return readJson(path.join(pendingDir(home), `${invitationId}.json`));
|
|
30
|
+
}
|
|
31
|
+
export function savePendingInvite(pending) {
|
|
32
|
+
secureWrite(pendingDir(), pending.invitationId, pending);
|
|
33
|
+
}
|
|
34
|
+
export function loadInviteGrant(invitationId, home = profileDir()) {
|
|
35
|
+
if (!ULID.test(invitationId))
|
|
36
|
+
return undefined;
|
|
37
|
+
return readJson(path.join(grantDir(home), `${invitationId}.json`));
|
|
38
|
+
}
|
|
39
|
+
/** The open (not closed, not sent, not yet expired) pending approval for this exact session and recipient, if any. */
|
|
40
|
+
export function findPendingInvite(profile, sessionId, recipient, now, home = profileDir()) {
|
|
41
|
+
let names;
|
|
42
|
+
try {
|
|
43
|
+
names = fs.readdirSync(pendingDir(home));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (error.code === 'ENOENT')
|
|
47
|
+
return undefined;
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
for (const name of names.filter((value) => value.endsWith('.json')).sort()) {
|
|
51
|
+
const pending = readJson(path.join(pendingDir(home), name));
|
|
52
|
+
if (pending?.status === 'awaiting' && pending.sessionId === sessionId && pending.recipient === recipient && pending.courierDid === profile.courierDid
|
|
53
|
+
&& pending.ownerDid === profile.ownerDid && Date.parse(pending.acceptanceExpiresAt) > now)
|
|
54
|
+
return pending;
|
|
55
|
+
}
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
/** A new pending invitation: fresh id, expiry at most 24 hours out and never past the main grant. */
|
|
59
|
+
export function newPendingInvite(profile, input, now) {
|
|
60
|
+
if (!profile.ownerDid || !profile.grantExpiresAt)
|
|
61
|
+
throw new CourierError('no-grant', 'No owner grant is installed.');
|
|
62
|
+
const expires = new Date(Math.floor(Math.min(now + DAY_MS, Date.parse(profile.grantExpiresAt)) / 1000) * 1000);
|
|
63
|
+
if (expires.getTime() - now < 60_000)
|
|
64
|
+
throw new CourierError('grant-expired', 'The Courier grant ends too soon to send an invitation.');
|
|
65
|
+
return {
|
|
66
|
+
v: 1, invitationId: ulid(now), recipient: input.recipient, sessionId: input.sessionId, subjectName: input.subjectName,
|
|
67
|
+
courierDid: profile.courierDid, ownerDid: profile.ownerDid, createdAt: new Date(now).toISOString(),
|
|
68
|
+
acceptanceExpiresAt: expires.toISOString(), accessExpiresAt: expires.toISOString(), status: 'awaiting',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
export function invitationContext(pending) {
|
|
72
|
+
return {
|
|
73
|
+
kind: 'share-invitation', version: 1, invitationId: pending.invitationId, recipientEmail: pending.recipient,
|
|
74
|
+
subjectKind: 'session', subjectName: pending.subjectName,
|
|
75
|
+
acceptanceExpiresAt: pending.acceptanceExpiresAt, accessExpiresAt: pending.accessExpiresAt,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** A host that could not be reached (or a registry that did not answer): says nothing about the approval, so it is retried, never refused. */
|
|
79
|
+
const TRANSIENT_ACTIVATION_CODES = new Set(['NODE_NOT_RESPONDING', 'registry_unavailable', 'ACTIVATION_TRANSPORT_FAILED']);
|
|
80
|
+
function activationUnavailable(error) {
|
|
81
|
+
const { reason, code } = (error ?? {});
|
|
82
|
+
return reason === 'activation_unavailable' || (typeof code === 'string' && TRANSIENT_ACTIVATION_CODES.has(code));
|
|
83
|
+
}
|
|
84
|
+
/** A share key id belongs to exactly one invitation, so a stored approval is never reusable for a second one. */
|
|
85
|
+
function keyIdUsedElsewhere(shareId, invitationId) {
|
|
86
|
+
let names;
|
|
87
|
+
try {
|
|
88
|
+
names = fs.readdirSync(grantDir());
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (error.code === 'ENOENT')
|
|
92
|
+
return false;
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
return names.filter((name) => name.endsWith('.json') && name !== `${invitationId}.json`)
|
|
96
|
+
.some((name) => readJson(path.join(grantDir(), name))?.shareId === shareId);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Verify the owner-signed grant for THIS pending request and install it as a runtime delegation on the Courier node. The
|
|
100
|
+
* grant's ReCap is a raw encryption network resource (no space), so it is a grant, not a session: the node-sdk verifies it
|
|
101
|
+
* (SIWE signature, signer, audience = this node's session key, expiry) and activates it. Order: the request binding, then
|
|
102
|
+
* the signed authority (exactly one key pair), then the install. Returns the key id from the signed grant.
|
|
103
|
+
*/
|
|
104
|
+
async function activateInviteGrant(node, profile, pending, payload, now) {
|
|
105
|
+
const state = pending.transport;
|
|
106
|
+
if (typeof state?.requestId !== 'string' || typeof state.bodyCid !== 'string')
|
|
107
|
+
throw new CourierError('bad-grant', 'No approval request exists for this invitation.');
|
|
108
|
+
// One strict parse: the binding and the lifetime are read from it, and the signature is verified over its exact text.
|
|
109
|
+
const parsed = parseApprovalSiwe(payload.siwe);
|
|
110
|
+
assertApprovalRequestBinding(parsed, { requestId: state.requestId, bodyCid: state.bodyCid });
|
|
111
|
+
const times = { ...(parsed.issuedAt ? { issuedAt: parsed.issuedAt } : {}), ...(parsed.expiresAt ? { expiresAt: parsed.expiresAt } : {}) };
|
|
112
|
+
if (!times.expiresAt || times.expiresAt.getTime() <= now)
|
|
113
|
+
throw new CourierError('grant-expired', 'The invitation approval has expired.');
|
|
114
|
+
if (pending.courierDid !== profile.courierDid)
|
|
115
|
+
throw new CourierError('bad-grant', 'The invitation approval was not requested by this Courier key.');
|
|
116
|
+
const owner = `did:pkh:eip155:${payload.chainId}:${payload.address}`;
|
|
117
|
+
if (!profile.ownerDid || owner.toLowerCase() !== profile.ownerDid.toLowerCase() || owner.toLowerCase() !== pending.ownerDid.toLowerCase()) {
|
|
118
|
+
throw new CourierError('bad-grant', 'The invitation approval was given by a different account than the Courier owner.');
|
|
119
|
+
}
|
|
120
|
+
let verified;
|
|
121
|
+
try {
|
|
122
|
+
verified = node.verifySessionGrant({
|
|
123
|
+
delegationHeader: { Authorization: payload.delegationHeader.Authorization }, delegationCid: payload.delegationCid, spaceId: payload.spaceId,
|
|
124
|
+
address: payload.address, chainId: payload.chainId, siwe: parsed.raw, signature: payload.signature,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
throw new CourierError('bad-grant', 'The invitation approval could not be verified for this Courier key.');
|
|
129
|
+
}
|
|
130
|
+
const signed = verified.recap.map((entry) => {
|
|
131
|
+
const service = entry.service.startsWith('tinycloud.') ? entry.service : `tinycloud.${entry.service}`;
|
|
132
|
+
return { service, space: entry.space, path: entry.path, actions: entry.actions.map((action) => (action.includes('/') ? action : `${service}/${action}`)), ...(entry.caveats?.length ? { caveats: [...entry.caveats] } : {}) };
|
|
133
|
+
});
|
|
134
|
+
const bounds = { ownerDid: owner, acceptanceExpiresAt: new Date(pending.acceptanceExpiresAt), now };
|
|
135
|
+
const shareId = assertInvitationApprovalGrant(signed, times, bounds);
|
|
136
|
+
const entry = signed[0];
|
|
137
|
+
const delegation = {
|
|
138
|
+
cid: payload.delegationCid, delegationHeader: { Authorization: payload.delegationHeader.Authorization }, spaceId: payload.spaceId,
|
|
139
|
+
path: entry.path, actions: [...entry.actions], resources: [{ service: 'encryption', space: 'encryption', path: entry.path, actions: [...entry.actions] }],
|
|
140
|
+
expiry: verified.expiresAt, delegateDID: payload.verificationMethod, ownerAddress: payload.address, chainId: payload.chainId, host: profile.host,
|
|
141
|
+
siweProof: { siwe: payload.siwe, signature: payload.signature },
|
|
142
|
+
};
|
|
143
|
+
try {
|
|
144
|
+
await activateValidatedRuntimeDelegation(node, delegation, {
|
|
145
|
+
host: profile.host,
|
|
146
|
+
// What the node ends up holding must be exactly the one pair, again from the signed bytes it parsed itself.
|
|
147
|
+
authorize: (effective) => { try {
|
|
148
|
+
return assertInvitationApprovalGrant(effective, times, bounds) === shareId;
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return false;
|
|
152
|
+
} },
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
// The host could not be reached (or answered with a transient status): the approval is fine and is kept; the next run installs it.
|
|
157
|
+
if (activationUnavailable(error)) {
|
|
158
|
+
throw new CourierError('activation-unavailable', 'The TinyCloud host could not be reached to install the invitation approval; nothing was sent. Run the command again to continue with the same approval.');
|
|
159
|
+
}
|
|
160
|
+
throw new CourierError('bad-grant', `The invitation approval could not be installed for this Courier key (${error.reason ?? error.code ?? 'refused'}).`);
|
|
161
|
+
}
|
|
162
|
+
return { shareId, expiresAt: verified.expiresAt };
|
|
163
|
+
}
|
|
164
|
+
/** A pending invitation whose approval cannot be used any more is closed, so the next run asks afresh. A stored approved grant is never removed. */
|
|
165
|
+
function closePending(pending) {
|
|
166
|
+
pending.status = 'closed';
|
|
167
|
+
savePendingInvite(pending);
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Create (once) and await this invitation's approval, then keep the approved per-invite grant. Nothing the caller does
|
|
171
|
+
* after this - relay delegation, state, Share key, link or email - happens unless the result is `approved`.
|
|
172
|
+
*/
|
|
173
|
+
export async function obtainInviteKey(options) {
|
|
174
|
+
const { node, profile, key, transport, pending } = options;
|
|
175
|
+
const clock = options.now ?? Date.now;
|
|
176
|
+
const sleep = options.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
|
|
177
|
+
const stored = loadInviteGrant(pending.invitationId);
|
|
178
|
+
if (stored) {
|
|
179
|
+
if (stored.invitationId !== pending.invitationId)
|
|
180
|
+
throw new CourierError('bad-grant', 'This approval belongs to another invitation.');
|
|
181
|
+
const activated = await activateInviteGrant(node, profile, pending, stored.payload, clock());
|
|
182
|
+
if (activated.shareId !== stored.shareId)
|
|
183
|
+
throw new CourierError('bad-grant', 'The stored approval no longer matches its key.');
|
|
184
|
+
return { status: 'approved', shareId: stored.shareId };
|
|
185
|
+
}
|
|
186
|
+
if (Date.parse(pending.acceptanceExpiresAt) <= clock()) {
|
|
187
|
+
closePending(pending);
|
|
188
|
+
throw new CourierError('invite-expired', 'The approval for this invitation was not given in time; nothing was created.');
|
|
189
|
+
}
|
|
190
|
+
if (pending.transport === undefined) {
|
|
191
|
+
const created = await transport.create({ context: invitationContext(pending), key, host: profile.host });
|
|
192
|
+
pending.approvalUrl = created.approvalUrl;
|
|
193
|
+
pending.transport = created.transport;
|
|
194
|
+
savePendingInvite(pending);
|
|
195
|
+
}
|
|
196
|
+
options.onApprovalUrl?.(pending.approvalUrl, pending);
|
|
197
|
+
const deadline = clock() + options.waitMs;
|
|
198
|
+
for (;;) {
|
|
199
|
+
let result;
|
|
200
|
+
try {
|
|
201
|
+
result = await transport.poll(pending, key);
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
// The approver says it does not know this request (or its result): nothing more can come of it.
|
|
205
|
+
if (error instanceof CourierError && error.code === 'approval-unavailable')
|
|
206
|
+
closePending(pending);
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
savePendingInvite(pending);
|
|
210
|
+
if (result.status === 'approved') {
|
|
211
|
+
let activated;
|
|
212
|
+
try {
|
|
213
|
+
activated = await activateInviteGrant(node, profile, pending, result.payload, clock());
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
// A result that is not this request's valid approval is never retried against the same request. A host that could not be reached
|
|
217
|
+
// says nothing about the approval, so the pending invitation stays and the result is fetched again on the next run.
|
|
218
|
+
if (error instanceof CourierError && error.code !== 'activation-unavailable')
|
|
219
|
+
closePending(pending);
|
|
220
|
+
throw error;
|
|
221
|
+
}
|
|
222
|
+
if (keyIdUsedElsewhere(activated.shareId, pending.invitationId)) {
|
|
223
|
+
closePending(pending);
|
|
224
|
+
throw new CourierError('bad-grant', 'This approval was already used for another invitation; each invitation needs its own approval.');
|
|
225
|
+
}
|
|
226
|
+
secureWrite(grantDir(), pending.invitationId, {
|
|
227
|
+
v: 1, invitationId: pending.invitationId, shareId: activated.shareId, payload: result.payload,
|
|
228
|
+
expiresAt: activated.expiresAt.toISOString(), receivedAt: new Date(clock()).toISOString(),
|
|
229
|
+
});
|
|
230
|
+
await transport.acknowledge?.(pending, key);
|
|
231
|
+
return { status: 'approved', shareId: activated.shareId };
|
|
232
|
+
}
|
|
233
|
+
if (result.status === 'denied' || result.status === 'expired') {
|
|
234
|
+
closePending(pending);
|
|
235
|
+
throw new CourierError('invite-approval-refused', result.status === 'denied' ? 'The owner declined this invitation; nothing was created.' : 'The approval request expired before it was given; nothing was created.');
|
|
236
|
+
}
|
|
237
|
+
if (clock() >= deadline)
|
|
238
|
+
return { status: 'awaiting', approvalUrl: pending.approvalUrl };
|
|
239
|
+
await sleep(Math.min(2000, Math.max(0, deadline - clock())));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
export function closeInvite(pending) {
|
|
243
|
+
closePending(pending);
|
|
244
|
+
}
|
|
245
|
+
export function markInviteSent(pending) {
|
|
246
|
+
pending.status = 'sent';
|
|
247
|
+
savePendingInvite(pending);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Exactly one run may go on to create the relay, the Share key, the link and the email for an approved invitation:
|
|
251
|
+
* the marker is created exclusively and never removed. A run that finds it refuses, so a rerun or a concurrent run can
|
|
252
|
+
* never send a second email for the same approval. It also closes the pending invitation (the marker and any stored approved
|
|
253
|
+
* grant stay), so an attempt interrupted after the claim does not leave the invitation waiting forever: the next run asks the
|
|
254
|
+
* owner afresh, and the old approval is never used again.
|
|
255
|
+
*/
|
|
256
|
+
export function claimInviteSend(pending) {
|
|
257
|
+
mkdirOwnerOnly(pendingDir());
|
|
258
|
+
try {
|
|
259
|
+
fs.closeSync(fs.openSync(path.join(pendingDir(), `${pending.invitationId}.sending`), 'wx', 0o600));
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
if (error.code === 'EEXIST') {
|
|
263
|
+
// A concurrent run that already finished the send has recorded it as sent: that is never overwritten with closed.
|
|
264
|
+
if (loadPendingInvite(pending.invitationId)?.status !== 'sent')
|
|
265
|
+
closePending(pending);
|
|
266
|
+
throw new CourierError('invite-in-progress', 'This invitation was already sent or an earlier attempt did not finish; nothing more was sent. Run the command again to start a new invitation (a new owner approval).');
|
|
267
|
+
}
|
|
268
|
+
throw error;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
//# sourceMappingURL=invite-approval.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invite-approval.js","sourceRoot":"","sources":["../src/invite-approval.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { InviteApprovalTransport, PendingInvite } from './invite-approval.js';
|
|
2
|
+
import type { AgentKey } from './profile.js';
|
|
3
|
+
export interface OpenKeyInviteDeps {
|
|
4
|
+
fetch?: typeof fetch;
|
|
5
|
+
now?: () => number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* The OpenKey side of one invitation approval: a signed intent request, then repeatable requester-authenticated reads of
|
|
9
|
+
* its encrypted result. Result verification beyond the binding to this request (holder, owner, key, expiry) is done by
|
|
10
|
+
* the caller from the signed SIWE, never from anything the transport reports.
|
|
11
|
+
*/
|
|
12
|
+
export declare function openKeyInviteTransport(deps?: OpenKeyInviteDeps): InviteApprovalTransport & {
|
|
13
|
+
acknowledge(pending: PendingInvite, key: AgentKey): Promise<void>;
|
|
14
|
+
};
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { createDecipheriv, createECDH, createHash, createHmac, createPrivateKey, randomBytes, randomUUID, sign } from 'node:crypto';
|
|
2
|
+
import { buildShareInvitationApprovalSpec, createApprovalRequest, signerFromJwk } from '@tinycloud/share-envelope/links';
|
|
3
|
+
import { CourierError } from './errors.js';
|
|
4
|
+
import { resolveOpenKeyApiHost } from './grant.js';
|
|
5
|
+
import { loadProfile } from './profile.js';
|
|
6
|
+
const DEFAULT_LINKS_API = 'https://api.tinycloud.xyz';
|
|
7
|
+
const unavailable = (message) => new CourierError('approval-unavailable', message);
|
|
8
|
+
function origin(value, label) {
|
|
9
|
+
let url;
|
|
10
|
+
try {
|
|
11
|
+
url = new URL(value);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
throw unavailable(`${label} is not an origin.`);
|
|
15
|
+
}
|
|
16
|
+
const loopback = ['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname);
|
|
17
|
+
if (url.pathname !== '/' || url.search || url.hash || (url.protocol !== 'https:' && !(url.protocol === 'http:' && loopback)))
|
|
18
|
+
throw unavailable(`${label} must be an HTTPS origin.`);
|
|
19
|
+
return url.origin;
|
|
20
|
+
}
|
|
21
|
+
function sessionProof(state, key, action, resultRef, ackId) {
|
|
22
|
+
const jwk = key.jwk;
|
|
23
|
+
const jkt = createHash('sha256').update(JSON.stringify({ crv: 'Ed25519', kty: 'OKP', x: jwk.x })).digest('base64url');
|
|
24
|
+
const path = action === 'discover' ? `/api/approval-requests/${state.requestId}/result` : `/api/approval-results/${resultRef}/${action}`;
|
|
25
|
+
const header = Buffer.from(JSON.stringify({ alg: 'EdDSA', kid: jkt, typ: 'openkey-session-proof+jwt' })).toString('base64url');
|
|
26
|
+
const payload = Buffer.from(JSON.stringify({
|
|
27
|
+
client_id: 'openkey-approval-result-v1',
|
|
28
|
+
cred_hash: createHash('sha256').update(JSON.stringify([action, state.requestId, state.bodyCid, resultRef, ackId])).digest('base64url'),
|
|
29
|
+
htm: 'POST', htu: state.apiOrigin + path, iat: Math.floor(Date.now() / 1000), jti: randomBytes(24).toString('base64url'),
|
|
30
|
+
})).toString('base64url');
|
|
31
|
+
const input = `${header}.${payload}`;
|
|
32
|
+
const signature = sign(null, Buffer.from(input), createPrivateKey({ key: { kty: jwk.kty, crv: jwk.crv, x: jwk.x, d: jwk.d }, format: 'jwk' }));
|
|
33
|
+
return `${input}.${signature.toString('base64url')}`;
|
|
34
|
+
}
|
|
35
|
+
function canonicalB64(value) {
|
|
36
|
+
if (typeof value !== 'string' || !/^[A-Za-z0-9_-]+$/.test(value))
|
|
37
|
+
throw unavailable('OpenKey returned an invalid result.');
|
|
38
|
+
const decoded = Buffer.from(value, 'base64url');
|
|
39
|
+
if (decoded.toString('base64url') !== value)
|
|
40
|
+
throw unavailable('OpenKey returned an invalid result.');
|
|
41
|
+
return decoded;
|
|
42
|
+
}
|
|
43
|
+
/** The result is AES-GCM under an ECDH-P-256 key only this request's relay key can derive. Node's ECDH refuses off-curve points. */
|
|
44
|
+
function decryptResult(envelope, requestId, relay) {
|
|
45
|
+
const value = envelope;
|
|
46
|
+
if (!value || value.version !== 1 || value.algorithm !== 'ECDH-P256-A256GCM')
|
|
47
|
+
throw unavailable('OpenKey returned an unsupported result.');
|
|
48
|
+
const x = canonicalB64(value.ephemeralPublicJwk?.x);
|
|
49
|
+
const y = canonicalB64(value.ephemeralPublicJwk?.y);
|
|
50
|
+
const nonce = canonicalB64(value.nonce);
|
|
51
|
+
const ciphertext = canonicalB64(value.ciphertext);
|
|
52
|
+
if (x.length !== 32 || y.length !== 32 || nonce.length !== 12 || ciphertext.length <= 16)
|
|
53
|
+
throw unavailable('OpenKey returned an invalid result.');
|
|
54
|
+
let secret;
|
|
55
|
+
try {
|
|
56
|
+
secret = relay.computeSecret(Buffer.concat([Buffer.from([4]), x, y]));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
throw unavailable('OpenKey returned an invalid result key.');
|
|
60
|
+
}
|
|
61
|
+
const extracted = createHmac('sha256', Buffer.from(requestId)).update(secret).digest();
|
|
62
|
+
const aesKey = createHmac('sha256', extracted).update(Buffer.from('openkey-device-relay-v1')).update(Buffer.from([1])).digest();
|
|
63
|
+
const decipher = createDecipheriv('aes-256-gcm', aesKey, nonce);
|
|
64
|
+
decipher.setAAD(Buffer.from(requestId));
|
|
65
|
+
decipher.setAuthTag(ciphertext.subarray(ciphertext.length - 16));
|
|
66
|
+
try {
|
|
67
|
+
const opened = JSON.parse(Buffer.concat([decipher.update(ciphertext.subarray(0, -16)), decipher.final()]).toString('utf8'));
|
|
68
|
+
if (opened && typeof opened === 'object' && !Array.isArray(opened))
|
|
69
|
+
return opened;
|
|
70
|
+
}
|
|
71
|
+
catch { /* falls through */ }
|
|
72
|
+
throw unavailable('OpenKey returned an unreadable result.');
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* The OpenKey side of one invitation approval: a signed intent request, then repeatable requester-authenticated reads of
|
|
76
|
+
* its encrypted result. Result verification beyond the binding to this request (holder, owner, key, expiry) is done by
|
|
77
|
+
* the caller from the signed SIWE, never from anything the transport reports.
|
|
78
|
+
*/
|
|
79
|
+
export function openKeyInviteTransport(deps = {}) {
|
|
80
|
+
const fetchFn = deps.fetch ?? fetch;
|
|
81
|
+
const now = deps.now ?? Date.now;
|
|
82
|
+
const post = async (state, key, action) => {
|
|
83
|
+
const resultRef = action === 'discover' ? '' : state.resultRef ?? '';
|
|
84
|
+
const path = action === 'discover' ? `/api/approval-requests/${state.requestId}/result` : `/api/approval-results/${resultRef}/${action}`;
|
|
85
|
+
const body = action === 'discover'
|
|
86
|
+
? { bodyCid: state.bodyCid, header: state.record.header, signature: state.record.signature }
|
|
87
|
+
: { requestId: state.requestId, bodyCid: state.bodyCid, ...(action === 'ack' ? { ackId: state.ackId } : {}) };
|
|
88
|
+
return fetchFn(state.apiOrigin + path, {
|
|
89
|
+
method: 'POST', credentials: 'omit', redirect: 'error', referrerPolicy: 'no-referrer',
|
|
90
|
+
headers: { 'content-type': 'application/json', 'OpenKey-Session-Proof': sessionProof(state, key, action, resultRef, action === 'ack' ? state.ackId : '') },
|
|
91
|
+
body: JSON.stringify(body), signal: AbortSignal.timeout(10_000),
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
return {
|
|
95
|
+
async create({ context, key, host }) {
|
|
96
|
+
const profile = loadProfile();
|
|
97
|
+
const openkeyOrigin = origin(profile.openkeyHost, 'OpenKey');
|
|
98
|
+
const apiOrigin = origin(resolveOpenKeyApiHost({ env: process.env.COURIER_OPENKEY_API_HOST, openkeyHost: openkeyOrigin }), 'OpenKey API');
|
|
99
|
+
const jwk = key.jwk;
|
|
100
|
+
const signer = signerFromJwk(jwk);
|
|
101
|
+
const spec = buildShareInvitationApprovalSpec({ targetDid: signer.did, targetPublicJwk: { kty: jwk.kty, crv: jwk.crv, x: jwk.x }, nodeOrigin: host, context, now: now() });
|
|
102
|
+
const relay = createECDH('prime256v1');
|
|
103
|
+
relay.generateKeys();
|
|
104
|
+
const point = relay.getPublicKey();
|
|
105
|
+
const request = { ...spec, resultEncryptionPublicJwk: { kty: 'EC', crv: 'P-256', x: point.subarray(1, 33).toString('base64url'), y: point.subarray(33).toString('base64url') } };
|
|
106
|
+
let created;
|
|
107
|
+
try {
|
|
108
|
+
created = await createApprovalRequest({ request, issuerKey: signer, apiOrigin: origin(process.env.COURIER_LINKS_API_ORIGIN ?? DEFAULT_LINKS_API, 'Links API'),
|
|
109
|
+
openkeyOrigin, expiresAt: new Date(context.acceptanceExpiresAt), now: now(), fetch: fetchFn });
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
throw unavailable('The approval request could not be created.');
|
|
113
|
+
}
|
|
114
|
+
const state = { requestId: created.id, bodyCid: created.bodyCid, record: created.record, request, apiOrigin,
|
|
115
|
+
relayPrivateKey: relay.getPrivateKey().toString('base64url'), ackId: randomUUID() };
|
|
116
|
+
return { approvalUrl: created.link, transport: state };
|
|
117
|
+
},
|
|
118
|
+
async poll(pending, key) {
|
|
119
|
+
const state = pending.transport;
|
|
120
|
+
if (!state)
|
|
121
|
+
throw unavailable('No approval request exists for this invitation.');
|
|
122
|
+
if (!state.resultEnvelope) {
|
|
123
|
+
let response;
|
|
124
|
+
try {
|
|
125
|
+
response = await post(state, key, 'discover');
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
return { status: 'pending' };
|
|
129
|
+
}
|
|
130
|
+
if (response.status === 202)
|
|
131
|
+
return { status: 'pending' };
|
|
132
|
+
if (!response.ok) {
|
|
133
|
+
const failed = (await response.clone().json().catch(() => null));
|
|
134
|
+
const code = failed?.code;
|
|
135
|
+
if (failed?.status === 'denied')
|
|
136
|
+
return { status: 'denied' };
|
|
137
|
+
if (code === 'expired_request' || code === 'expired_result')
|
|
138
|
+
return { status: 'expired' };
|
|
139
|
+
if (code === 'not_found' || code === 'request_binding' || code === 'invalid_proof')
|
|
140
|
+
throw unavailable('OpenKey does not recognise this approval request.');
|
|
141
|
+
return { status: 'pending' };
|
|
142
|
+
}
|
|
143
|
+
const found = await response.json();
|
|
144
|
+
if (typeof found.resultRef !== 'string' || !/^[A-Za-z0-9_-]{20,128}$/.test(found.resultRef) || typeof found.expiresAt !== 'string')
|
|
145
|
+
throw unavailable('OpenKey returned an invalid result reference.');
|
|
146
|
+
state.resultRef = found.resultRef;
|
|
147
|
+
state.resultExpiresAt = found.expiresAt;
|
|
148
|
+
let fetched;
|
|
149
|
+
try {
|
|
150
|
+
fetched = await post(state, key, 'fetch');
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return { status: 'pending' };
|
|
154
|
+
}
|
|
155
|
+
if (!fetched.ok)
|
|
156
|
+
return { status: 'pending' };
|
|
157
|
+
const result = await fetched.json();
|
|
158
|
+
if (result.requestId !== state.requestId || result.bodyCid !== state.bodyCid || result.resultRef !== state.resultRef || result.expiresAt !== state.resultExpiresAt || !result.relay) {
|
|
159
|
+
throw unavailable('The approval result does not match this request.');
|
|
160
|
+
}
|
|
161
|
+
state.resultEnvelope = result.relay;
|
|
162
|
+
}
|
|
163
|
+
const relay = createECDH('prime256v1');
|
|
164
|
+
relay.setPrivateKey(Buffer.from(state.relayPrivateKey, 'base64url'));
|
|
165
|
+
const opened = decryptResult(state.resultEnvelope, state.requestId, relay);
|
|
166
|
+
const delegation = opened.delegation;
|
|
167
|
+
if (opened.resultVersion !== 1 || opened.requestId !== state.requestId || opened.requestDigest !== state.bodyCid
|
|
168
|
+
|| opened.requesterDid !== state.request.issuer || opened.targetDid !== state.request.targetDid || !delegation || typeof delegation !== 'object') {
|
|
169
|
+
throw new CourierError('bad-grant', 'The approval result does not belong to this request.');
|
|
170
|
+
}
|
|
171
|
+
return { status: 'approved', payload: delegation };
|
|
172
|
+
},
|
|
173
|
+
async acknowledge(pending, key) {
|
|
174
|
+
const state = pending.transport;
|
|
175
|
+
if (!state?.resultRef)
|
|
176
|
+
return;
|
|
177
|
+
try {
|
|
178
|
+
await post(state, key, 'ack');
|
|
179
|
+
}
|
|
180
|
+
catch { /* the stored approval is already committed; OpenKey may be told on the next run */ }
|
|
181
|
+
},
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=invite-openkey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invite-openkey.js","sourceRoot":"","sources":["../src/invite-openkey.ts"],"names":[],"mappings":"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"}
|
package/dist/main.js
CHANGED
|
@@ -14,6 +14,7 @@ import { cmdBroker, cmdRunApproved } from './broker.js';
|
|
|
14
14
|
import { cmdCredential } from './credential.js';
|
|
15
15
|
import { courierVersion } from './version.js';
|
|
16
16
|
import { cmdStart } from './guided.js';
|
|
17
|
+
import { cmdStatus } from './status.js';
|
|
17
18
|
import { cmdInvite, cmdJoin } from './invitation.js';
|
|
18
19
|
function usage() {
|
|
19
20
|
const name = programName();
|
|
@@ -51,12 +52,13 @@ Setup & pairing (humans run these):
|
|
|
51
52
|
Accept artifact A, B or C; prints B or C to pass on
|
|
52
53
|
pair renew [peer] [--force] Renew both directions; humans or watcher only
|
|
53
54
|
pair renew <peer> --renew-artifact [--force] Emit renewed C artifact for handoff; receiver runs pair accept
|
|
54
|
-
revoke <peer> Stop renewing
|
|
55
|
+
revoke <peer> Stop renewing and remove the peer; their access ends when the current grant expires. Files you already shared stay available until each share expires or you revoke it (\`tinycloud share revoke <id>\`).
|
|
55
56
|
|
|
56
57
|
Threads (agents run these):
|
|
57
58
|
send <peer> (--new <subject> | --thread <id>) [--text t | --file f | stdin]
|
|
58
59
|
[--intent request|ask|answer|update|inform] [--ask "…"]… [--constraint "…"]…
|
|
59
60
|
[--reply-to <messageId>] [--task-ref <taskId>]…
|
|
61
|
+
status [--peer <peer>] [--json] Saved per-side expiry
|
|
60
62
|
inbox [--json] [--peek] New counterparty messages; --peek skips receipt updates
|
|
61
63
|
read <threadId> [--peer p] [--json]
|
|
62
64
|
The merged thread: both sides' messages + tasks
|
|
@@ -176,6 +178,7 @@ export async function run(argv) {
|
|
|
176
178
|
case 'pair': return cmdPair(sub);
|
|
177
179
|
case 'revoke': return cmdRevoke(sub);
|
|
178
180
|
case 'send': return cmdSend(sub);
|
|
181
|
+
case 'status': return cmdStatus(sub);
|
|
179
182
|
case 'inbox': return cmdInbox(sub);
|
|
180
183
|
case 'read': return cmdRead(sub);
|
|
181
184
|
case 'task': return cmdTask(sub);
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAmB,MAAM,WAAW,CAAC;AACvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,EACL,WAAW,EAAE,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,GAClH,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAErD,SAAS,KAAK;IACZ,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,OAAO,GAAG,IAAI;;SAEP,IAAI;;;;;;;;;;;;;;;;;;;;;8CAqBiC,IAAI
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
package/dist/status.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ParsedArgs } from './args.js';
|
|
2
|
+
import { type StoredPeer } from './profile.js';
|
|
3
|
+
export declare const EXPIRY_WARNING_MS: number;
|
|
4
|
+
export type GrantExpiry = {
|
|
5
|
+
state: 'missing' | 'unknown' | 'expired' | 'expiring' | 'current';
|
|
6
|
+
expiresAt: string | null;
|
|
7
|
+
};
|
|
8
|
+
/** Local expiry metadata only: this does not verify authority or remote access. */
|
|
9
|
+
export declare function grantExpiry(expiresAt: string | undefined, now?: number): GrantExpiry;
|
|
10
|
+
export declare function peerExpiryStatus(peer: StoredPeer, now?: number): {
|
|
11
|
+
peer: string;
|
|
12
|
+
pairing: "pending-A" | "awaiting-C" | "paired";
|
|
13
|
+
inbound: GrantExpiry;
|
|
14
|
+
outbound: GrantExpiry;
|
|
15
|
+
remoteReadability: "not-checked";
|
|
16
|
+
renewal: {
|
|
17
|
+
state: "unknown";
|
|
18
|
+
command: string | null;
|
|
19
|
+
};
|
|
20
|
+
warnings: string[];
|
|
21
|
+
};
|
|
22
|
+
/** Works even after grants lapse: never initializes a node, renews, or sends. */
|
|
23
|
+
export declare function cmdStatus(args: ParsedArgs): void;
|