@substrat-run/vertical-auth 0.21.1 → 0.22.1
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/become-link.d.ts +17 -0
- package/dist/become-link.d.ts.map +1 -0
- package/dist/become-link.js +12 -0
- package/dist/become-link.js.map +1 -0
- package/dist/identity-do.d.ts +13 -10
- package/dist/identity-do.d.ts.map +1 -1
- package/dist/identity-do.js +22 -16
- package/dist/identity-do.js.map +1 -1
- package/dist/invite-routes.d.ts +80 -12
- package/dist/invite-routes.d.ts.map +1 -1
- package/dist/invite-routes.js +121 -20
- package/dist/invite-routes.js.map +1 -1
- package/dist/member-directory.d.ts +64 -10
- package/dist/member-directory.d.ts.map +1 -1
- package/dist/member-directory.js +77 -18
- package/dist/member-directory.js.map +1 -1
- package/dist/owner-claim-link.d.ts +1 -1
- package/dist/owner-claim-routes.d.ts +4 -6
- package/dist/owner-claim-routes.d.ts.map +1 -1
- package/dist/owner-claim-routes.js +9 -23
- package/dist/owner-claim-routes.js.map +1 -1
- package/dist/owner-seat.d.ts +9 -17
- package/dist/owner-seat.d.ts.map +1 -1
- package/dist/owner-seat.js +12 -38
- package/dist/owner-seat.js.map +1 -1
- package/package.json +5 -5
package/dist/invite-routes.js
CHANGED
|
@@ -17,6 +17,14 @@
|
|
|
17
17
|
* and the directory then resolves them as that member. Revoking takes the principal's scope
|
|
18
18
|
* roles back and then removes the invite row.
|
|
19
19
|
*
|
|
20
|
+
* Since #1686 the token is the secret of a `become` capability in the scope's own Durable
|
|
21
|
+
* Object, minted by the inviter under a bound (they must hold everything the invited
|
|
22
|
+
* principal holds): single use, revocable, and on the spine — its mint as
|
|
23
|
+
* `capability.become-minted` with the inviter as actor, its accept as `capability.exercised`.
|
|
24
|
+
* It has no expiry, as an invite never had, and the inviter is not re-checked at accept:
|
|
25
|
+
* the role was bounded when it was granted, and withdrawing the invite is the lever. An
|
|
26
|
+
* invite minted before #1686 is redeemed the old way, by hash (`claimInvite`).
|
|
27
|
+
*
|
|
20
28
|
* Who may invite, and at which role, are two questions (#1931). The vertical's admin gate
|
|
21
29
|
* answers the first — may this caller manage members at all. The second is the kernel's
|
|
22
30
|
* assignment bound (`ctx.canAssign`): a caller may confer a role only if they already hold
|
|
@@ -32,10 +40,13 @@
|
|
|
32
40
|
* than this one with more fields.
|
|
33
41
|
*/
|
|
34
42
|
import { HTTPException } from 'hono/http-exception';
|
|
35
|
-
import { coverage, coverageRefusal, principalId, z } from '@substrat-run/contracts';
|
|
36
|
-
import { ulid } from '@substrat-run/kernel';
|
|
37
|
-
import {
|
|
43
|
+
import { BECOME_LINK_STATES_MAX_IDS, boundedBecomeMint, boundedBecomeRevoke, becomeLinkState, capabilityId, coverage, coverageRefusal, principalId, z, } from '@substrat-run/contracts';
|
|
44
|
+
import { capabilityTokenHash, plausibleCapabilitySecret, ulid } from '@substrat-run/kernel';
|
|
45
|
+
import { redeemBecomeLink } from './become-link.js';
|
|
46
|
+
import { invitePath, sha256Hex } from './owner-claim-link.js';
|
|
38
47
|
import { bodyOf } from './request-body.js';
|
|
48
|
+
/** The label every member invite's capability carries — what an operator's capability read shows. */
|
|
49
|
+
export const MEMBER_INVITE_LABEL = 'member invite';
|
|
39
50
|
const inviteCaller = z.object({ principal: principalId });
|
|
40
51
|
/** The body `POST /api/invites` takes. */
|
|
41
52
|
export const inviteBody = z.object({
|
|
@@ -52,34 +63,117 @@ export const uncovered = (missing, roleKey, act) => new HTTPException(403, { mes
|
|
|
52
63
|
* own `POST /api/invites` and the platform's `/internal/members/invite` (vertical-host), so the
|
|
53
64
|
* two doors cannot drift on the token, the hash, or the order.
|
|
54
65
|
*
|
|
55
|
-
* Pre-mint a principal
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
66
|
+
* Pre-mint a principal, then three writes, each failing closed:
|
|
67
|
+
* 1. grant it the role through `grant`, which MUST be the bounded grant (check and write in one
|
|
68
|
+
* scope task) — a refusal returns its coverage and nothing else is written;
|
|
69
|
+
* 2. mint its link (#1686): a `become` capability for that principal, single use and with no
|
|
70
|
+
* expiry (an invite has never had one), bounded by what the inviter holds — the scope's own
|
|
71
|
+
* record, on the spine as `capability.become-minted`. A refusal takes the grant back;
|
|
72
|
+
* 3. record the invite under the secret's hash, naming the capability.
|
|
73
|
+
* The grant comes first: a row whose principal holds nothing is a link to no access, while a
|
|
74
|
+
* grant with no row is inert — nobody can bind to it, and a capability with no row is refused
|
|
75
|
+
* before its exchange. The writes are two Durable Objects with no transaction between them, so a
|
|
76
|
+
* failed record revokes the capability and takes the grant back (`rollback`) before the failure
|
|
77
|
+
* is rethrown: inert is not harmless when every retry would mint another orphan. If a rollback
|
|
78
|
+
* step fails too, the ORIGINAL failure is what the caller hears.
|
|
63
79
|
*/
|
|
64
80
|
export async function mintMemberInvite(steps, input) {
|
|
65
81
|
const principal = principalId.parse(ulid());
|
|
66
|
-
// A long, URL-safe token; only its hash is stored. Two UUIDs = 256 bits of entropy.
|
|
67
|
-
const token = claimToken();
|
|
68
82
|
const bound = coverage.safeParse(await steps.grant(principal));
|
|
69
83
|
if (!bound.success) {
|
|
70
84
|
throw new HTTPException(500, { message: 'the canAssign bound did not answer with a coverage — refusing' });
|
|
71
85
|
}
|
|
72
86
|
if (!bound.data.covered)
|
|
73
87
|
return { ok: false, coverage: bound.data };
|
|
88
|
+
const ungrant = () => steps.rollback(principal).catch(() => undefined);
|
|
89
|
+
let minted;
|
|
74
90
|
try {
|
|
75
|
-
await steps.
|
|
91
|
+
minted = boundedBecomeMint.parse(await steps.mint({ principal, maxUses: 1, label: MEMBER_INVITE_LABEL }));
|
|
76
92
|
}
|
|
77
93
|
catch (err) {
|
|
78
|
-
await
|
|
94
|
+
await ungrant();
|
|
95
|
+
throw err;
|
|
96
|
+
}
|
|
97
|
+
if (!minted.ok) {
|
|
98
|
+
await ungrant();
|
|
99
|
+
// The grant just made is what the principal holds; it holds nothing only when the role
|
|
100
|
+
// carries no permission at all — nothing to invite anyone into. The principal was minted
|
|
101
|
+
// just now, so no link to it can have been exchanged; that refusal is answered all the same.
|
|
102
|
+
if (!('coverage' in minted)) {
|
|
103
|
+
throw new HTTPException(409, {
|
|
104
|
+
message: minted.refused === 'target-holds-nothing'
|
|
105
|
+
? `'${input.roleKey}' confers nothing here — there is nothing to invite anyone into`
|
|
106
|
+
: 'this invite\'s principal is already claimed — refusing a second link to it',
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return { ok: false, coverage: minted.coverage };
|
|
110
|
+
}
|
|
111
|
+
const link = minted.minted;
|
|
112
|
+
try {
|
|
113
|
+
await steps.record(principal, await capabilityTokenHash(link.secret), link.id);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
await steps.revokeCapability(link.id).catch(() => undefined);
|
|
117
|
+
await ungrant();
|
|
79
118
|
throw err;
|
|
80
119
|
}
|
|
81
120
|
const origin = input.origin.replace(/\/$/, '');
|
|
82
|
-
return { ok: true, invite: { principal, roleKey: input.roleKey, email: input.email, acceptUrl: `${origin}${invitePath(
|
|
121
|
+
return { ok: true, invite: { principal, roleKey: input.roleKey, email: input.email, acceptUrl: `${origin}${invitePath(link.secret)}` } };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Join each invite to where its link stands (#1686), in ONE read of the scope — the list every
|
|
125
|
+
* pending-invite door shows, so a link the scope revoked (its principal's holdings changed) or that
|
|
126
|
+
* expired is never listed as open. A legacy hash-only invite has no link to read: `link: null`.
|
|
127
|
+
*/
|
|
128
|
+
export async function withLinkStates(rows, states) {
|
|
129
|
+
const ids = rows.flatMap((r) => (r.capabilityId ? [capabilityId.parse(r.capabilityId)] : []));
|
|
130
|
+
// In pages of the read's cap (`BECOME_LINK_STATES_MAX_IDS`), which refuses rather than truncates.
|
|
131
|
+
const read = [];
|
|
132
|
+
for (let at = 0; at < ids.length; at += BECOME_LINK_STATES_MAX_IDS) {
|
|
133
|
+
const page = ids.slice(at, at + BECOME_LINK_STATES_MAX_IDS);
|
|
134
|
+
const answer = (await states(page)).map((s) => becomeLinkState.parse(s));
|
|
135
|
+
if (answer.length !== page.length)
|
|
136
|
+
break;
|
|
137
|
+
read.push(...answer);
|
|
138
|
+
}
|
|
139
|
+
if (read.length !== ids.length)
|
|
140
|
+
throw new HTTPException(500, { message: 'the scope answered a link state per id it was not asked for — refusing' });
|
|
141
|
+
const byId = new Map(ids.map((id, i) => [id, read[i]]));
|
|
142
|
+
return rows.map(({ capabilityId: id, ...row }) => ({ ...row, link: id ? byId.get(id) : null }));
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Accept an invite (#1150, #1686) — the one copy every accept door runs. A capability secret is
|
|
146
|
+
* redeemed as every `become` link is (`redeemBecomeLink`): checked against the directory before
|
|
147
|
+
* the scope spends its use, exchanged, then bound only while the row still names that capability
|
|
148
|
+
* and principal. A token that is not a capability secret is a LEGACY hash-only invite, redeemed by
|
|
149
|
+
* hash (`claimInvite`). Null for every refusal, one answer.
|
|
150
|
+
*/
|
|
151
|
+
export async function acceptMemberInvite(deps, scopeId, sub, token) {
|
|
152
|
+
if (!plausibleCapabilitySecret(token)) {
|
|
153
|
+
// LEGACY — a hash-only invite (see `claimInvite`).
|
|
154
|
+
return deps.directory.claimInvite(scopeId, sub, await sha256Hex(token));
|
|
155
|
+
}
|
|
156
|
+
return redeemBecomeLink({
|
|
157
|
+
matches: (hash) => deps.directory.inviteMatches(scopeId, hash),
|
|
158
|
+
exchange: deps.exchange,
|
|
159
|
+
bind: (capabilityId, principal) => deps.directory.claimInviteByCapability(scopeId, sub, capabilityId, principal),
|
|
160
|
+
}, token);
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Withdraw an invite's link and then its row (#1686), once the caller's bound has taken the
|
|
164
|
+
* roles. The link goes first, named by the row: a revoke that fails leaves the row in place, so
|
|
165
|
+
* the withdrawal fails as a whole and its retry finds the link again — the scope's own record
|
|
166
|
+
* and the directory never part company. Revoking is idempotent, so a retry after a revoke that
|
|
167
|
+
* landed and a delete that did not is the same call. Then the row goes, which stops an accept.
|
|
168
|
+
*/
|
|
169
|
+
export async function withdrawMemberInvite(steps, scopeId, principal) {
|
|
170
|
+
const link = await steps.directory.inviteLink(scopeId, principal);
|
|
171
|
+
if (link) {
|
|
172
|
+
const revoke = boundedBecomeRevoke.parse(await steps.revokeCapability(capabilityId.parse(link)));
|
|
173
|
+
if (!revoke.ok)
|
|
174
|
+
throw uncovered(revoke.coverage.missing, principal, 'withdraw the link of');
|
|
175
|
+
}
|
|
176
|
+
await steps.directory.revokeInvite(scopeId, principal);
|
|
83
177
|
}
|
|
84
178
|
/**
|
|
85
179
|
* Mount the four invite routes on a vertical's Hono app:
|
|
@@ -106,6 +200,9 @@ export function mountInviteRoutes(app, deps) {
|
|
|
106
200
|
if (typeof deps.assignScopeRoleBounded !== 'function') {
|
|
107
201
|
throw new HTTPException(500, { message: 'invites are mounted without the bounded grant — refusing to confer an unbounded role' });
|
|
108
202
|
}
|
|
203
|
+
if (typeof deps.mintBecomeCapabilityBounded !== 'function' || typeof deps.revokeBecomeCapability !== 'function') {
|
|
204
|
+
throw new HTTPException(500, { message: 'invites are mounted without the capability verbs — refusing to mint a link nothing can revoke' });
|
|
205
|
+
}
|
|
109
206
|
const parsed = inviteCaller.safeParse(caller);
|
|
110
207
|
if (!parsed.success) {
|
|
111
208
|
throw new HTTPException(500, { message: 'the admin gate named no caller — refusing to confer a role the bound cannot be asked about' });
|
|
@@ -124,7 +221,9 @@ export function mountInviteRoutes(app, deps) {
|
|
|
124
221
|
app.get('/api/invites', async (c) => {
|
|
125
222
|
const node = await deps.nodeFor(c.req.raw, c.env);
|
|
126
223
|
await deps.requireAdmin(c);
|
|
127
|
-
|
|
224
|
+
const rows = await deps.directory(c.env, node).listInvites(node.scopeId);
|
|
225
|
+
const invites = await withLinkStates(rows, (ids) => deps.becomeLinkStates(c.env, node, ids));
|
|
226
|
+
return c.json({ roles: [...deps.roles], invites });
|
|
128
227
|
});
|
|
129
228
|
app.post('/api/invites', async (c) => {
|
|
130
229
|
const node = await deps.nodeFor(c.req.raw, c.env);
|
|
@@ -135,7 +234,9 @@ export function mountInviteRoutes(app, deps) {
|
|
|
135
234
|
throw new HTTPException(400, { message: `unknown role '${roleKey}'` });
|
|
136
235
|
const minted = await mintMemberInvite({
|
|
137
236
|
grant: (assignee) => deps.assignScopeRoleBounded(c.env, node, caller.principal, assignee, roleKey),
|
|
138
|
-
|
|
237
|
+
mint: (link) => deps.mintBecomeCapabilityBounded(c.env, node, caller.principal, link),
|
|
238
|
+
record: (principal, tokenHash, link) => deps.directory(c.env, node).createInvite(node.scopeId, principal, roleKey, email ?? null, tokenHash, link),
|
|
239
|
+
revokeCapability: (link) => deps.revokeBecomeCapability(c.env, node, link, caller.principal),
|
|
139
240
|
rollback: (principal) => deps.revokeScopeRole(c.env, node.scopeId, principal, roleKey),
|
|
140
241
|
}, { roleKey, email: email ?? null, origin: originOf(c.req.raw) });
|
|
141
242
|
if (!minted.ok)
|
|
@@ -160,7 +261,7 @@ export function mountInviteRoutes(app, deps) {
|
|
|
160
261
|
// principal holding nothing.
|
|
161
262
|
const taken = await deps.revokeScopeRolesBounded(c.env, node, caller.principal, principal.data);
|
|
162
263
|
assertCoverage(taken.coverage, principal.data, 'withdraw the invite of');
|
|
163
|
-
await directory.
|
|
264
|
+
await withdrawMemberInvite({ directory, revokeCapability: (link) => deps.revokeBecomeCapability(c.env, node, link, caller.principal) }, node.scopeId, principal.data);
|
|
164
265
|
}
|
|
165
266
|
return c.body(null, 204);
|
|
166
267
|
});
|
|
@@ -176,7 +277,7 @@ export function mountInviteRoutes(app, deps) {
|
|
|
176
277
|
if (!subject)
|
|
177
278
|
throw new HTTPException(401, { message: 'sign in before accepting an invite' });
|
|
178
279
|
const { token } = await bodyOf(c, acceptInviteBody);
|
|
179
|
-
const principal = await deps.directory(c.env, node).
|
|
280
|
+
const principal = await acceptMemberInvite({ directory: deps.directory(c.env, node), exchange: (secret) => deps.exchangeCapability(c.env, node, secret) }, node.scopeId, subject.sub, token);
|
|
180
281
|
if (!principal)
|
|
181
282
|
throw new HTTPException(400, { message: 'this invite is invalid or already used' });
|
|
182
283
|
return c.json({ ok: true, principal });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invite-routes.js","sourceRoot":"","sources":["../src/invite-routes.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"invite-routes.js","sourceRoot":"","sources":["../src/invite-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,13 @@
|
|
|
7
7
|
* An invite is a pre-minted principal + a role the inviter already granted at scope level,
|
|
8
8
|
* waiting for a login to claim it by token. Only the token's HASH is stored — the token itself
|
|
9
9
|
* lives in the accept link, never here, so a read of this table cannot mint access.
|
|
10
|
+
*
|
|
11
|
+
* Since #1686 the token is the secret of a `become` capability in the scope's own Durable
|
|
12
|
+
* Object (single use, revocable, on the spine), and `capability_id` names it: the scope judges
|
|
13
|
+
* the secret, this row says which capability IS the invite and which principal it seats. A row
|
|
14
|
+
* with no `capability_id` is LEGACY — hash alone, as every invite was before #1686 and as
|
|
15
|
+
* ticket0's own desk-invite flow still writes them — and is still redeemed the old way, by hash;
|
|
16
|
+
* an invite has no expiry, so nothing ages those out (see `claimInvite`).
|
|
10
17
|
*/
|
|
11
18
|
import type { RegistrySql } from './site-registry.js';
|
|
12
19
|
export { migrateOwnerSeat, unbindPrincipal } from './owner-seat.js';
|
|
@@ -14,12 +21,23 @@ export type { RegistrySql } from './site-registry.js';
|
|
|
14
21
|
export declare const INVITE_DDL: string[];
|
|
15
22
|
/** The whole directory an invite touches: the identity (and owner-seat) tables, then the invites. */
|
|
16
23
|
export declare const MEMBER_DIRECTORY_DDL: readonly string[];
|
|
17
|
-
/**
|
|
24
|
+
/**
|
|
25
|
+
* Bring an `invite` table from before #1686 up to date: `CREATE TABLE IF NOT EXISTS` leaves an
|
|
26
|
+
* existing table alone, so a directory whose storage predates `capability_id` needs the one
|
|
27
|
+
* `ALTER`, and every row it had reads as legacy (NULL). Idempotent — run it after the DDL.
|
|
28
|
+
*/
|
|
29
|
+
export declare function migrateInvites(sql: RegistrySql): void;
|
|
30
|
+
/**
|
|
31
|
+
* An outstanding invite as the directory returns it — never its token. `capabilityId` names the
|
|
32
|
+
* `become` capability its link is (#1686), so a list can ask the scope where that link stands;
|
|
33
|
+
* null for a legacy hash-only invite.
|
|
34
|
+
*/
|
|
18
35
|
export type InviteRow = {
|
|
19
36
|
principal: string;
|
|
20
37
|
roleKey: string;
|
|
21
38
|
email: string | null;
|
|
22
39
|
createdAt: number;
|
|
40
|
+
capabilityId: string | null;
|
|
23
41
|
};
|
|
24
42
|
/** One principal as the identity directory knows it at a scope (#1150). */
|
|
25
43
|
export type MemberBinding = {
|
|
@@ -27,20 +45,56 @@ export type MemberBinding = {
|
|
|
27
45
|
logins: number;
|
|
28
46
|
email: string | null;
|
|
29
47
|
};
|
|
30
|
-
|
|
48
|
+
/**
|
|
49
|
+
* Record an invite under its token's hash. `capabilityId` names the `become` capability whose
|
|
50
|
+
* secret the token is (#1686); null writes a legacy hash-only row, which this package's own
|
|
51
|
+
* invite routes no longer mint.
|
|
52
|
+
*/
|
|
53
|
+
export declare function createInvite(sql: RegistrySql, scopeId: string, principal: string, roleKey: string, email: string | null, tokenHash: string, capabilityId?: string | null): void;
|
|
31
54
|
/** The scope's outstanding (unclaimed) invites, newest first. No token. */
|
|
32
55
|
export declare function listInvites(sql: RegistrySql, scopeId: string): InviteRow[];
|
|
33
56
|
/** One outstanding invite by its pre-minted principal, or null (#1931). */
|
|
34
57
|
export declare function getInvite(sql: RegistrySql, scopeId: string, principal: string): InviteRow | null;
|
|
35
58
|
export declare function inviteExists(sql: RegistrySql, scopeId: string, tokenHash: string): boolean;
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
*
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
*
|
|
59
|
+
/**
|
|
60
|
+
* Withdraw an unclaimed invite by its pre-minted principal. Returns the `become` capability its
|
|
61
|
+
* link was (#1686), or null for a legacy invite, or none. Deleting the row is what stops an
|
|
62
|
+
* accept here; a withdrawal revokes the link in the scope BEFORE this (`inviteLink`).
|
|
63
|
+
*/
|
|
64
|
+
export declare function revokeInvite(sql: RegistrySql, scopeId: string, principal: string): string | null;
|
|
65
|
+
/**
|
|
66
|
+
* The `become` capability an open invite's link is (#1686), or null — a legacy invite, or none.
|
|
67
|
+
* What a withdrawal revokes FIRST, while the row is still there to name it: a revoke that fails
|
|
68
|
+
* leaves the row, and the retry finds the link again.
|
|
69
|
+
*/
|
|
70
|
+
export declare function inviteLink(sql: RegistrySql, scopeId: string, principal: string): string | null;
|
|
71
|
+
/**
|
|
72
|
+
* Is `tokenHash` an open capability-era invite here (#1686)? Asked BEFORE the secret is
|
|
73
|
+
* exchanged, so a secret that is no open invite — withdrawn, already accepted, or a `become`
|
|
74
|
+
* capability minted for something else — is refused without spending its use. The exchange is
|
|
75
|
+
* still the authority: this only decides whether to ask it.
|
|
76
|
+
*/
|
|
77
|
+
export declare function inviteMatches(sql: RegistrySql, scopeId: string, tokenHash: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Accept an invite with an exchanged `become` capability (#1686): the scope has taken the
|
|
80
|
+
* capability's one use and answered the principal it becomes. Binds the subject when an open
|
|
81
|
+
* invite here names that capability AND that principal, and consumes it — so a withdrawal
|
|
82
|
+
* landing between the exchange and this finds nothing to bind. Null otherwise, one answer.
|
|
83
|
+
*/
|
|
84
|
+
export declare function claimInviteByCapability(sql: RegistrySql, scopeId: string, sub: string, capabilityId: string, principal: string): string | null;
|
|
85
|
+
/**
|
|
86
|
+
* LEGACY (#1686) — claim an invite minted before invites became `become` capabilities, by its
|
|
87
|
+
* token's hash: bind the verified subject to the invite's pre-minted principal and consume the
|
|
88
|
+
* invite, with no await between the read and the writes — so in the Durable Object a withdrawal
|
|
89
|
+
* (`revokeInvite`) and a claim are serialized, and a claim after a withdrawal finds nothing.
|
|
90
|
+
* Returns the principal, or null when no unclaimed legacy invite matches. It writes nothing to
|
|
91
|
+
* the scope: the role was granted when the invite was minted.
|
|
92
|
+
*
|
|
93
|
+
* A capability-era row is NEVER claimed here, whatever hash is presented: its secret goes
|
|
94
|
+
* through the scope's exchange (`claimInviteByCapability`), which is what spends its one use
|
|
95
|
+
* and puts it on the spine. Unlike an owner claim link, a legacy invite never expires, so this
|
|
96
|
+
* path cannot age out on a timer: it stays until every legacy row is accepted or withdrawn, or
|
|
97
|
+
* a cut-off is decided.
|
|
44
98
|
*/
|
|
45
99
|
export declare function claimInvite(sql: RegistrySql, scopeId: string, sub: string, tokenHash: string): string | null;
|
|
46
100
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"member-directory.d.ts","sourceRoot":"","sources":["../src/member-directory.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"member-directory.d.ts","sourceRoot":"","sources":["../src/member-directory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACpE,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEtD,eAAO,MAAM,UAAU,EAAE,MAAM,EAO9B,CAAC;AAEF,qGAAqG;AACrG,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAAuC,CAAC;AAE1F;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAGrD;AAED;;;;GAIG;AACH,MAAM,MAAM,SAAS,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAErI,2EAA2E;AAC3E,MAAM,MAAM,aAAa,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAUxF;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,EAAE,SAAS,EAAE,MAAM,EAC9G,YAAY,GAAE,MAAM,GAAG,IAAW,GACjC,IAAI,CAKN;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,CAK1E;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAMhG;AAED,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAE1F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMhG;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM9F;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAK3F;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GACtF,MAAM,GAAG,IAAI,CAMf;AASD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAM5G;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,EAAE,CAarF"}
|
package/dist/member-directory.js
CHANGED
|
@@ -5,50 +5,109 @@ export const INVITE_DDL = [
|
|
|
5
5
|
`CREATE TABLE IF NOT EXISTS invite (
|
|
6
6
|
token_hash TEXT PRIMARY KEY, scope_id TEXT NOT NULL, principal TEXT NOT NULL,
|
|
7
7
|
role_key TEXT NOT NULL, email TEXT, claimed INTEGER NOT NULL DEFAULT 0,
|
|
8
|
-
created_at INTEGER NOT NULL DEFAULT (cast(unixepoch('subsecond') * 1000 as integer))
|
|
8
|
+
created_at INTEGER NOT NULL DEFAULT (cast(unixepoch('subsecond') * 1000 as integer)),
|
|
9
|
+
capability_id TEXT)`,
|
|
9
10
|
`CREATE INDEX IF NOT EXISTS invite_by_scope ON invite (scope_id)`,
|
|
10
11
|
];
|
|
11
12
|
/** The whole directory an invite touches: the identity (and owner-seat) tables, then the invites. */
|
|
12
13
|
export const MEMBER_DIRECTORY_DDL = [...OWNER_SEAT_DDL, ...INVITE_DDL];
|
|
14
|
+
/**
|
|
15
|
+
* Bring an `invite` table from before #1686 up to date: `CREATE TABLE IF NOT EXISTS` leaves an
|
|
16
|
+
* existing table alone, so a directory whose storage predates `capability_id` needs the one
|
|
17
|
+
* `ALTER`, and every row it had reads as legacy (NULL). Idempotent — run it after the DDL.
|
|
18
|
+
*/
|
|
19
|
+
export function migrateInvites(sql) {
|
|
20
|
+
const columns = [...sql.exec('PRAGMA table_info(invite)')].map((r) => r.name);
|
|
21
|
+
if (!columns.includes('capability_id'))
|
|
22
|
+
sql.exec('ALTER TABLE invite ADD COLUMN capability_id TEXT');
|
|
23
|
+
}
|
|
13
24
|
const inviteRowOf = (r) => ({
|
|
14
25
|
principal: r.principal,
|
|
15
26
|
roleKey: r.role_key,
|
|
16
27
|
email: r.email ?? null,
|
|
17
28
|
createdAt: Number(r.created_at),
|
|
29
|
+
capabilityId: r.capability_id ?? null,
|
|
18
30
|
});
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
/**
|
|
32
|
+
* Record an invite under its token's hash. `capabilityId` names the `become` capability whose
|
|
33
|
+
* secret the token is (#1686); null writes a legacy hash-only row, which this package's own
|
|
34
|
+
* invite routes no longer mint.
|
|
35
|
+
*/
|
|
36
|
+
export function createInvite(sql, scopeId, principal, roleKey, email, tokenHash, capabilityId = null) {
|
|
37
|
+
sql.exec('INSERT INTO invite (token_hash, scope_id, principal, role_key, email, capability_id) VALUES (?, ?, ?, ?, ?, ?)', tokenHash, scopeId, principal, roleKey, email, capabilityId);
|
|
21
38
|
}
|
|
22
39
|
/** The scope's outstanding (unclaimed) invites, newest first. No token. */
|
|
23
40
|
export function listInvites(sql, scopeId) {
|
|
24
|
-
return [...sql.exec('SELECT principal, role_key, email, created_at FROM invite WHERE scope_id = ? AND claimed = 0 ORDER BY created_at DESC', scopeId)].map(inviteRowOf);
|
|
41
|
+
return [...sql.exec('SELECT principal, role_key, email, created_at, capability_id FROM invite WHERE scope_id = ? AND claimed = 0 ORDER BY created_at DESC', scopeId)].map(inviteRowOf);
|
|
25
42
|
}
|
|
26
43
|
/** One outstanding invite by its pre-minted principal, or null (#1931). */
|
|
27
44
|
export function getInvite(sql, scopeId, principal) {
|
|
28
|
-
const r = [...sql.exec('SELECT principal, role_key, email, created_at FROM invite WHERE scope_id = ? AND principal = ? AND claimed = 0', scopeId, principal)][0];
|
|
45
|
+
const r = [...sql.exec('SELECT principal, role_key, email, created_at, capability_id FROM invite WHERE scope_id = ? AND principal = ? AND claimed = 0', scopeId, principal)][0];
|
|
29
46
|
return r ? inviteRowOf(r) : null;
|
|
30
47
|
}
|
|
31
48
|
export function inviteExists(sql, scopeId, tokenHash) {
|
|
32
49
|
return [...sql.exec('SELECT 1 FROM invite WHERE scope_id = ? AND token_hash = ? AND claimed = 0', scopeId, tokenHash)].length > 0;
|
|
33
50
|
}
|
|
34
|
-
/**
|
|
51
|
+
/**
|
|
52
|
+
* Withdraw an unclaimed invite by its pre-minted principal. Returns the `become` capability its
|
|
53
|
+
* link was (#1686), or null for a legacy invite, or none. Deleting the row is what stops an
|
|
54
|
+
* accept here; a withdrawal revokes the link in the scope BEFORE this (`inviteLink`).
|
|
55
|
+
*/
|
|
35
56
|
export function revokeInvite(sql, scopeId, principal) {
|
|
36
|
-
sql.exec('DELETE FROM invite WHERE scope_id = ? AND principal = ? AND claimed = 0', scopeId, principal);
|
|
57
|
+
const gone = [...sql.exec('DELETE FROM invite WHERE scope_id = ? AND principal = ? AND claimed = 0 RETURNING capability_id', scopeId, principal)][0];
|
|
58
|
+
return gone?.capability_id ?? null;
|
|
37
59
|
}
|
|
38
60
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* nothing. Returns the principal, or null when no unclaimed invite matches. It writes nothing
|
|
43
|
-
* to the scope: the role was granted when the invite was minted.
|
|
61
|
+
* The `become` capability an open invite's link is (#1686), or null — a legacy invite, or none.
|
|
62
|
+
* What a withdrawal revokes FIRST, while the row is still there to name it: a revoke that fails
|
|
63
|
+
* leaves the row, and the retry finds the link again.
|
|
44
64
|
*/
|
|
45
|
-
export function
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
65
|
+
export function inviteLink(sql, scopeId, principal) {
|
|
66
|
+
const open = [...sql.exec('SELECT capability_id FROM invite WHERE scope_id = ? AND principal = ? AND claimed = 0', scopeId, principal)][0];
|
|
67
|
+
return open?.capability_id ?? null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Is `tokenHash` an open capability-era invite here (#1686)? Asked BEFORE the secret is
|
|
71
|
+
* exchanged, so a secret that is no open invite — withdrawn, already accepted, or a `become`
|
|
72
|
+
* capability minted for something else — is refused without spending its use. The exchange is
|
|
73
|
+
* still the authority: this only decides whether to ask it.
|
|
74
|
+
*/
|
|
75
|
+
export function inviteMatches(sql, scopeId, tokenHash) {
|
|
76
|
+
return [...sql.exec('SELECT 1 FROM invite WHERE scope_id = ? AND token_hash = ? AND claimed = 0 AND capability_id IS NOT NULL', scopeId, tokenHash)].length > 0;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Accept an invite with an exchanged `become` capability (#1686): the scope has taken the
|
|
80
|
+
* capability's one use and answered the principal it becomes. Binds the subject when an open
|
|
81
|
+
* invite here names that capability AND that principal, and consumes it — so a withdrawal
|
|
82
|
+
* landing between the exchange and this finds nothing to bind. Null otherwise, one answer.
|
|
83
|
+
*/
|
|
84
|
+
export function claimInviteByCapability(sql, scopeId, sub, capabilityId, principal) {
|
|
85
|
+
const inv = [...sql.exec('SELECT token_hash FROM invite WHERE scope_id = ? AND capability_id = ? AND principal = ? AND claimed = 0', scopeId, capabilityId, principal)][0];
|
|
86
|
+
return inv ? bindInvite(sql, scopeId, sub, principal, inv.token_hash) : null;
|
|
87
|
+
}
|
|
88
|
+
/** Bind the subject to the invite's principal and consume the invite — the write both claims share. */
|
|
89
|
+
function bindInvite(sql, scopeId, sub, principal, tokenHash) {
|
|
90
|
+
sql.exec('INSERT OR REPLACE INTO identity (scope_id, sub, principal) VALUES (?, ?, ?)', scopeId, sub, principal);
|
|
50
91
|
sql.exec('UPDATE invite SET claimed = 1 WHERE scope_id = ? AND token_hash = ?', scopeId, tokenHash);
|
|
51
|
-
return
|
|
92
|
+
return principal;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* LEGACY (#1686) — claim an invite minted before invites became `become` capabilities, by its
|
|
96
|
+
* token's hash: bind the verified subject to the invite's pre-minted principal and consume the
|
|
97
|
+
* invite, with no await between the read and the writes — so in the Durable Object a withdrawal
|
|
98
|
+
* (`revokeInvite`) and a claim are serialized, and a claim after a withdrawal finds nothing.
|
|
99
|
+
* Returns the principal, or null when no unclaimed legacy invite matches. It writes nothing to
|
|
100
|
+
* the scope: the role was granted when the invite was minted.
|
|
101
|
+
*
|
|
102
|
+
* A capability-era row is NEVER claimed here, whatever hash is presented: its secret goes
|
|
103
|
+
* through the scope's exchange (`claimInviteByCapability`), which is what spends its one use
|
|
104
|
+
* and puts it on the spine. Unlike an owner claim link, a legacy invite never expires, so this
|
|
105
|
+
* path cannot age out on a timer: it stays until every legacy row is accepted or withdrawn, or
|
|
106
|
+
* a cut-off is decided.
|
|
107
|
+
*/
|
|
108
|
+
export function claimInvite(sql, scopeId, sub, tokenHash) {
|
|
109
|
+
const inv = [...sql.exec('SELECT principal FROM invite WHERE scope_id = ? AND token_hash = ? AND claimed = 0 AND capability_id IS NULL', scopeId, tokenHash)][0];
|
|
110
|
+
return inv ? bindInvite(sql, scopeId, sub, inv.principal, tokenHash) : null;
|
|
52
111
|
}
|
|
53
112
|
/**
|
|
54
113
|
* Who this directory knows at the scope, by principal (#1150): how many subjects are bound to
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"member-directory.js","sourceRoot":"","sources":["../src/member-directory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"member-directory.js","sourceRoot":"","sources":["../src/member-directory.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,7 +30,7 @@ export declare const UNATTRIBUTED_PLATFORM_ACTOR: PlatformActorId;
|
|
|
30
30
|
*/
|
|
31
31
|
export interface OwnerClaimMintHost {
|
|
32
32
|
mintCapabilityLocal(tenantId: TenantId, scopeId: ScopeId, input: BecomeCapabilityInput, actor: PlatformActorId): Promise<MintedCapability>;
|
|
33
|
-
revokeCapabilityLocal(scopeId: ScopeId, capabilityId: CapabilityId, actor: PlatformActorId): Promise<
|
|
33
|
+
revokeCapabilityLocal(scopeId: ScopeId, capabilityId: CapabilityId, actor: PlatformActorId): Promise<unknown>;
|
|
34
34
|
}
|
|
35
35
|
/** The slice of the identity directory a mint touches. */
|
|
36
36
|
export type OwnerClaimMintDirectory = Pick<IdentityStub, 'ownerClaimTarget' | 'recordOwnerClaim'>;
|
|
@@ -21,18 +21,16 @@
|
|
|
21
21
|
* only if that capability is still the recorded link and names the pending owner.
|
|
22
22
|
*
|
|
23
23
|
* Every refusal after step 1 is the same 400, so a probe learns nothing about which step said no.
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* deploy that ships this. REMOVE that branch in the release after the one that ships #1686
|
|
28
|
-
* (written 2026-10-04), with `claimOwner` in owner-seat.ts.
|
|
24
|
+
* A token that is not a capability secret at all gets it too: the hash-only links #925 minted
|
|
25
|
+
* before #1686 are no longer redeemed — every one of them expired `OWNER_CLAIM_TTL_MS` after it
|
|
26
|
+
* was minted, and the release after #1686 has long shipped.
|
|
29
27
|
*/
|
|
30
28
|
import type { Context, Hono } from 'hono';
|
|
31
29
|
import { z, type CapabilityExchange, type ScopeId, type TenantId } from '@substrat-run/contracts';
|
|
32
30
|
import type { IdentityStub } from './identity-do.js';
|
|
33
31
|
import type { AuthProvider, AuthSubject } from './provider.js';
|
|
34
32
|
/** The slice of the identity directory the redemption touches. */
|
|
35
|
-
export type OwnerClaimDirectory = Pick<IdentityStub, 'ownerClaimMatches' | 'claimOwnerByCapability'
|
|
33
|
+
export type OwnerClaimDirectory = Pick<IdentityStub, 'ownerClaimMatches' | 'claimOwnerByCapability'>;
|
|
36
34
|
/** What the redemption needs of the scope host: the exchange, asked for a `become` capability only. */
|
|
37
35
|
export interface OwnerClaimExchangeHost {
|
|
38
36
|
exchangeCapability(tenantId: TenantId, scopeId: ScopeId, secret: string, options?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"owner-claim-routes.d.ts","sourceRoot":"","sources":["../src/owner-claim-routes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"owner-claim-routes.d.ts","sourceRoot":"","sources":["../src/owner-claim-routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE1C,OAAO,EAAE,CAAC,EAAE,KAAK,kBAAkB,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAElG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG/D,kEAAkE;AAClE,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,YAAY,EAAE,mBAAmB,GAAG,wBAAwB,CAAC,CAAC;AAErG,uGAAuG;AACvG,MAAM,WAAW,sBAAsB;IACrC,kBAAkB,CAChB,QAAQ,EAAE,QAAQ,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAA;KAAE,GACpC,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC;CACvC;AAED,8CAA8C;AAC9C,eAAO,MAAM,cAAc;;iBAAyC,CAAC;AAErE,uDAAuD;AACvD,MAAM,WAAW,YAAY,CAAC,CAAC;IAC7B,IAAI,EAAE,CAAC,CAAC;IACR,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,WAAW,CAAC;CACtB;AAED,gGAAgG;AAChG,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE;IACvG,0FAA0F;IAC1F,OAAO,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;IAClD,mGAAmG;IACnG,YAAY,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;IAC9D,wFAAwF;IACxF,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,mBAAmB,CAAC;IACpD,gEAAgE;IAChE,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,sBAAsB,CAAC;IACzC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC;QAAE,QAAQ,EAAE,CAAC,CAAA;KAAE,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACtF;AAKD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS;IAAE,QAAQ,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,EAClG,GAAG,EAAE,IAAI,CAAC;IAAE,QAAQ,EAAE,CAAC,CAAA;CAAE,CAAC,EAC1B,IAAI,EAAE,mBAAmB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC9B,IAAI,CAqBN"}
|