@fuzdev/fuz_app 0.58.0 → 0.60.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/dist/actions/CLAUDE.md +13 -8
- package/dist/actions/action_codegen.d.ts +1 -1
- package/dist/actions/action_codegen.js +2 -2
- package/dist/actions/action_event_helpers.d.ts +3 -3
- package/dist/actions/action_event_helpers.js +8 -8
- package/dist/actions/action_event_types.d.ts +3 -3
- package/dist/actions/action_event_types.js +3 -3
- package/dist/actions/transports_ws_auth_guard.d.ts +2 -2
- package/dist/actions/transports_ws_auth_guard.js +3 -3
- package/dist/auth/CLAUDE.md +215 -45
- package/dist/auth/account_action_specs.d.ts +9 -0
- package/dist/auth/account_action_specs.d.ts.map +1 -1
- package/dist/auth/account_action_specs.js +9 -0
- package/dist/auth/actor_lookup_action_specs.d.ts +127 -0
- package/dist/auth/actor_lookup_action_specs.d.ts.map +1 -0
- package/dist/auth/actor_lookup_action_specs.js +93 -0
- package/dist/auth/actor_lookup_actions.d.ts +19 -0
- package/dist/auth/actor_lookup_actions.d.ts.map +1 -0
- package/dist/auth/actor_lookup_actions.js +32 -0
- package/dist/auth/actor_lookup_queries.d.ts +44 -0
- package/dist/auth/actor_lookup_queries.d.ts.map +1 -0
- package/dist/auth/actor_lookup_queries.js +42 -0
- package/dist/auth/actor_search_action_specs.d.ts +166 -0
- package/dist/auth/actor_search_action_specs.d.ts.map +1 -0
- package/dist/auth/actor_search_action_specs.js +139 -0
- package/dist/auth/actor_search_actions.d.ts +31 -0
- package/dist/auth/actor_search_actions.d.ts.map +1 -0
- package/dist/auth/actor_search_actions.js +61 -0
- package/dist/auth/actor_search_queries.d.ts +75 -0
- package/dist/auth/actor_search_queries.d.ts.map +1 -0
- package/dist/auth/actor_search_queries.js +91 -0
- package/dist/auth/admin_action_specs.d.ts +35 -0
- package/dist/auth/admin_action_specs.d.ts.map +1 -1
- package/dist/auth/admin_action_specs.js +35 -0
- package/dist/auth/admin_actions.js +2 -2
- package/dist/auth/all_action_spec_registries.d.ts +55 -0
- package/dist/auth/all_action_spec_registries.d.ts.map +1 -0
- package/dist/auth/all_action_spec_registries.js +59 -0
- package/dist/auth/audit_emitter.d.ts +1 -1
- package/dist/auth/audit_emitter.js +2 -2
- package/dist/auth/audit_log_queries.d.ts +1 -1
- package/dist/auth/audit_log_queries.js +3 -3
- package/dist/auth/audit_log_routes.d.ts +1 -1
- package/dist/auth/audit_log_routes.js +1 -1
- package/dist/auth/audit_log_schema.d.ts +5 -5
- package/dist/auth/audit_log_schema.js +7 -7
- package/dist/auth/auth_ddl.d.ts +7 -0
- package/dist/auth/auth_ddl.d.ts.map +1 -1
- package/dist/auth/auth_ddl.js +8 -0
- package/dist/auth/credential_type_schema.d.ts +1 -1
- package/dist/auth/credential_type_schema.js +3 -3
- package/dist/auth/grant_path_schema.d.ts +1 -1
- package/dist/auth/grant_path_schema.js +3 -3
- package/dist/auth/migrations.d.ts +4 -4
- package/dist/auth/migrations.d.ts.map +1 -1
- package/dist/auth/migrations.js +7 -6
- package/dist/auth/role_grant_offer_action_specs.d.ts +17 -0
- package/dist/auth/role_grant_offer_action_specs.d.ts.map +1 -1
- package/dist/auth/role_grant_offer_action_specs.js +17 -0
- package/dist/auth/role_grant_offer_actions.js +2 -2
- package/dist/auth/role_grant_offer_notifications.d.ts +2 -2
- package/dist/auth/role_grant_offer_notifications.js +2 -2
- package/dist/auth/role_grant_queries.d.ts +21 -0
- package/dist/auth/role_grant_queries.d.ts.map +1 -1
- package/dist/auth/role_grant_queries.js +31 -0
- package/dist/auth/role_schema.d.ts +2 -2
- package/dist/auth/role_schema.js +3 -3
- package/dist/auth/self_service_role_action_specs.d.ts +8 -0
- package/dist/auth/self_service_role_action_specs.d.ts.map +1 -1
- package/dist/auth/self_service_role_action_specs.js +8 -0
- package/dist/auth/self_service_role_actions.d.ts +1 -1
- package/dist/auth/self_service_role_actions.js +2 -2
- package/dist/auth/session_cookie.d.ts +1 -1
- package/dist/auth/session_cookie.js +1 -1
- package/dist/auth/session_middleware.d.ts +1 -1
- package/dist/auth/session_middleware.js +5 -5
- package/dist/rate_limiter.d.ts +5 -5
- package/dist/rate_limiter.js +6 -6
- package/dist/realtime/sse_auth_guard.d.ts +3 -3
- package/dist/realtime/sse_auth_guard.js +4 -4
- package/dist/server/app_backend.d.ts +3 -3
- package/dist/server/app_backend.js +4 -4
- package/dist/server/app_server.d.ts +1 -1
- package/dist/server/app_server.js +10 -10
- package/dist/testing/CLAUDE.md +22 -12
- package/dist/testing/admin_integration.js +4 -4
- package/dist/testing/app_server.d.ts +1 -1
- package/dist/testing/app_server.js +2 -2
- package/dist/testing/attack_surface.d.ts +4 -4
- package/dist/testing/attack_surface.js +6 -6
- package/dist/testing/audit_completeness.js +4 -4
- package/dist/testing/data_exposure.d.ts +2 -2
- package/dist/testing/data_exposure.js +7 -7
- package/dist/testing/db.d.ts +8 -8
- package/dist/testing/db.js +11 -11
- package/dist/testing/integration.js +4 -4
- package/dist/testing/integration_helpers.d.ts +6 -6
- package/dist/testing/integration_helpers.js +7 -7
- package/dist/testing/rate_limiting.js +4 -4
- package/dist/testing/round_trip.js +2 -2
- package/dist/testing/rpc_round_trip.js +2 -2
- package/dist/testing/schema_generators.d.ts.map +1 -1
- package/dist/testing/schema_generators.js +23 -2
- package/dist/testing/sse_round_trip.js +2 -2
- package/dist/testing/surface_invariants.d.ts +4 -4
- package/dist/testing/surface_invariants.js +5 -5
- package/package.json +1 -1
|
@@ -64,7 +64,7 @@ export const AuditOutcome = z.enum(['success', 'failure']);
|
|
|
64
64
|
* stub schema); the Zod schemas themselves are reachable and mutable —
|
|
65
65
|
* freeze isn't a security boundary.
|
|
66
66
|
*/
|
|
67
|
-
export const
|
|
67
|
+
export const audit_metadata_schemas = Object.freeze({
|
|
68
68
|
login: z
|
|
69
69
|
.looseObject({
|
|
70
70
|
username: z.string().meta({ description: 'Username submitted with the login attempt.' }),
|
|
@@ -265,9 +265,9 @@ export const get_audit_metadata = (event) => {
|
|
|
265
265
|
return event.metadata;
|
|
266
266
|
};
|
|
267
267
|
/** Builtin fuz_app audit-log config — every existing event type and its metadata schema. */
|
|
268
|
-
export const
|
|
268
|
+
export const builtin_audit_log_config = Object.freeze({
|
|
269
269
|
event_types: AUDIT_EVENT_TYPES,
|
|
270
|
-
metadata_schemas:
|
|
270
|
+
metadata_schemas: audit_metadata_schemas,
|
|
271
271
|
});
|
|
272
272
|
/**
|
|
273
273
|
* Build an `AuditLogConfig` by merging fuz_app builtins with consumer extras.
|
|
@@ -277,20 +277,20 @@ export const BUILTIN_AUDIT_LOG_CONFIG = Object.freeze({
|
|
|
277
277
|
*
|
|
278
278
|
* Call once at startup; pass the result to `create_app_backend` (which
|
|
279
279
|
* threads it into `AppDeps.audit`). Builtin handlers omit the
|
|
280
|
-
* `audit_log_config` slot and pick up `
|
|
280
|
+
* `audit_log_config` slot and pick up `builtin_audit_log_config`.
|
|
281
281
|
*
|
|
282
282
|
* @throws Error when an `extra_events` key collides with a builtin event type or fails `AuditEventTypeName` format validation
|
|
283
283
|
*/
|
|
284
284
|
export const create_audit_log_config = (options) => {
|
|
285
285
|
const extras = options?.extra_events;
|
|
286
286
|
if (!extras)
|
|
287
|
-
return
|
|
287
|
+
return builtin_audit_log_config;
|
|
288
288
|
const extra_entries = Object.entries(extras);
|
|
289
289
|
if (extra_entries.length === 0)
|
|
290
|
-
return
|
|
290
|
+
return builtin_audit_log_config;
|
|
291
291
|
const builtin_set = new Set(AUDIT_EVENT_TYPES);
|
|
292
292
|
const extra_keys = [];
|
|
293
|
-
const metadata_schemas = { ...
|
|
293
|
+
const metadata_schemas = { ...audit_metadata_schemas };
|
|
294
294
|
for (const [t, schema] of extra_entries) {
|
|
295
295
|
if (builtin_set.has(t)) {
|
|
296
296
|
throw new Error(`extra_events key "${t}" collides with a builtin event type — pick a distinct string (e.g. "app_${t}")`);
|
package/dist/auth/auth_ddl.d.ts
CHANGED
|
@@ -12,6 +12,13 @@
|
|
|
12
12
|
export declare const ACCOUNT_SCHEMA = "\nCREATE TABLE IF NOT EXISTS account (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n username TEXT UNIQUE NOT NULL,\n email TEXT,\n email_verified BOOLEAN NOT NULL DEFAULT false,\n password_hash TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n created_by UUID,\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_by UUID\n)";
|
|
13
13
|
export declare const ACTOR_SCHEMA = "\nCREATE TABLE IF NOT EXISTS actor (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n account_id UUID NOT NULL REFERENCES account(id) ON DELETE CASCADE,\n name TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n updated_at TIMESTAMPTZ,\n updated_by UUID REFERENCES actor(id) ON DELETE SET NULL\n)";
|
|
14
14
|
export declare const ACTOR_INDEX = "\nCREATE INDEX IF NOT EXISTS idx_actor_account ON actor(account_id)";
|
|
15
|
+
/**
|
|
16
|
+
* Functional index on `LOWER(actor.name)` supporting case-insensitive
|
|
17
|
+
* prefix search by `actor_search` (`LOWER(name) LIKE LOWER(query) || '%'`).
|
|
18
|
+
* `text_pattern_ops` keeps the LIKE-prefix pattern index-eligible — without
|
|
19
|
+
* it the planner falls back to a sequential scan once the table grows.
|
|
20
|
+
*/
|
|
21
|
+
export declare const ACTOR_NAME_LOWER_INDEX = "\nCREATE INDEX IF NOT EXISTS idx_actor_name_lower ON actor (LOWER(name) text_pattern_ops)";
|
|
15
22
|
export declare const ROLE_GRANT_SCHEMA = "\nCREATE TABLE IF NOT EXISTS role_grant (\n id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\n actor_id UUID NOT NULL REFERENCES actor(id) ON DELETE CASCADE,\n role TEXT NOT NULL,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMPTZ,\n revoked_at TIMESTAMPTZ,\n revoked_by UUID REFERENCES actor(id) ON DELETE SET NULL,\n granted_by UUID REFERENCES actor(id) ON DELETE SET NULL\n)";
|
|
16
23
|
export declare const ROLE_GRANT_INDEXES: string[];
|
|
17
24
|
export declare const AUTH_SESSION_SCHEMA = "\nCREATE TABLE IF NOT EXISTS auth_session (\n id TEXT PRIMARY KEY,\n account_id UUID NOT NULL REFERENCES account(id) ON DELETE CASCADE,\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\n expires_at TIMESTAMPTZ NOT NULL,\n last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\n)";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth_ddl.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/auth_ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,cAAc,8WAWzB,CAAC;AAEH,eAAO,MAAM,YAAY,mUAQvB,CAAC;AAEH,eAAO,MAAM,WAAW,wEAC0C,CAAC;AAEnE,eAAO,MAAM,iBAAiB,2ZAU5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,UAI9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,0RAO9B,CAAC;AAEH,eAAO,MAAM,oBAAoB,UAGhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,iUAU3B,CAAC;AAEH,eAAO,MAAM,mBAAmB,4GACsE,CAAC;AAEvG,eAAO,MAAM,yBAAyB,6FACiD,CAAC;AAExF,eAAO,MAAM,eAAe,gFAC8C,CAAC;AAE3E,eAAO,MAAM,qBAAqB,wJAIhC,CAAC;AAEH,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,yHAGP,CAAC;AAE1B,eAAO,MAAM,aAAa,6ZAUxB,CAAC;AAEH,eAAO,MAAM,cAAc,UAI1B,CAAC;AAEF,eAAO,MAAM,mBAAmB,oMAM9B,CAAC;AAEH,eAAO,MAAM,iBAAiB,sEACkC,CAAC"}
|
|
1
|
+
{"version":3,"file":"auth_ddl.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/auth_ddl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,eAAO,MAAM,cAAc,8WAWzB,CAAC;AAEH,eAAO,MAAM,YAAY,mUAQvB,CAAC;AAEH,eAAO,MAAM,WAAW,wEAC0C,CAAC;AAEnE;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,8FACqD,CAAC;AAEzF,eAAO,MAAM,iBAAiB,2ZAU5B,CAAC;AAEH,eAAO,MAAM,kBAAkB,UAI9B,CAAC;AAEF,eAAO,MAAM,mBAAmB,0RAO9B,CAAC;AAEH,eAAO,MAAM,oBAAoB,UAGhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,iUAU3B,CAAC;AAEH,eAAO,MAAM,mBAAmB,4GACsE,CAAC;AAEvG,eAAO,MAAM,yBAAyB,6FACiD,CAAC;AAExF,eAAO,MAAM,eAAe,gFAC8C,CAAC;AAE3E,eAAO,MAAM,qBAAqB,wJAIhC,CAAC;AAEH,6FAA6F;AAC7F,eAAO,MAAM,mBAAmB,yHAGP,CAAC;AAE1B,eAAO,MAAM,aAAa,6ZAUxB,CAAC;AAEH,eAAO,MAAM,cAAc,UAI1B,CAAC;AAEF,eAAO,MAAM,mBAAmB,oMAM9B,CAAC;AAEH,eAAO,MAAM,iBAAiB,sEACkC,CAAC"}
|
package/dist/auth/auth_ddl.js
CHANGED
|
@@ -32,6 +32,14 @@ CREATE TABLE IF NOT EXISTS actor (
|
|
|
32
32
|
)`;
|
|
33
33
|
export const ACTOR_INDEX = `
|
|
34
34
|
CREATE INDEX IF NOT EXISTS idx_actor_account ON actor(account_id)`;
|
|
35
|
+
/**
|
|
36
|
+
* Functional index on `LOWER(actor.name)` supporting case-insensitive
|
|
37
|
+
* prefix search by `actor_search` (`LOWER(name) LIKE LOWER(query) || '%'`).
|
|
38
|
+
* `text_pattern_ops` keeps the LIKE-prefix pattern index-eligible — without
|
|
39
|
+
* it the planner falls back to a sequential scan once the table grows.
|
|
40
|
+
*/
|
|
41
|
+
export const ACTOR_NAME_LOWER_INDEX = `
|
|
42
|
+
CREATE INDEX IF NOT EXISTS idx_actor_name_lower ON actor (LOWER(name) text_pattern_ops)`;
|
|
35
43
|
export const ROLE_GRANT_SCHEMA = `
|
|
36
44
|
CREATE TABLE IF NOT EXISTS role_grant (
|
|
37
45
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
@@ -67,7 +67,7 @@ export interface CredentialTypeMeta {
|
|
|
67
67
|
* here. Read once at startup by `create_credential_type_schema`;
|
|
68
68
|
* runtime mutation has no effect on already-built schemas.
|
|
69
69
|
*/
|
|
70
|
-
export declare const
|
|
70
|
+
export declare const builtin_credential_type_meta: ReadonlyMap<string, CredentialTypeMeta>;
|
|
71
71
|
/** The result of `create_credential_type_schema` — a Zod schema and metadata map. */
|
|
72
72
|
export interface CredentialTypeSchemaResult {
|
|
73
73
|
/**
|
|
@@ -60,7 +60,7 @@ export const BuiltinCredentialType = z.enum(BUILTIN_CREDENTIAL_TYPES);
|
|
|
60
60
|
* here. Read once at startup by `create_credential_type_schema`;
|
|
61
61
|
* runtime mutation has no effect on already-built schemas.
|
|
62
62
|
*/
|
|
63
|
-
export const
|
|
63
|
+
export const builtin_credential_type_meta = new Map([
|
|
64
64
|
[
|
|
65
65
|
CREDENTIAL_TYPE_SESSION,
|
|
66
66
|
{ description: 'Cookie-based session credential, signed and validated server-side.' },
|
|
@@ -109,7 +109,7 @@ export const create_credential_type_schema = (consumer_types = {}) => {
|
|
|
109
109
|
if (!parsed.success) {
|
|
110
110
|
throw new Error(`Invalid credential-type name "${name}": ${parsed.error.issues[0].message}`);
|
|
111
111
|
}
|
|
112
|
-
if (
|
|
112
|
+
if (builtin_credential_type_meta.has(name)) {
|
|
113
113
|
throw new Error(`Consumer credential-type "${name}" collides with builtin credential-type`);
|
|
114
114
|
}
|
|
115
115
|
if (seen.has(name)) {
|
|
@@ -119,7 +119,7 @@ export const create_credential_type_schema = (consumer_types = {}) => {
|
|
|
119
119
|
}
|
|
120
120
|
const all_names = [...BUILTIN_CREDENTIAL_TYPES, ...consumer_names];
|
|
121
121
|
const CredentialType = z.enum(all_names);
|
|
122
|
-
const credential_types = new Map(
|
|
122
|
+
const credential_types = new Map(builtin_credential_type_meta);
|
|
123
123
|
for (const name of consumer_names) {
|
|
124
124
|
credential_types.set(name, consumer_types[name]);
|
|
125
125
|
}
|
|
@@ -70,7 +70,7 @@ export interface GrantPathMeta {
|
|
|
70
70
|
* here. Read once at startup by `create_grant_path_schema`; runtime
|
|
71
71
|
* mutation has no effect on already-built schemas.
|
|
72
72
|
*/
|
|
73
|
-
export declare const
|
|
73
|
+
export declare const builtin_grant_path_meta: ReadonlyMap<string, GrantPathMeta>;
|
|
74
74
|
/** The result of `create_grant_path_schema` — a Zod schema and metadata map. */
|
|
75
75
|
export interface GrantPathSchemaResult {
|
|
76
76
|
/**
|
|
@@ -63,7 +63,7 @@ export const BuiltinGrantPath = z.enum(BUILTIN_GRANT_PATHS);
|
|
|
63
63
|
* here. Read once at startup by `create_grant_path_schema`; runtime
|
|
64
64
|
* mutation has no effect on already-built schemas.
|
|
65
65
|
*/
|
|
66
|
-
export const
|
|
66
|
+
export const builtin_grant_path_meta = new Map([
|
|
67
67
|
[
|
|
68
68
|
GRANT_PATH_ADMIN,
|
|
69
69
|
{
|
|
@@ -119,7 +119,7 @@ export const create_grant_path_schema = (consumer_paths = {}) => {
|
|
|
119
119
|
if (!parsed.success) {
|
|
120
120
|
throw new Error(`Invalid grant-path name "${name}": ${parsed.error.issues[0].message}`);
|
|
121
121
|
}
|
|
122
|
-
if (
|
|
122
|
+
if (builtin_grant_path_meta.has(name)) {
|
|
123
123
|
throw new Error(`Consumer grant-path "${name}" collides with builtin grant-path`);
|
|
124
124
|
}
|
|
125
125
|
if (seen.has(name)) {
|
|
@@ -129,7 +129,7 @@ export const create_grant_path_schema = (consumer_paths = {}) => {
|
|
|
129
129
|
}
|
|
130
130
|
const all_names = [...BUILTIN_GRANT_PATHS, ...consumer_names];
|
|
131
131
|
const GrantPath = z.enum(all_names);
|
|
132
|
-
const grant_paths = new Map(
|
|
132
|
+
const grant_paths = new Map(builtin_grant_path_meta);
|
|
133
133
|
for (const name of consumer_names) {
|
|
134
134
|
grant_paths.set(name, consumer_paths[name]);
|
|
135
135
|
}
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* To add a migration in the pre-stable phase, prefer extending an existing
|
|
19
19
|
* entry's body (consumers will re-bootstrap on upgrade). If you do append
|
|
20
|
-
* a new entry to `
|
|
20
|
+
* a new entry to `auth_migrations`, the runner will apply it on existing
|
|
21
21
|
* tracker rows — the same shape that will become mandatory once the
|
|
22
22
|
* schema stabilizes:
|
|
23
23
|
*
|
|
@@ -46,7 +46,7 @@ export declare const AUTH_MIGRATION_NAMESPACE = "fuz_auth";
|
|
|
46
46
|
* as `ReadonlyArray<string>` (not a literal tuple) so `.includes()` accepts
|
|
47
47
|
* any consumer-supplied namespace string without a cast.
|
|
48
48
|
*/
|
|
49
|
-
export declare const
|
|
49
|
+
export declare const reserved_migration_namespaces: ReadonlyArray<string>;
|
|
50
50
|
/**
|
|
51
51
|
* Auth schema migrations in order.
|
|
52
52
|
*
|
|
@@ -67,7 +67,7 @@ export declare const RESERVED_MIGRATION_NAMESPACES: ReadonlyArray<string>;
|
|
|
67
67
|
* (registry-membership validation against `create_scope_kind_schema`);
|
|
68
68
|
* v2 may add INSERT-time `(role, scope_kind)` enforcement.
|
|
69
69
|
*/
|
|
70
|
-
export declare const
|
|
70
|
+
export declare const auth_migrations: Array<Migration>;
|
|
71
71
|
/** Pre-composed migration namespace for auth tables. */
|
|
72
|
-
export declare const
|
|
72
|
+
export declare const auth_migration_ns: MigrationNamespace;
|
|
73
73
|
//# sourceMappingURL=migrations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrations.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;
|
|
1
|
+
{"version":3,"file":"migrations.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AA+BH,OAAO,KAAK,EAAC,SAAS,EAAE,kBAAkB,EAAC,MAAM,kBAAkB,CAAC;AAEpE,wDAAwD;AACxD,eAAO,MAAM,wBAAwB,aAAa,CAAC;AAEnD;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,EAAE,aAAa,CAAC,MAAM,CAA8B,CAAC;AAE/F;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,SAAS,CAsF5C,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,iBAAiB,EAAE,kBAG/B,CAAC"}
|
package/dist/auth/migrations.js
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* To add a migration in the pre-stable phase, prefer extending an existing
|
|
19
19
|
* entry's body (consumers will re-bootstrap on upgrade). If you do append
|
|
20
|
-
* a new entry to `
|
|
20
|
+
* a new entry to `auth_migrations`, the runner will apply it on existing
|
|
21
21
|
* tracker rows — the same shape that will become mandatory once the
|
|
22
22
|
* schema stabilizes:
|
|
23
23
|
*
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
*
|
|
37
37
|
* @module
|
|
38
38
|
*/
|
|
39
|
-
import { ACCOUNT_SCHEMA, ACCOUNT_EMAIL_INDEX, ACCOUNT_USERNAME_CI_INDEX, ACTOR_SCHEMA, ACTOR_INDEX, ROLE_GRANT_SCHEMA, ROLE_GRANT_INDEXES, AUTH_SESSION_SCHEMA, AUTH_SESSION_INDEXES, API_TOKEN_SCHEMA, API_TOKEN_INDEX, BOOTSTRAP_LOCK_SCHEMA, BOOTSTRAP_LOCK_SEED, INVITE_SCHEMA, INVITE_INDEXES, APP_SETTINGS_SCHEMA, APP_SETTINGS_SEED, } from './auth_ddl.js';
|
|
39
|
+
import { ACCOUNT_SCHEMA, ACCOUNT_EMAIL_INDEX, ACCOUNT_USERNAME_CI_INDEX, ACTOR_SCHEMA, ACTOR_INDEX, ACTOR_NAME_LOWER_INDEX, ROLE_GRANT_SCHEMA, ROLE_GRANT_INDEXES, AUTH_SESSION_SCHEMA, AUTH_SESSION_INDEXES, API_TOKEN_SCHEMA, API_TOKEN_INDEX, BOOTSTRAP_LOCK_SCHEMA, BOOTSTRAP_LOCK_SEED, INVITE_SCHEMA, INVITE_INDEXES, APP_SETTINGS_SCHEMA, APP_SETTINGS_SEED, } from './auth_ddl.js';
|
|
40
40
|
import { AUDIT_LOG_SCHEMA, AUDIT_LOG_INDEXES } from './audit_log_ddl.js';
|
|
41
41
|
import { ROLE_GRANT_OFFER_SCHEMA, ROLE_GRANT_OFFER_PENDING_UNIQUE_INDEX, ROLE_GRANT_OFFER_INBOX_INDEX, ROLE_GRANT_OFFER_SCOPE_SENTINEL_UUID, ROLE_GRANT_OFFER_SCOPE_KIND_GLOBAL_TOKEN, } from './role_grant_offer_ddl.js';
|
|
42
42
|
/** Namespace identifier for fuz_app auth migrations. */
|
|
@@ -48,7 +48,7 @@ export const AUTH_MIGRATION_NAMESPACE = 'fuz_auth';
|
|
|
48
48
|
* as `ReadonlyArray<string>` (not a literal tuple) so `.includes()` accepts
|
|
49
49
|
* any consumer-supplied namespace string without a cast.
|
|
50
50
|
*/
|
|
51
|
-
export const
|
|
51
|
+
export const reserved_migration_namespaces = [AUTH_MIGRATION_NAMESPACE];
|
|
52
52
|
/**
|
|
53
53
|
* Auth schema migrations in order.
|
|
54
54
|
*
|
|
@@ -69,7 +69,7 @@ export const RESERVED_MIGRATION_NAMESPACES = [AUTH_MIGRATION_NAMESPACE];
|
|
|
69
69
|
* (registry-membership validation against `create_scope_kind_schema`);
|
|
70
70
|
* v2 may add INSERT-time `(role, scope_kind)` enforcement.
|
|
71
71
|
*/
|
|
72
|
-
export const
|
|
72
|
+
export const auth_migrations = [
|
|
73
73
|
// v0: full auth schema — all IF NOT EXISTS, safe for existing databases
|
|
74
74
|
{
|
|
75
75
|
name: 'full_auth_schema',
|
|
@@ -79,6 +79,7 @@ export const AUTH_MIGRATIONS = [
|
|
|
79
79
|
await db.query(ACCOUNT_USERNAME_CI_INDEX);
|
|
80
80
|
await db.query(ACTOR_SCHEMA);
|
|
81
81
|
await db.query(ACTOR_INDEX);
|
|
82
|
+
await db.query(ACTOR_NAME_LOWER_INDEX);
|
|
82
83
|
await db.query(ROLE_GRANT_SCHEMA);
|
|
83
84
|
for (const sql of ROLE_GRANT_INDEXES) {
|
|
84
85
|
await db.query(sql);
|
|
@@ -150,7 +151,7 @@ export const AUTH_MIGRATIONS = [
|
|
|
150
151
|
},
|
|
151
152
|
];
|
|
152
153
|
/** Pre-composed migration namespace for auth tables. */
|
|
153
|
-
export const
|
|
154
|
+
export const auth_migration_ns = {
|
|
154
155
|
namespace: AUTH_MIGRATION_NAMESPACE,
|
|
155
|
-
migrations:
|
|
156
|
+
migrations: auth_migrations,
|
|
156
157
|
};
|
|
@@ -209,6 +209,16 @@ export declare const RoleGrantRevokeOutput: z.ZodObject<{
|
|
|
209
209
|
revoked: z.ZodLiteral<true>;
|
|
210
210
|
}, z.core.$strict>;
|
|
211
211
|
export type RoleGrantRevokeOutput = z.infer<typeof RoleGrantRevokeOutput>;
|
|
212
|
+
/**
|
|
213
|
+
* `rate_limit: 'account'` throttles offer-spam at the authenticated
|
|
214
|
+
* grantor and bounds the account-existence oracle on `to_account_id` —
|
|
215
|
+
* the same shape as `invite_create_action_spec` upstream addresses, where
|
|
216
|
+
* a hostile authed caller iterates recipients to probe
|
|
217
|
+
* `ERROR_ACCOUNT_NOT_FOUND` (and the actor-binding via
|
|
218
|
+
* `ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH`) as an enumeration
|
|
219
|
+
* vector. Failure-outcome audit rows preserve the forensic trail; the
|
|
220
|
+
* rate cap closes the budget.
|
|
221
|
+
*/
|
|
212
222
|
export declare const role_grant_offer_create_action_spec: {
|
|
213
223
|
method: string;
|
|
214
224
|
kind: "request_response";
|
|
@@ -250,6 +260,7 @@ export declare const role_grant_offer_create_action_spec: {
|
|
|
250
260
|
async: true;
|
|
251
261
|
description: string;
|
|
252
262
|
error_reasons: ("role_grant_offer_self_target" | "role_grant_offer_role_not_grantable" | "role_grant_offer_not_authorized" | "role_grant_offer_actor_account_mismatch")[];
|
|
263
|
+
rate_limit: "account";
|
|
253
264
|
};
|
|
254
265
|
export declare const role_grant_offer_accept_action_spec: {
|
|
255
266
|
method: string;
|
|
@@ -405,6 +416,12 @@ export declare const role_grant_offer_history_action_spec: {
|
|
|
405
416
|
async: true;
|
|
406
417
|
description: string;
|
|
407
418
|
};
|
|
419
|
+
/**
|
|
420
|
+
* `rate_limit: 'account'` bounds admin-side burn of `role_grant_revoke` —
|
|
421
|
+
* the action is admin-gated and audit-trailed, but the per-account cap
|
|
422
|
+
* keeps a single admin script from churning role_grants in a loop and
|
|
423
|
+
* obscuring audit context for unrelated activity.
|
|
424
|
+
*/
|
|
408
425
|
export declare const role_grant_revoke_action_spec: {
|
|
409
426
|
method: string;
|
|
410
427
|
kind: "request_response";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role_grant_offer_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAGtB,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAUzE,oEAAoE;AACpE,eAAO,MAAM,kCAAkC,EAAG,8BAAuC,CAAC;AAC1F,kEAAkE;AAClE,eAAO,MAAM,+BAA+B,EAAG,2BAAoC,CAAC;AACpF,sDAAsD;AACtD,eAAO,MAAM,8BAA8B,EAAG,0BAAmC,CAAC;AAClF,wGAAwG;AACxG,eAAO,MAAM,gCAAgC,EAAG,4BAAqC,CAAC;AACtF,uIAAuI;AACvI,eAAO,MAAM,yCAAyC,EACrD,qCAA8C,CAAC;AAChD,gKAAgK;AAChK,eAAO,MAAM,qCAAqC,EAAG,iCAA0C,CAAC;AAChG,6FAA6F;AAC7F,eAAO,MAAM,qCAAqC,EAAG,iCAA0C,CAAC;AAChG,wHAAwH;AACxH,eAAO,MAAM,6CAA6C,EACzD,yCAAkD,CAAC;AAIpD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;kBAoBpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElF,2CAA2C;AAC3C,eAAO,MAAM,yBAAyB;;;kBAGpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,yBAAyB,CAAC,CAAC;AAElF,4CAA4C;AAC5C,eAAO,MAAM,0BAA0B;;;;kBAQrC,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF,4CAA4C;AAC5C,eAAO,MAAM,0BAA0B;;;kBAGrC,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF,uGAAuG;AACvG,eAAO,MAAM,uBAAuB;;;mBAOvB,CAAC;AACd,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB;;;;;kBAQ/B,CAAC;AACH,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,0BAA0B;;;;;mBAa1B,CAAC;AACd,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF,4CAA4C;AAC5C,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;kBAErC,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF,4CAA4C;AAC5C,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;kBAIrC,CAAC;AACH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAEpF,0EAA0E;AAC1E,eAAO,MAAM,sBAAsB;;kBAAwC,CAAC;AAC5E,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,sBAAsB,CAAC,CAAC;AAE5E,0CAA0C;AAC1C,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;kBAAwD,CAAC;AAC9F,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,6CAA6C;AAC7C,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;kBAAwD,CAAC;AACjG,MAAM,MAAM,2BAA2B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEtF,sCAAsC;AACtC,eAAO,MAAM,qBAAqB;;;kBAGhC,CAAC;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAI1E,eAAO,MAAM,mCAAmC
|
|
1
|
+
{"version":3,"file":"role_grant_offer_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_offer_action_specs.ts"],"names":[],"mappings":"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"}
|
|
@@ -157,6 +157,16 @@ export const RoleGrantRevokeOutput = z.strictObject({
|
|
|
157
157
|
revoked: z.literal(true),
|
|
158
158
|
});
|
|
159
159
|
// -- Action specs -----------------------------------------------------------
|
|
160
|
+
/**
|
|
161
|
+
* `rate_limit: 'account'` throttles offer-spam at the authenticated
|
|
162
|
+
* grantor and bounds the account-existence oracle on `to_account_id` —
|
|
163
|
+
* the same shape as `invite_create_action_spec` upstream addresses, where
|
|
164
|
+
* a hostile authed caller iterates recipients to probe
|
|
165
|
+
* `ERROR_ACCOUNT_NOT_FOUND` (and the actor-binding via
|
|
166
|
+
* `ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH`) as an enumeration
|
|
167
|
+
* vector. Failure-outcome audit rows preserve the forensic trail; the
|
|
168
|
+
* rate cap closes the budget.
|
|
169
|
+
*/
|
|
160
170
|
export const role_grant_offer_create_action_spec = {
|
|
161
171
|
method: 'role_grant_offer_create',
|
|
162
172
|
kind: 'request_response',
|
|
@@ -173,6 +183,7 @@ export const role_grant_offer_create_action_spec = {
|
|
|
173
183
|
ERROR_ROLE_GRANT_OFFER_NOT_AUTHORIZED,
|
|
174
184
|
ERROR_ROLE_GRANT_OFFER_ACTOR_ACCOUNT_MISMATCH,
|
|
175
185
|
],
|
|
186
|
+
rate_limit: 'account',
|
|
176
187
|
};
|
|
177
188
|
export const role_grant_offer_accept_action_spec = {
|
|
178
189
|
method: 'role_grant_offer_accept',
|
|
@@ -237,6 +248,12 @@ export const role_grant_offer_history_action_spec = {
|
|
|
237
248
|
async: true,
|
|
238
249
|
description: 'List every offer involving the caller (either direction), including terminal rows, newest first. Admins may pass `account_id` to inspect another account.',
|
|
239
250
|
};
|
|
251
|
+
/**
|
|
252
|
+
* `rate_limit: 'account'` bounds admin-side burn of `role_grant_revoke` —
|
|
253
|
+
* the action is admin-gated and audit-trailed, but the per-account cap
|
|
254
|
+
* keeps a single admin script from churning role_grants in a loop and
|
|
255
|
+
* obscuring audit context for unrelated activity.
|
|
256
|
+
*/
|
|
240
257
|
export const role_grant_revoke_action_spec = {
|
|
241
258
|
method: 'role_grant_revoke',
|
|
242
259
|
kind: 'request_response',
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
import { rpc_action, } from '../actions/action_rpc.js';
|
|
41
41
|
import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
|
|
42
42
|
import { emit_after_commit } from '../http/pending_effects.js';
|
|
43
|
-
import {
|
|
43
|
+
import { builtin_role_specs_by_name, ROLE_ADMIN, role_has_grant_path, } from './role_schema.js';
|
|
44
44
|
import { GRANT_PATH_ADMIN } from './grant_path_schema.js';
|
|
45
45
|
import { ROLE_GRANT_OFFER_DEFAULT_TTL_MS, to_role_grant_offer_json, } from './role_grant_offer_schema.js';
|
|
46
46
|
import { query_role_grant_offer_create, query_role_grant_offer_decline, query_role_grant_offer_retract, query_role_grant_offer_list, query_role_grant_offer_history_for_account, query_accept_offer, RoleGrantOfferActorAccountMismatchError, RoleGrantOfferActorMismatchError, RoleGrantOfferAlreadyTerminalError, RoleGrantOfferExpiredError, RoleGrantOfferNotFoundError, RoleGrantOfferSelfTargetError, } from './role_grant_offer_queries.js';
|
|
@@ -108,7 +108,7 @@ export const authorize_admin_or_holder = async (auth, input, _deps, _ctx) => {
|
|
|
108
108
|
*/
|
|
109
109
|
export const create_role_grant_offer_actions = (deps, options = {}) => {
|
|
110
110
|
const { log, audit, notification_sender = null } = deps;
|
|
111
|
-
const role_specs = options.roles?.role_specs ??
|
|
111
|
+
const role_specs = options.roles?.role_specs ?? builtin_role_specs_by_name;
|
|
112
112
|
const default_ttl_ms = options.default_ttl_ms ?? ROLE_GRANT_OFFER_DEFAULT_TTL_MS;
|
|
113
113
|
const authorize = options.authorize ?? default_authorize;
|
|
114
114
|
// Four denial paths (admin-grant-path gate, authorize, self-target,
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* `NotificationSender.send_to_account` argument), not in the payload.
|
|
24
24
|
*
|
|
25
25
|
* The specs surface as `EventSpec`s via `create_action_event_spec` — callers
|
|
26
|
-
* append `
|
|
26
|
+
* append `role_grant_offer_notification_specs` to their `event_specs` on
|
|
27
27
|
* `create_app_server` so the surface reflects them and DEV-mode broadcast
|
|
28
28
|
* validation catches payload drift.
|
|
29
29
|
*
|
|
@@ -376,7 +376,7 @@ export declare const role_grant_revoke_notification_spec: {
|
|
|
376
376
|
* Pass to `create_app_server`'s `event_specs` so the attack surface reflects
|
|
377
377
|
* them and DEV-mode `create_validated_broadcaster` catches payload drift.
|
|
378
378
|
*/
|
|
379
|
-
export declare const
|
|
379
|
+
export declare const role_grant_offer_notification_specs: Array<EventSpec>;
|
|
380
380
|
export declare const build_role_grant_offer_received_notification: (params: RoleGrantOfferReceivedParams) => JsonrpcNotification;
|
|
381
381
|
export declare const build_role_grant_offer_retracted_notification: (params: RoleGrantOfferRetractedParams) => JsonrpcNotification;
|
|
382
382
|
export declare const build_role_grant_offer_accepted_notification: (params: RoleGrantOfferAcceptedParams) => JsonrpcNotification;
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* `NotificationSender.send_to_account` argument), not in the payload.
|
|
24
24
|
*
|
|
25
25
|
* The specs surface as `EventSpec`s via `create_action_event_spec` — callers
|
|
26
|
-
* append `
|
|
26
|
+
* append `role_grant_offer_notification_specs` to their `event_specs` on
|
|
27
27
|
* `create_app_server` so the surface reflects them and DEV-mode broadcast
|
|
28
28
|
* validation catches payload drift.
|
|
29
29
|
*
|
|
@@ -165,7 +165,7 @@ export const role_grant_revoke_notification_spec = {
|
|
|
165
165
|
* Pass to `create_app_server`'s `event_specs` so the attack surface reflects
|
|
166
166
|
* them and DEV-mode `create_validated_broadcaster` catches payload drift.
|
|
167
167
|
*/
|
|
168
|
-
export const
|
|
168
|
+
export const role_grant_offer_notification_specs = [
|
|
169
169
|
create_action_event_spec(role_grant_offer_received_notification_spec),
|
|
170
170
|
create_action_event_spec(role_grant_offer_retracted_notification_spec),
|
|
171
171
|
create_action_event_spec(role_grant_offer_accepted_notification_spec),
|
|
@@ -113,6 +113,27 @@ export declare const query_role_grant_find_active_for_actor: (deps: QueryDeps, a
|
|
|
113
113
|
* The `IS NOT DISTINCT FROM` comparison handles the NULL case uniformly.
|
|
114
114
|
*/
|
|
115
115
|
export declare const query_role_grant_has_role: (deps: QueryDeps, actor_id: string, role: string, scope_id?: string | null) => Promise<boolean>;
|
|
116
|
+
/**
|
|
117
|
+
* Account-grain check: does any actor on `account_id` hold an active
|
|
118
|
+
* global role_grant for `role`?
|
|
119
|
+
*
|
|
120
|
+
* Symmetric with `query_role_grant_has_role` but keyed on the account
|
|
121
|
+
* instead of a single actor — for surfaces with `auth: actor: 'none'`
|
|
122
|
+
* that don't load `auth.role_grants` and can't use the in-memory
|
|
123
|
+
* `has_scoped_role` predicate. Joins `role_grant` → `actor`; matches
|
|
124
|
+
* only global role_grants (`scope_id IS NULL`) since the use case is
|
|
125
|
+
* "is the caller's account broadly admin", not scope-aware.
|
|
126
|
+
*
|
|
127
|
+
* Fast under the existing `idx_role_grant_actor` index — the inner
|
|
128
|
+
* `actor_id IN (...)` subquery is index-scan, and the outer EXISTS
|
|
129
|
+
* stops at the first match.
|
|
130
|
+
*
|
|
131
|
+
* @param deps - query dependencies
|
|
132
|
+
* @param account_id - the account to check
|
|
133
|
+
* @param role - the role to check for (e.g. `ROLE_ADMIN`)
|
|
134
|
+
* @returns `true` if any actor on the account has an active global role_grant for `role`
|
|
135
|
+
*/
|
|
136
|
+
export declare const query_account_has_global_role: (deps: QueryDeps, account_id: string, role: string) => Promise<boolean>;
|
|
116
137
|
/**
|
|
117
138
|
* List all role_grants for an actor (including revoked/expired).
|
|
118
139
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"role_grant_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_queries.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"role_grant_queries.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/role_grant_queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -180,6 +180,37 @@ export const query_role_grant_has_role = async (deps, actor_id, role, scope_id)
|
|
|
180
180
|
) AS exists`, [actor_id, role, scope_id ?? null]);
|
|
181
181
|
return row?.exists ?? false;
|
|
182
182
|
};
|
|
183
|
+
/**
|
|
184
|
+
* Account-grain check: does any actor on `account_id` hold an active
|
|
185
|
+
* global role_grant for `role`?
|
|
186
|
+
*
|
|
187
|
+
* Symmetric with `query_role_grant_has_role` but keyed on the account
|
|
188
|
+
* instead of a single actor — for surfaces with `auth: actor: 'none'`
|
|
189
|
+
* that don't load `auth.role_grants` and can't use the in-memory
|
|
190
|
+
* `has_scoped_role` predicate. Joins `role_grant` → `actor`; matches
|
|
191
|
+
* only global role_grants (`scope_id IS NULL`) since the use case is
|
|
192
|
+
* "is the caller's account broadly admin", not scope-aware.
|
|
193
|
+
*
|
|
194
|
+
* Fast under the existing `idx_role_grant_actor` index — the inner
|
|
195
|
+
* `actor_id IN (...)` subquery is index-scan, and the outer EXISTS
|
|
196
|
+
* stops at the first match.
|
|
197
|
+
*
|
|
198
|
+
* @param deps - query dependencies
|
|
199
|
+
* @param account_id - the account to check
|
|
200
|
+
* @param role - the role to check for (e.g. `ROLE_ADMIN`)
|
|
201
|
+
* @returns `true` if any actor on the account has an active global role_grant for `role`
|
|
202
|
+
*/
|
|
203
|
+
export const query_account_has_global_role = async (deps, account_id, role) => {
|
|
204
|
+
const row = await deps.db.query_one(`SELECT EXISTS(
|
|
205
|
+
SELECT 1 FROM role_grant
|
|
206
|
+
WHERE actor_id IN (SELECT id FROM actor WHERE account_id = $1)
|
|
207
|
+
AND role = $2
|
|
208
|
+
AND scope_id IS NULL
|
|
209
|
+
AND revoked_at IS NULL
|
|
210
|
+
AND (expires_at IS NULL OR expires_at > NOW())
|
|
211
|
+
) AS exists`, [account_id, role]);
|
|
212
|
+
return row?.exists ?? false;
|
|
213
|
+
};
|
|
183
214
|
/**
|
|
184
215
|
* List all role_grants for an actor (including revoked/expired).
|
|
185
216
|
*/
|
|
@@ -63,7 +63,7 @@ export type BuiltinRole = z.infer<typeof BuiltinRole>;
|
|
|
63
63
|
* flows. Only useful for diagnostic snapshotting.
|
|
64
64
|
*
|
|
65
65
|
* Builtins (`keeper`, `admin`) ship preconfigured in
|
|
66
|
-
* `
|
|
66
|
+
* `builtin_role_specs_by_name`.
|
|
67
67
|
*/
|
|
68
68
|
export interface RoleSpec {
|
|
69
69
|
/** Unique role name. Must match `RoleName` regex; collisions with builtins throw. */
|
|
@@ -105,7 +105,7 @@ export interface RoleSpec {
|
|
|
105
105
|
* no effect on already-built role schemas (the factory copies entries
|
|
106
106
|
* into a fresh `Map`).
|
|
107
107
|
*/
|
|
108
|
-
export declare const
|
|
108
|
+
export declare const builtin_role_specs_by_name: ReadonlyMap<string, RoleSpec>;
|
|
109
109
|
/** Optional registries to validate `RoleSpec` cross-axis fields against at construction time. */
|
|
110
110
|
export interface CreateRoleSchemaOptions {
|
|
111
111
|
/** Pass `create_credential_type_schema()` to validate `RoleSpec.required_credential_types` entries. */
|
package/dist/auth/role_schema.js
CHANGED
|
@@ -44,7 +44,7 @@ export const BuiltinRole = z.enum(BUILTIN_ROLES);
|
|
|
44
44
|
* no effect on already-built role schemas (the factory copies entries
|
|
45
45
|
* into a fresh `Map`).
|
|
46
46
|
*/
|
|
47
|
-
export const
|
|
47
|
+
export const builtin_role_specs_by_name = new Map([
|
|
48
48
|
[
|
|
49
49
|
ROLE_KEEPER,
|
|
50
50
|
{
|
|
@@ -139,7 +139,7 @@ export const create_role_schema = (consumer_roles, options = {}) => {
|
|
|
139
139
|
if (!parsed.success) {
|
|
140
140
|
throw new Error(`Invalid role name "${spec.name}": ${parsed.error.issues[0].message}`);
|
|
141
141
|
}
|
|
142
|
-
if (
|
|
142
|
+
if (builtin_role_specs_by_name.has(spec.name)) {
|
|
143
143
|
throw new Error(`App role "${spec.name}" collides with builtin role`);
|
|
144
144
|
}
|
|
145
145
|
if (seen.has(spec.name)) {
|
|
@@ -150,7 +150,7 @@ export const create_role_schema = (consumer_roles, options = {}) => {
|
|
|
150
150
|
validate_registry_membership(spec.name, 'applicable_scope_kinds', spec.applicable_scope_kinds, scope_kinds_registry);
|
|
151
151
|
validate_registry_membership(spec.name, 'grant_paths', spec.grant_paths, grant_paths_registry);
|
|
152
152
|
}
|
|
153
|
-
const role_specs = new Map(
|
|
153
|
+
const role_specs = new Map(builtin_role_specs_by_name);
|
|
154
154
|
for (const spec of consumer_roles) {
|
|
155
155
|
role_specs.set(spec.name, spec);
|
|
156
156
|
}
|
|
@@ -29,6 +29,13 @@ export declare const SelfServiceRoleSetOutput: z.ZodObject<{
|
|
|
29
29
|
changed: z.ZodBoolean;
|
|
30
30
|
}, z.core.$strict>;
|
|
31
31
|
export type SelfServiceRoleSetOutput = z.infer<typeof SelfServiceRoleSetOutput>;
|
|
32
|
+
/**
|
|
33
|
+
* `rate_limit: 'account'` bounds audit-row churn. The toggle is idempotent
|
|
34
|
+
* (`changed: false` re-grants/re-revokes), but every call still writes a
|
|
35
|
+
* `role_grant_create` or `role_grant_revoke` audit row with
|
|
36
|
+
* `self_service: true`. Without the cap, a caller could flap the role in
|
|
37
|
+
* a loop to inflate the audit log and obscure other activity.
|
|
38
|
+
*/
|
|
32
39
|
export declare const self_service_role_set_action_spec: {
|
|
33
40
|
method: string;
|
|
34
41
|
kind: "request_response";
|
|
@@ -50,6 +57,7 @@ export declare const self_service_role_set_action_spec: {
|
|
|
50
57
|
}, z.core.$strict>;
|
|
51
58
|
async: true;
|
|
52
59
|
description: string;
|
|
60
|
+
rate_limit: "account";
|
|
53
61
|
};
|
|
54
62
|
/**
|
|
55
63
|
* All self-service role action specs — a codegen-ready registry. Single-element
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self_service_role_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAIzE,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,EAAG,gCAAyC,CAAC;AAE9F,yCAAyC;AACzC,eAAO,MAAM,uBAAuB;;;;kBAOlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;kBAInC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF,eAAO,MAAM,iCAAiC
|
|
1
|
+
{"version":3,"file":"self_service_role_action_specs.d.ts","sourceRoot":"../src/lib/","sources":["../../src/lib/auth/self_service_role_action_specs.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAC,CAAC,EAAC,MAAM,KAAK,CAAC;AAEtB,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,2BAA2B,CAAC;AAIzE,0FAA0F;AAC1F,eAAO,MAAM,oCAAoC,EAAG,gCAAyC,CAAC;AAE9F,yCAAyC;AACzC,eAAO,MAAM,uBAAuB;;;;kBAOlC,CAAC;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAE9E;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;kBAInC,CAAC;AACH,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAEhF;;;;;;GAMG;AACH,eAAO,MAAM,iCAAiC;;;;;;;;;;;;;;;;;;;;;;CAYT,CAAC;AAEtC;;;;GAIG;AACH,eAAO,MAAM,kCAAkC,EAAE,aAAa,CAAC,yBAAyB,CAEvF,CAAC"}
|
|
@@ -30,6 +30,13 @@ export const SelfServiceRoleSetOutput = z.strictObject({
|
|
|
30
30
|
enabled: z.boolean(),
|
|
31
31
|
changed: z.boolean(),
|
|
32
32
|
});
|
|
33
|
+
/**
|
|
34
|
+
* `rate_limit: 'account'` bounds audit-row churn. The toggle is idempotent
|
|
35
|
+
* (`changed: false` re-grants/re-revokes), but every call still writes a
|
|
36
|
+
* `role_grant_create` or `role_grant_revoke` audit row with
|
|
37
|
+
* `self_service: true`. Without the cap, a caller could flap the role in
|
|
38
|
+
* a loop to inflate the audit log and obscure other activity.
|
|
39
|
+
*/
|
|
33
40
|
export const self_service_role_set_action_spec = {
|
|
34
41
|
method: 'self_service_role_set',
|
|
35
42
|
kind: 'request_response',
|
|
@@ -40,6 +47,7 @@ export const self_service_role_set_action_spec = {
|
|
|
40
47
|
output: SelfServiceRoleSetOutput,
|
|
41
48
|
async: true,
|
|
42
49
|
description: 'Toggle a self-service role. Idempotent in both directions — `changed: false` when post-call state already matched the request.',
|
|
50
|
+
rate_limit: 'account',
|
|
43
51
|
};
|
|
44
52
|
/**
|
|
45
53
|
* All self-service role action specs — a codegen-ready registry. Single-element
|
|
@@ -44,7 +44,7 @@ export interface SelfServiceRoleActionsOptions {
|
|
|
44
44
|
/**
|
|
45
45
|
* Optional override allowlist of role strings eligible for
|
|
46
46
|
* self-service. When omitted, eligibility is derived from
|
|
47
|
-
* `roles.role_specs` (or `
|
|
47
|
+
* `roles.role_specs` (or `builtin_role_specs_by_name` when `roles`
|
|
48
48
|
* is also omitted) by selecting every role whose
|
|
49
49
|
* `RoleSpec.grant_paths` includes `'self_service'`. Pass an empty
|
|
50
50
|
* array to lock the surface down (every call comes back as
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
*/
|
|
39
39
|
import { rpc_action } from '../actions/action_rpc.js';
|
|
40
40
|
import { jsonrpc_errors } from '../http/jsonrpc_errors.js';
|
|
41
|
-
import {
|
|
41
|
+
import { builtin_role_specs_by_name, list_roles_with_grant_path, } from './role_schema.js';
|
|
42
42
|
import { GRANT_PATH_SELF_SERVICE } from './grant_path_schema.js';
|
|
43
43
|
import { query_create_role_grant, query_revoke_role_grant } from './role_grant_queries.js';
|
|
44
44
|
import { is_role_grant_active } from './account_schema.js';
|
|
@@ -55,7 +55,7 @@ import { ERROR_ROLE_NOT_SELF_SERVICE_ELIGIBLE, self_service_role_set_action_spec
|
|
|
55
55
|
* @throws Error at factory time if any `eligible_roles` entry is missing from `options.roles.role_specs`
|
|
56
56
|
*/
|
|
57
57
|
export const create_self_service_role_actions = (deps, options = {}) => {
|
|
58
|
-
const role_specs = options.roles?.role_specs ??
|
|
58
|
+
const role_specs = options.roles?.role_specs ?? builtin_role_specs_by_name;
|
|
59
59
|
const eligible = options.eligible_roles
|
|
60
60
|
? new Set(options.eligible_roles)
|
|
61
61
|
: new Set(list_roles_with_grant_path(role_specs, GRANT_PATH_SELF_SERVICE));
|
|
@@ -38,7 +38,7 @@ export interface SessionCookieOptions {
|
|
|
38
38
|
* - `sameSite: 'strict'` - Prevents CSRF
|
|
39
39
|
* - `httpOnly: true` - Prevents XSS access to cookie
|
|
40
40
|
*/
|
|
41
|
-
export declare const
|
|
41
|
+
export declare const session_cookie_options: SessionCookieOptions;
|
|
42
42
|
/**
|
|
43
43
|
* Configuration for a session cookie format.
|
|
44
44
|
*
|
|
@@ -31,7 +31,7 @@ const EXPIRES_AT_INTEGER_RE = /^\d+$/;
|
|
|
31
31
|
* - `sameSite: 'strict'` - Prevents CSRF
|
|
32
32
|
* - `httpOnly: true` - Prevents XSS access to cookie
|
|
33
33
|
*/
|
|
34
|
-
export const
|
|
34
|
+
export const session_cookie_options = {
|
|
35
35
|
path: '/',
|
|
36
36
|
httpOnly: true,
|
|
37
37
|
secure: true,
|