@vantageos/cloud-identity 0.13.0 → 0.16.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/CHANGELOG.md +129 -0
- package/README.md +186 -1
- package/dist/identity-refusal.d.ts +1 -1
- package/dist/identity-refusal.d.ts.map +1 -1
- package/dist/identity-refusal.js.map +1 -1
- package/dist/index.d.ts +6 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/dist/org-by-id.d.ts +170 -0
- package/dist/org-by-id.d.ts.map +1 -0
- package/dist/org-by-id.js +232 -0
- package/dist/org-by-id.js.map +1 -0
- package/dist/principal-by-id.d.ts +138 -0
- package/dist/principal-by-id.d.ts.map +1 -1
- package/dist/principal-by-id.js +173 -0
- package/dist/principal-by-id.js.map +1 -1
- package/dist/resource-server.d.ts +108 -0
- package/dist/resource-server.d.ts.map +1 -0
- package/dist/resource-server.js +171 -0
- package/dist/resource-server.js.map +1 -0
- package/dist/scope-filter.d.ts +12 -9
- package/dist/scope-filter.d.ts.map +1 -1
- package/dist/scope-filter.js +12 -9
- package/dist/scope-filter.js.map +1 -1
- package/dist/types.d.ts +7 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +9 -1
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vantageos/cloud-identity — an organisation is its permanent ID.
|
|
3
|
+
*
|
|
4
|
+
* Everything here decides "which organisation" from the permanent org ID a
|
|
5
|
+
* verified credential or a stored row carries. A label (the slug an org can be
|
|
6
|
+
* renamed to) is display text: it never selects an org and never proves two
|
|
7
|
+
* references are one org.
|
|
8
|
+
*
|
|
9
|
+
* Refusal, always. There is no option that compares or resolves by label: a
|
|
10
|
+
* reference or credential without an org ID names no organisation, and a
|
|
11
|
+
* mapping is reached only by an ID.
|
|
12
|
+
*
|
|
13
|
+
* The store is the consumer's: every read is an adapter it supplies, called
|
|
14
|
+
* with the key as presented, byte for byte. A missing, throwing or malformed
|
|
15
|
+
* adapter refuses. An adapter's error text is never surfaced.
|
|
16
|
+
*/
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
import { refusal } from "./identity-refusal.js";
|
|
19
|
+
import { resolveTenantIdOrAbsent } from "./org-guard.js";
|
|
20
|
+
function nonEmpty(value) {
|
|
21
|
+
return typeof value === "string" && value.length > 0;
|
|
22
|
+
}
|
|
23
|
+
function isUnstamped(ref) {
|
|
24
|
+
return (ref === null ||
|
|
25
|
+
ref === undefined ||
|
|
26
|
+
((ref.id === null || ref.id === undefined) &&
|
|
27
|
+
(ref.label === null || ref.label === undefined)));
|
|
28
|
+
}
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
// sameOrg / isFleetStamp / sameTenantStamp
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
/**
|
|
33
|
+
* Do two references name the same organisation? Only by ID, when both carry
|
|
34
|
+
* one. A label never matches, and absence is not a match: two unstamped
|
|
35
|
+
* references are NOT the same organisation here.
|
|
36
|
+
*/
|
|
37
|
+
export function sameOrg(a, b) {
|
|
38
|
+
if (!a || !b)
|
|
39
|
+
return false;
|
|
40
|
+
return nonEmpty(a.id) && nonEmpty(b.id) && a.id === b.id;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Is a stamp the fleet's: unstamped, or the operator organisation's? The
|
|
44
|
+
* operator is read from stored data by the caller (see `findOperatorOrg`);
|
|
45
|
+
* pass `undefined` when there is not exactly one, and only an unstamped stamp
|
|
46
|
+
* is the fleet's. An empty-string stamp is neither unstamped nor the operator.
|
|
47
|
+
*/
|
|
48
|
+
export function isFleetStamp(stamp, operator) {
|
|
49
|
+
if (isUnstamped(stamp))
|
|
50
|
+
return true;
|
|
51
|
+
return operator !== null && operator !== undefined && sameOrg(stamp, operator);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Do two stamps name the same tenant: the same organisation, or both the
|
|
55
|
+
* fleet's? Two IDs that differ are two tenants even under one label.
|
|
56
|
+
*/
|
|
57
|
+
export function sameTenantStamp(a, b, operator) {
|
|
58
|
+
if (isFleetStamp(a, operator) && isFleetStamp(b, operator))
|
|
59
|
+
return true;
|
|
60
|
+
return sameOrg(a, b);
|
|
61
|
+
}
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// The stored mapping row
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
/**
|
|
66
|
+
* The consumer's organisation mapping row, as an adapter returns it. `id` is
|
|
67
|
+
* the permanent org ID and may be absent while the store is being filled;
|
|
68
|
+
* `label` is the slug. Extra fields are allowed and ignored.
|
|
69
|
+
*/
|
|
70
|
+
export const orgMappingRowSchema = z.object({
|
|
71
|
+
id: z.string().min(1).nullish(),
|
|
72
|
+
label: z.string().min(1),
|
|
73
|
+
active: z.boolean(),
|
|
74
|
+
allowedOrchestrators: z.array(z.string()),
|
|
75
|
+
scopes: z.array(z.string()),
|
|
76
|
+
orgKind: z.string().nullish(),
|
|
77
|
+
});
|
|
78
|
+
function kindOf(raw) {
|
|
79
|
+
return raw === "operator" || raw === "client" ? raw : null;
|
|
80
|
+
}
|
|
81
|
+
/** Calls an adapter; a missing or throwing one is `called: false`. */
|
|
82
|
+
async function call(lookup, ...args) {
|
|
83
|
+
if (typeof lookup !== "function")
|
|
84
|
+
return { called: false };
|
|
85
|
+
try {
|
|
86
|
+
const raw = await lookup(...args);
|
|
87
|
+
return { called: true, row: raw ?? null };
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return { called: false };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const CLERK_ORG_ID_SHAPE = /^org_[A-Za-z0-9]+$/;
|
|
94
|
+
const ID_CLAIMS = ["org_id", "organizationId", "orgId"];
|
|
95
|
+
/** The first claim that is shaped like a Clerk org ID and resolves as a tenant. */
|
|
96
|
+
function claimedOrgId(claims) {
|
|
97
|
+
for (const name of ID_CLAIMS) {
|
|
98
|
+
const value = claims[name];
|
|
99
|
+
if (typeof value !== "string" || !CLERK_ORG_ID_SHAPE.test(value))
|
|
100
|
+
continue;
|
|
101
|
+
const resolved = resolveTenantIdOrAbsent({ kind: "session", identity: { orgId: value } });
|
|
102
|
+
if (resolved.present)
|
|
103
|
+
return resolved.tenantId;
|
|
104
|
+
}
|
|
105
|
+
return undefined;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Resolves a VERIFIED credential's claims to the stored mapping row of its
|
|
109
|
+
* organisation, or refuses. The claim's org ID selects the row; nothing the
|
|
110
|
+
* request supplies does.
|
|
111
|
+
*
|
|
112
|
+
* A credential carrying no usable org ID is refused
|
|
113
|
+
* (`no-verified-organisation`) and an ID no mapping holds is refused
|
|
114
|
+
* (`org-mapping-not-found`). A label claim (a slug) is never read: it neither
|
|
115
|
+
* selects a mapping nor rescues a missing ID.
|
|
116
|
+
*
|
|
117
|
+
* `claims` is the verified identity's own claim record, never a request field.
|
|
118
|
+
*/
|
|
119
|
+
export async function resolveOrgFromClaim(claims, lookups, options) {
|
|
120
|
+
const door = options?.door ?? "resolveOrgFromClaim";
|
|
121
|
+
const deny = (reason, detail) => ({
|
|
122
|
+
ok: false,
|
|
123
|
+
refusal: refusal("RBAC_DENIED", reason, door, detail),
|
|
124
|
+
});
|
|
125
|
+
const record = claims && typeof claims === "object" ? claims : {};
|
|
126
|
+
const orgId = claimedOrgId(record);
|
|
127
|
+
if (orgId === undefined) {
|
|
128
|
+
return deny("no-verified-organisation", "The credential carries no verified organisation.");
|
|
129
|
+
}
|
|
130
|
+
const served = (row, id) => {
|
|
131
|
+
if (row.active !== true) {
|
|
132
|
+
return deny("organisation-not-active", "The organisation is not mapped or not active.");
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
ok: true,
|
|
136
|
+
org: {
|
|
137
|
+
id,
|
|
138
|
+
label: row.label,
|
|
139
|
+
allowedOrchestrators: row.allowedOrchestrators,
|
|
140
|
+
scopes: row.scopes,
|
|
141
|
+
orgKind: kindOf(row.orgKind),
|
|
142
|
+
},
|
|
143
|
+
};
|
|
144
|
+
};
|
|
145
|
+
const invalid = deny("org-mapping-record-invalid", "The organisation mapping record is not well formed.");
|
|
146
|
+
const unreadable = deny("org-mapping-lookup-failed", "The organisation mapping could not be read, so none is resolved.");
|
|
147
|
+
const found = await call(lookups?.orgById, orgId);
|
|
148
|
+
if (!found.called)
|
|
149
|
+
return unreadable;
|
|
150
|
+
if (found.row === null) {
|
|
151
|
+
return deny("org-mapping-not-found", "No organisation mapping holds the credential's organisation ID.");
|
|
152
|
+
}
|
|
153
|
+
const parsed = orgMappingRowSchema.safeParse(found.row);
|
|
154
|
+
if (!parsed.success || parsed.data.id !== orgId)
|
|
155
|
+
return invalid;
|
|
156
|
+
return served(parsed.data, orgId);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* BACKFILL ONLY. Derives the permanent org ID of the organisation a label
|
|
160
|
+
* names, from the consumer's stored mapping, so a one-off migration can stamp
|
|
161
|
+
* rows written before IDs existed.
|
|
162
|
+
*
|
|
163
|
+
* MUST NEVER be called on a request path. A request decides its organisation
|
|
164
|
+
* from the verified credential's `org_id` claim (`resolveOrgFromClaim`); a miss
|
|
165
|
+
* there is a refusal, never a retry by label. A label is renamable display
|
|
166
|
+
* text: resolving an org from it on a request is the name-to-ID defect this
|
|
167
|
+
* module exists to close, and the export name carries that restriction so a
|
|
168
|
+
* reviewer sees it at every call site.
|
|
169
|
+
*
|
|
170
|
+
* A derivation and not an authorization: it answers for an inactive mapping
|
|
171
|
+
* too. It never invents an ID: a mapping with none filled is `id-not-filled`.
|
|
172
|
+
*/
|
|
173
|
+
export async function resolveOrgIdForLabelBackfillOnly(label, lookups) {
|
|
174
|
+
const absent = (reason) => ({
|
|
175
|
+
present: false,
|
|
176
|
+
absence: { code: "ORG_ID_ABSENT", reason },
|
|
177
|
+
});
|
|
178
|
+
if (!nonEmpty(label))
|
|
179
|
+
return absent("no-label");
|
|
180
|
+
const found = await call(lookups?.orgByLabel, label);
|
|
181
|
+
if (!found.called)
|
|
182
|
+
return absent("lookup-failed");
|
|
183
|
+
if (found.row === null)
|
|
184
|
+
return absent("not-mapped");
|
|
185
|
+
const parsed = orgMappingRowSchema.safeParse(found.row);
|
|
186
|
+
if (!parsed.success || parsed.data.label !== label)
|
|
187
|
+
return absent("record-invalid");
|
|
188
|
+
if (parsed.data.id === undefined || parsed.data.id === null)
|
|
189
|
+
return absent("id-not-filled");
|
|
190
|
+
return { present: true, orgId: parsed.data.id };
|
|
191
|
+
}
|
|
192
|
+
const DEFAULT_OPERATOR_READ_CAP = 1000;
|
|
193
|
+
/**
|
|
194
|
+
* Finds the operator organisation (the fleet) from stored mapping rows: the
|
|
195
|
+
* single ACTIVE row whose kind is exactly `"operator"`. None, several, an
|
|
196
|
+
* over-cap read, an unreadable store and a malformed row are each a typed
|
|
197
|
+
* non-answer, so the caller can only treat the fleet as "no single operator"
|
|
198
|
+
* (fail closed) and never widen from a guess.
|
|
199
|
+
*/
|
|
200
|
+
export async function findOperatorOrg(lookups, options) {
|
|
201
|
+
const cap = options?.cap ?? DEFAULT_OPERATOR_READ_CAP;
|
|
202
|
+
const read = lookups?.activeOrganisations;
|
|
203
|
+
if (typeof read !== "function")
|
|
204
|
+
return { kind: "unreadable" };
|
|
205
|
+
let raw;
|
|
206
|
+
try {
|
|
207
|
+
raw = await read(cap + 1);
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
return { kind: "unreadable" };
|
|
211
|
+
}
|
|
212
|
+
if (!Array.isArray(raw))
|
|
213
|
+
return { kind: "unreadable" };
|
|
214
|
+
if (raw.length > cap)
|
|
215
|
+
return { kind: "overCap" };
|
|
216
|
+
const operators = [];
|
|
217
|
+
for (const item of raw) {
|
|
218
|
+
const parsed = orgMappingRowSchema.safeParse(item);
|
|
219
|
+
if (!parsed.success)
|
|
220
|
+
return { kind: "unreadable" };
|
|
221
|
+
if (parsed.data.active === true && parsed.data.orgKind === "operator") {
|
|
222
|
+
operators.push(parsed.data);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (operators.length === 0)
|
|
226
|
+
return { kind: "none" };
|
|
227
|
+
if (operators.length > 1)
|
|
228
|
+
return { kind: "many", count: operators.length };
|
|
229
|
+
const [only] = operators;
|
|
230
|
+
return { kind: "one", org: { id: only.id ?? undefined, label: only.label } };
|
|
231
|
+
}
|
|
232
|
+
//# sourceMappingURL=org-by-id.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"org-by-id.js","sourceRoot":"","sources":["../src/org-by-id.ts"],"names":[],"mappings":"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"}
|
|
@@ -211,6 +211,40 @@ export declare function resolveActingPrincipal(credential: ActingCredential | nu
|
|
|
211
211
|
* absent owner is refused.
|
|
212
212
|
*/
|
|
213
213
|
export declare function assertTargetBelongsTo(principal: ActingPrincipal | null | undefined, target: TargetIds | null | undefined, lookups: OrgKindLookups, opts?: AssertTargetOptions): Promise<AssertTargetResult>;
|
|
214
|
+
export type FilterTargetsResult<T> = {
|
|
215
|
+
ok: true;
|
|
216
|
+
rows: T[];
|
|
217
|
+
} | {
|
|
218
|
+
ok: false;
|
|
219
|
+
refusal: IdentityRefusal;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Keeps the rows that belong to the principal, deciding by STORED ID only.
|
|
223
|
+
* The ID-keyed replacement for the name-keyed `scopeFilterList`.
|
|
224
|
+
*
|
|
225
|
+
* Each row is judged by `assertTargetBelongsTo` (never re-derived here), so
|
|
226
|
+
* the same organisation, operator-org, unstamped, `ownerOnly` and
|
|
227
|
+
* `fleetCrossOrg` rules apply.
|
|
228
|
+
*
|
|
229
|
+
* - The principal is proved FIRST, before any row is read. An absent or
|
|
230
|
+
* unresolved principal, or a failed organisation-kind lookup for it,
|
|
231
|
+
* returns `{ ok: false, refusal }` naming the door, even for an empty
|
|
232
|
+
* list: a refusal is never an `ok: true` with no rows.
|
|
233
|
+
* - `fleetCrossOrg: true` from a principal that is not `kind: "fleet"` is a
|
|
234
|
+
* misconfigured door and is refused `reserved-fleet-scope` up front, for
|
|
235
|
+
* any list. Per row, `reserved-fleet-scope` therefore only means "this row
|
|
236
|
+
* is in the operator scope" and the row is dropped.
|
|
237
|
+
* - A resolved principal whose rows all belong elsewhere gets
|
|
238
|
+
* `{ ok: true, rows: [] }`: an absence, distinguishable from a refusal.
|
|
239
|
+
* - A row that does not belong (other organisation, operator-org row,
|
|
240
|
+
* unstamped, owner mismatch) is dropped. A same-NAME row of another
|
|
241
|
+
* organisation is dropped: no name field is read.
|
|
242
|
+
* - A lookup failure on any row refuses the whole call. It is never a
|
|
243
|
+
* silent drop and never a pass; any refusal reason not known to mean
|
|
244
|
+
* "this row is not yours" refuses too.
|
|
245
|
+
* - The order of the kept rows is the order of the input.
|
|
246
|
+
*/
|
|
247
|
+
export declare function filterTargetsBelongingTo<T extends TargetIds>(principal: ActingPrincipal | null | undefined, rows: readonly T[], lookups: OrgKindLookups, opts?: AssertTargetOptions): Promise<FilterTargetsResult<T>>;
|
|
214
248
|
export type AssertOrgAdminOptions = {
|
|
215
249
|
/**
|
|
216
250
|
* The role values that count as organisation admin, exactly as the verified
|
|
@@ -290,5 +324,109 @@ export type AssertPrincipalListedResult = {
|
|
|
290
324
|
* The fleet sentinel is out of scope here.
|
|
291
325
|
*/
|
|
292
326
|
export declare function assertPrincipalListed(principal: ActingPrincipal | null | undefined, list: PrincipalIdList | null | undefined, opts?: AssertPrincipalListedOptions): AssertPrincipalListedResult;
|
|
327
|
+
/** The recipient of a message, named by its stored agent ID and organisation ID. */
|
|
328
|
+
export type RecipientIds = {
|
|
329
|
+
/** The recipient agent's stored ID. */
|
|
330
|
+
agentId: string;
|
|
331
|
+
/** The recipient agent's stored organisation ID. */
|
|
332
|
+
orgId: string;
|
|
333
|
+
};
|
|
334
|
+
/**
|
|
335
|
+
* The lookups `assertRecipientAddressable` reads: the organisation kind, and
|
|
336
|
+
* the stored roster of agent IDs of one organisation (a client's list of the
|
|
337
|
+
* fleet agents it may reach). `null`, a miss or a throw is an unresolvable
|
|
338
|
+
* roster and refuses.
|
|
339
|
+
*/
|
|
340
|
+
export type RecipientLookups = OrgKindLookups & {
|
|
341
|
+
rosterOf?: Lookup<[orgId: string], PrincipalIdList>;
|
|
342
|
+
};
|
|
343
|
+
export type AssertRecipientAddressableOptions = {
|
|
344
|
+
/** The consumer's name for the door; carried on every refusal. */
|
|
345
|
+
door?: string;
|
|
346
|
+
};
|
|
347
|
+
export type AssertRecipientAddressableResult = {
|
|
348
|
+
ok: true;
|
|
349
|
+
} | {
|
|
350
|
+
ok: false;
|
|
351
|
+
refusal: IdentityRefusal;
|
|
352
|
+
};
|
|
353
|
+
/**
|
|
354
|
+
* Decides whether a sender may address a recipient, across organisations
|
|
355
|
+
* included, by AGENT ID only. The sender must come from
|
|
356
|
+
* `resolveActingPrincipal`. No name is read anywhere; a name never matches.
|
|
357
|
+
*
|
|
358
|
+
* Admitted iff one of these holds:
|
|
359
|
+
* (a) same organisation: the sender's `orgId` equals the recipient's;
|
|
360
|
+
* (b) client to operator: the sender is in a client organisation, the
|
|
361
|
+
* recipient is in the operator organisation, and the RECIPIENT's ID is
|
|
362
|
+
* on the SENDER organisation's roster;
|
|
363
|
+
* (c) operator to client: the sender is in the operator organisation, the
|
|
364
|
+
* recipient is in a client organisation, and the SENDER's ID is on the
|
|
365
|
+
* RECIPIENT organisation's roster.
|
|
366
|
+
*
|
|
367
|
+
* Everything else is refused with a typed `RBAC_DENIED` carrying the door
|
|
368
|
+
* (default `"assertRecipientAddressable"`): an absent sender or one without an
|
|
369
|
+
* ID (`credential-invalid`), a sender that is not `kind: "agent"`
|
|
370
|
+
* (`principal-not-an-agent`), an absent recipient or one without an agent ID
|
|
371
|
+
* or organisation (`target-unstamped`), client to client across organisations
|
|
372
|
+
* and an organisation kind that is neither operator nor client
|
|
373
|
+
* (`target-other-organisation`), a missing or throwing `orgKindOf` /
|
|
374
|
+
* `rosterOf` (`principal-lookup-failed`), an absent roster (`list-absent`), and
|
|
375
|
+
* a roster that is empty, stored under the wrong organisation or does not list
|
|
376
|
+
* the ID (the refusals of {@link assertPrincipalListed}, which is reused for
|
|
377
|
+
* that check).
|
|
378
|
+
*/
|
|
379
|
+
export declare function assertRecipientAddressable(sender: ActingPrincipal | null | undefined, recipient: RecipientIds | null | undefined, lookups: RecipientLookups, opts?: AssertRecipientAddressableOptions): Promise<AssertRecipientAddressableResult>;
|
|
380
|
+
/**
|
|
381
|
+
* A verified session that carries a person but NO organisation (a signed-in
|
|
382
|
+
* user who has not joined one). `resolveActingPrincipal` cannot express this:
|
|
383
|
+
* a person credential requires `verifiedOrgId`, so a no-organisation session
|
|
384
|
+
* is refused there exactly as a garbled credential is. This kind exists so
|
|
385
|
+
* the consumer can say "verified, and no organisation" on purpose; an absent
|
|
386
|
+
* `verifiedOrgId` on a `person` credential stays a garbled credential.
|
|
387
|
+
*/
|
|
388
|
+
declare const preOrgCredentialSchema: z.ZodObject<{
|
|
389
|
+
kind: z.ZodLiteral<"person-no-org">;
|
|
390
|
+
personId: z.ZodString;
|
|
391
|
+
}, z.core.$strict>;
|
|
392
|
+
export type CallerCredential = ActingCredential | z.input<typeof preOrgCredentialSchema>;
|
|
393
|
+
export type AssertCallerStandingOptions = {
|
|
394
|
+
/** Role values that make a person an organisation admin; see `assertOrgAdmin`. */
|
|
395
|
+
adminRoles: readonly string[];
|
|
396
|
+
/** The consumer's name for the door; carried on every refusal. */
|
|
397
|
+
door?: string;
|
|
398
|
+
};
|
|
399
|
+
/**
|
|
400
|
+
* The four callers, said apart. `anonymous` means no caller could be
|
|
401
|
+
* resolved (no credential, a garbled one, a miss, an inactive row) and carries
|
|
402
|
+
* the typed refusal; it is never what a signed-in session without an
|
|
403
|
+
* organisation becomes.
|
|
404
|
+
*/
|
|
405
|
+
export type CallerStanding = {
|
|
406
|
+
standing: "anonymous";
|
|
407
|
+
refusal: IdentityRefusal;
|
|
408
|
+
} | {
|
|
409
|
+
standing: "pre-org";
|
|
410
|
+
personId: string;
|
|
411
|
+
} | {
|
|
412
|
+
standing: "member";
|
|
413
|
+
principal: ActingPrincipal;
|
|
414
|
+
} | {
|
|
415
|
+
standing: "admin";
|
|
416
|
+
principal: ActingPrincipal;
|
|
417
|
+
} | {
|
|
418
|
+
standing: "fleet";
|
|
419
|
+
principal: ActingPrincipal;
|
|
420
|
+
};
|
|
421
|
+
/**
|
|
422
|
+
* Derives a caller's STANDING from a verified credential. It adds one case to
|
|
423
|
+
* the existing primitives, the signed-in session with no organisation, and
|
|
424
|
+
* reuses them for everything else: `resolveActingPrincipal` decides who the
|
|
425
|
+
* caller is (and `fleet`), `assertOrgAdmin` decides `admin` against the
|
|
426
|
+
* principal's own organisation. Any other resolved principal (a person
|
|
427
|
+
* without the admin role, an agent, a non-operator service account) is a
|
|
428
|
+
* `member`; read `principal.kind` to tell them apart.
|
|
429
|
+
*/
|
|
430
|
+
export declare function resolveCallerStanding(credential: CallerCredential | null | undefined, lookups: PrincipalLookups, opts: AssertCallerStandingOptions): Promise<CallerStanding>;
|
|
293
431
|
export {};
|
|
294
432
|
//# sourceMappingURL=principal-by-id.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"principal-by-id.d.ts","sourceRoot":"","sources":["../src/principal-by-id.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"principal-by-id.d.ts","sourceRoot":"","sources":["../src/principal-by-id.ts"],"names":[],"mappings":"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"}
|
package/dist/principal-by-id.js
CHANGED
|
@@ -343,6 +343,64 @@ export async function assertTargetBelongsTo(principal, target, lookups, opts = {
|
|
|
343
343
|
}
|
|
344
344
|
return { ok: true };
|
|
345
345
|
}
|
|
346
|
+
/** Refusal reasons that say only "this ROW is not the principal's". */
|
|
347
|
+
const ROW_NOT_OURS = new Set([
|
|
348
|
+
"target-unstamped",
|
|
349
|
+
"target-other-organisation",
|
|
350
|
+
"target-owner-mismatch",
|
|
351
|
+
"reserved-fleet-scope",
|
|
352
|
+
]);
|
|
353
|
+
/**
|
|
354
|
+
* Keeps the rows that belong to the principal, deciding by STORED ID only.
|
|
355
|
+
* The ID-keyed replacement for the name-keyed `scopeFilterList`.
|
|
356
|
+
*
|
|
357
|
+
* Each row is judged by `assertTargetBelongsTo` (never re-derived here), so
|
|
358
|
+
* the same organisation, operator-org, unstamped, `ownerOnly` and
|
|
359
|
+
* `fleetCrossOrg` rules apply.
|
|
360
|
+
*
|
|
361
|
+
* - The principal is proved FIRST, before any row is read. An absent or
|
|
362
|
+
* unresolved principal, or a failed organisation-kind lookup for it,
|
|
363
|
+
* returns `{ ok: false, refusal }` naming the door, even for an empty
|
|
364
|
+
* list: a refusal is never an `ok: true` with no rows.
|
|
365
|
+
* - `fleetCrossOrg: true` from a principal that is not `kind: "fleet"` is a
|
|
366
|
+
* misconfigured door and is refused `reserved-fleet-scope` up front, for
|
|
367
|
+
* any list. Per row, `reserved-fleet-scope` therefore only means "this row
|
|
368
|
+
* is in the operator scope" and the row is dropped.
|
|
369
|
+
* - A resolved principal whose rows all belong elsewhere gets
|
|
370
|
+
* `{ ok: true, rows: [] }`: an absence, distinguishable from a refusal.
|
|
371
|
+
* - A row that does not belong (other organisation, operator-org row,
|
|
372
|
+
* unstamped, owner mismatch) is dropped. A same-NAME row of another
|
|
373
|
+
* organisation is dropped: no name field is read.
|
|
374
|
+
* - A lookup failure on any row refuses the whole call. It is never a
|
|
375
|
+
* silent drop and never a pass; any refusal reason not known to mean
|
|
376
|
+
* "this row is not yours" refuses too.
|
|
377
|
+
* - The order of the kept rows is the order of the input.
|
|
378
|
+
*/
|
|
379
|
+
export async function filterTargetsBelongingTo(principal, rows, lookups, opts = {}) {
|
|
380
|
+
const door = opts.door ?? "filterTargetsBelongingTo";
|
|
381
|
+
const doorOpts = { ...opts, door };
|
|
382
|
+
// A door asking for cross-organisation reach that the principal does not
|
|
383
|
+
// hold is a misconfigured door: refused, never an absence of rows.
|
|
384
|
+
if (opts.fleetCrossOrg === true && principal != null && principal.kind !== "fleet") {
|
|
385
|
+
return denied("reserved-fleet-scope", door, "Cross-organisation reach is held only by the operator organisation's service account.");
|
|
386
|
+
}
|
|
387
|
+
// Prove the principal on a target that is its own organisation's, owner
|
|
388
|
+
// check off: only a principal-level fault can refuse this.
|
|
389
|
+
const proof = await assertTargetBelongsTo(principal, { orgId: principal?.orgId }, lookups, { ...doorOpts, ownerOnly: false, fleetCrossOrg: false });
|
|
390
|
+
if (!proof.ok)
|
|
391
|
+
return proof;
|
|
392
|
+
const kept = [];
|
|
393
|
+
for (const row of rows) {
|
|
394
|
+
const verdict = await assertTargetBelongsTo(principal, row, lookups, doorOpts);
|
|
395
|
+
if (verdict.ok) {
|
|
396
|
+
kept.push(row);
|
|
397
|
+
}
|
|
398
|
+
else if (!ROW_NOT_OURS.has(verdict.refusal.reason)) {
|
|
399
|
+
return verdict;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
return { ok: true, rows: kept };
|
|
403
|
+
}
|
|
346
404
|
/**
|
|
347
405
|
* Admits a principal as ADMIN of the target organisation, deciding by ID only.
|
|
348
406
|
* The principal must come from `resolveActingPrincipal`; the role is the
|
|
@@ -438,4 +496,119 @@ export function assertPrincipalListed(principal, list, opts) {
|
|
|
438
496
|
}
|
|
439
497
|
return { ok: true };
|
|
440
498
|
}
|
|
499
|
+
/**
|
|
500
|
+
* Decides whether a sender may address a recipient, across organisations
|
|
501
|
+
* included, by AGENT ID only. The sender must come from
|
|
502
|
+
* `resolveActingPrincipal`. No name is read anywhere; a name never matches.
|
|
503
|
+
*
|
|
504
|
+
* Admitted iff one of these holds:
|
|
505
|
+
* (a) same organisation: the sender's `orgId` equals the recipient's;
|
|
506
|
+
* (b) client to operator: the sender is in a client organisation, the
|
|
507
|
+
* recipient is in the operator organisation, and the RECIPIENT's ID is
|
|
508
|
+
* on the SENDER organisation's roster;
|
|
509
|
+
* (c) operator to client: the sender is in the operator organisation, the
|
|
510
|
+
* recipient is in a client organisation, and the SENDER's ID is on the
|
|
511
|
+
* RECIPIENT organisation's roster.
|
|
512
|
+
*
|
|
513
|
+
* Everything else is refused with a typed `RBAC_DENIED` carrying the door
|
|
514
|
+
* (default `"assertRecipientAddressable"`): an absent sender or one without an
|
|
515
|
+
* ID (`credential-invalid`), a sender that is not `kind: "agent"`
|
|
516
|
+
* (`principal-not-an-agent`), an absent recipient or one without an agent ID
|
|
517
|
+
* or organisation (`target-unstamped`), client to client across organisations
|
|
518
|
+
* and an organisation kind that is neither operator nor client
|
|
519
|
+
* (`target-other-organisation`), a missing or throwing `orgKindOf` /
|
|
520
|
+
* `rosterOf` (`principal-lookup-failed`), an absent roster (`list-absent`), and
|
|
521
|
+
* a roster that is empty, stored under the wrong organisation or does not list
|
|
522
|
+
* the ID (the refusals of {@link assertPrincipalListed}, which is reused for
|
|
523
|
+
* that check).
|
|
524
|
+
*/
|
|
525
|
+
export async function assertRecipientAddressable(sender, recipient, lookups, opts) {
|
|
526
|
+
const door = opts?.door ?? "assertRecipientAddressable";
|
|
527
|
+
if (sender === null ||
|
|
528
|
+
typeof sender !== "object" ||
|
|
529
|
+
!nonEmpty(sender.principalId) ||
|
|
530
|
+
!nonEmpty(sender.orgId)) {
|
|
531
|
+
return denied("credential-invalid", door, "No resolved sender stands behind this call.");
|
|
532
|
+
}
|
|
533
|
+
if (sender.kind !== "agent") {
|
|
534
|
+
return denied("principal-not-an-agent", door, "Only an agent addresses a recipient; the sender is not an agent.");
|
|
535
|
+
}
|
|
536
|
+
if (recipient === null ||
|
|
537
|
+
typeof recipient !== "object" ||
|
|
538
|
+
!nonEmpty(recipient.agentId) ||
|
|
539
|
+
!nonEmpty(recipient.orgId)) {
|
|
540
|
+
return denied("target-unstamped", door, "The recipient carries no agent ID and organisation.");
|
|
541
|
+
}
|
|
542
|
+
if (recipient.orgId === sender.orgId)
|
|
543
|
+
return { ok: true };
|
|
544
|
+
const senderKind = await loadOrgKind(lookups, sender.orgId, door);
|
|
545
|
+
if (!senderKind.ok)
|
|
546
|
+
return senderKind;
|
|
547
|
+
const recipientKind = await loadOrgKind(lookups, recipient.orgId, door);
|
|
548
|
+
if (!recipientKind.ok)
|
|
549
|
+
return recipientKind;
|
|
550
|
+
let clientOrgId;
|
|
551
|
+
let listed;
|
|
552
|
+
if (senderKind.kind === "client" && recipientKind.kind === "operator") {
|
|
553
|
+
clientOrgId = sender.orgId;
|
|
554
|
+
listed = { principalId: recipient.agentId };
|
|
555
|
+
}
|
|
556
|
+
else if (senderKind.kind === "operator" && recipientKind.kind === "client") {
|
|
557
|
+
clientOrgId = recipient.orgId;
|
|
558
|
+
listed = { principalId: sender.principalId };
|
|
559
|
+
}
|
|
560
|
+
else {
|
|
561
|
+
return denied("target-other-organisation", door, "The recipient belongs to another organisation that this sender may not reach.");
|
|
562
|
+
}
|
|
563
|
+
const rosterOf = lookups?.rosterOf;
|
|
564
|
+
if (typeof rosterOf !== "function") {
|
|
565
|
+
return denied("principal-lookup-failed", door, "No lookup was supplied for the roster.");
|
|
566
|
+
}
|
|
567
|
+
let roster;
|
|
568
|
+
try {
|
|
569
|
+
roster = await rosterOf(clientOrgId);
|
|
570
|
+
}
|
|
571
|
+
catch {
|
|
572
|
+
return denied("principal-lookup-failed", door, "The roster could not be read, so none is resolved.");
|
|
573
|
+
}
|
|
574
|
+
return assertPrincipalListed({ ...listed, orgId: clientOrgId, kind: "agent" }, roster, { door });
|
|
575
|
+
}
|
|
576
|
+
// ---------------------------------------------------------------------------
|
|
577
|
+
// resolveCallerStanding (0.14.0)
|
|
578
|
+
// ---------------------------------------------------------------------------
|
|
579
|
+
/**
|
|
580
|
+
* A verified session that carries a person but NO organisation (a signed-in
|
|
581
|
+
* user who has not joined one). `resolveActingPrincipal` cannot express this:
|
|
582
|
+
* a person credential requires `verifiedOrgId`, so a no-organisation session
|
|
583
|
+
* is refused there exactly as a garbled credential is. This kind exists so
|
|
584
|
+
* the consumer can say "verified, and no organisation" on purpose; an absent
|
|
585
|
+
* `verifiedOrgId` on a `person` credential stays a garbled credential.
|
|
586
|
+
*/
|
|
587
|
+
const preOrgCredentialSchema = z.strictObject({
|
|
588
|
+
kind: z.literal("person-no-org"),
|
|
589
|
+
personId: z.string().min(1),
|
|
590
|
+
});
|
|
591
|
+
/**
|
|
592
|
+
* Derives a caller's STANDING from a verified credential. It adds one case to
|
|
593
|
+
* the existing primitives, the signed-in session with no organisation, and
|
|
594
|
+
* reuses them for everything else: `resolveActingPrincipal` decides who the
|
|
595
|
+
* caller is (and `fleet`), `assertOrgAdmin` decides `admin` against the
|
|
596
|
+
* principal's own organisation. Any other resolved principal (a person
|
|
597
|
+
* without the admin role, an agent, a non-operator service account) is a
|
|
598
|
+
* `member`; read `principal.kind` to tell them apart.
|
|
599
|
+
*/
|
|
600
|
+
export async function resolveCallerStanding(credential, lookups, opts) {
|
|
601
|
+
const door = opts?.door ?? "resolveCallerStanding";
|
|
602
|
+
const preOrg = preOrgCredentialSchema.safeParse(credential);
|
|
603
|
+
if (preOrg.success)
|
|
604
|
+
return { standing: "pre-org", personId: preOrg.data.personId };
|
|
605
|
+
const resolved = await resolveActingPrincipal(credential, lookups, door);
|
|
606
|
+
if (!resolved.ok)
|
|
607
|
+
return { standing: "anonymous", refusal: resolved.refusal };
|
|
608
|
+
const { principal } = resolved;
|
|
609
|
+
if (principal.kind === "fleet")
|
|
610
|
+
return { standing: "fleet", principal };
|
|
611
|
+
const admin = assertOrgAdmin(principal, principal.orgId, { adminRoles: opts?.adminRoles, door });
|
|
612
|
+
return { standing: admin.ok ? "admin" : "member", principal };
|
|
613
|
+
}
|
|
441
614
|
//# sourceMappingURL=principal-by-id.js.map
|