@selvajs/server 1.2.0 → 1.3.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/access/guards.d.ts +213 -0
- package/dist/access/guards.d.ts.map +1 -0
- package/dist/access/guards.js +417 -0
- package/dist/access/guards.js.map +1 -0
- package/dist/access/index.d.ts +2 -0
- package/dist/access/index.d.ts.map +1 -1
- package/dist/access/index.js +6 -0
- package/dist/access/index.js.map +1 -1
- package/dist/access/permissions-scope.d.ts +15 -0
- package/dist/access/permissions-scope.d.ts.map +1 -0
- package/dist/access/permissions-scope.js +23 -0
- package/dist/access/permissions-scope.js.map +1 -0
- package/dist/api/bodies.d.ts +104 -0
- package/dist/api/bodies.d.ts.map +1 -0
- package/dist/api/bodies.js +87 -0
- package/dist/api/bodies.js.map +1 -0
- package/dist/api/deps.d.ts +135 -0
- package/dist/api/deps.d.ts.map +1 -0
- package/dist/api/deps.js +55 -0
- package/dist/api/deps.js.map +1 -0
- package/dist/api/errors.d.ts +35 -0
- package/dist/api/errors.d.ts.map +1 -0
- package/dist/api/errors.js +63 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/index.d.ts +12 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +15 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/map-core-error.d.ts +19 -0
- package/dist/api/map-core-error.d.ts.map +1 -0
- package/dist/api/map-core-error.js +49 -0
- package/dist/api/map-core-error.js.map +1 -0
- package/dist/api/pagination.d.ts +19 -0
- package/dist/api/pagination.d.ts.map +1 -0
- package/dist/api/pagination.js +40 -0
- package/dist/api/pagination.js.map +1 -0
- package/dist/api/request.d.ts +93 -0
- package/dist/api/request.d.ts.map +1 -0
- package/dist/api/request.js +150 -0
- package/dist/api/request.js.map +1 -0
- package/dist/api/respond.d.ts +29 -0
- package/dist/api/respond.d.ts.map +1 -0
- package/dist/api/respond.js +59 -0
- package/dist/api/respond.js.map +1 -0
- package/dist/api/responses-schema.d.ts +158 -0
- package/dist/api/responses-schema.d.ts.map +1 -0
- package/dist/api/responses-schema.js +104 -0
- package/dist/api/responses-schema.js.map +1 -0
- package/dist/api/responses.d.ts +19 -0
- package/dist/api/responses.d.ts.map +1 -0
- package/dist/api/responses.js +21 -0
- package/dist/api/responses.js.map +1 -0
- package/dist/api/shaped.d.ts +23 -0
- package/dist/api/shaped.d.ts.map +1 -0
- package/dist/api/shaped.js +29 -0
- package/dist/api/shaped.js.map +1 -0
- package/dist/api/types.d.ts +41 -0
- package/dist/api/types.d.ts.map +1 -0
- package/dist/api/types.js +12 -0
- package/dist/api/types.js.map +1 -0
- package/dist/compute/errors.d.ts +18 -0
- package/dist/compute/errors.d.ts.map +1 -0
- package/dist/compute/errors.js +21 -0
- package/dist/compute/errors.js.map +1 -0
- package/dist/compute/evict-changed-servers.d.ts +22 -0
- package/dist/compute/evict-changed-servers.d.ts.map +1 -0
- package/dist/compute/evict-changed-servers.js +31 -0
- package/dist/compute/evict-changed-servers.js.map +1 -0
- package/dist/compute/idempotency-http.d.ts +47 -0
- package/dist/compute/idempotency-http.d.ts.map +1 -0
- package/dist/compute/idempotency-http.js +51 -0
- package/dist/compute/idempotency-http.js.map +1 -0
- package/dist/compute/index.d.ts +5 -0
- package/dist/compute/index.d.ts.map +1 -1
- package/dist/compute/index.js +5 -0
- package/dist/compute/index.js.map +1 -1
- package/dist/compute/resolve-server.d.ts +25 -0
- package/dist/compute/resolve-server.d.ts.map +1 -0
- package/dist/compute/resolve-server.js +35 -0
- package/dist/compute/resolve-server.js.map +1 -0
- package/dist/compute/server-config-write.d.ts +52 -0
- package/dist/compute/server-config-write.d.ts.map +1 -0
- package/dist/compute/server-config-write.js +100 -0
- package/dist/compute/server-config-write.js.map +1 -0
- package/dist/definitions/index.d.ts +1 -0
- package/dist/definitions/index.d.ts.map +1 -1
- package/dist/definitions/index.js +1 -0
- package/dist/definitions/index.js.map +1 -1
- package/dist/definitions/visibility.d.ts +74 -0
- package/dist/definitions/visibility.d.ts.map +1 -0
- package/dist/definitions/visibility.js +117 -0
- package/dist/definitions/visibility.js.map +1 -0
- package/dist/handlers/definitionVersions.d.ts +30 -0
- package/dist/handlers/definitionVersions.d.ts.map +1 -0
- package/dist/handlers/definitionVersions.js +93 -0
- package/dist/handlers/definitionVersions.js.map +1 -0
- package/dist/handlers/definitions.d.ts +35 -0
- package/dist/handlers/definitions.d.ts.map +1 -0
- package/dist/handlers/definitions.js +207 -0
- package/dist/handlers/definitions.js.map +1 -0
- package/dist/handlers/index.d.ts +27 -0
- package/dist/handlers/index.d.ts.map +1 -0
- package/dist/handlers/index.js +29 -0
- package/dist/handlers/index.js.map +1 -0
- package/dist/handlers/invite-lookup.d.ts +11 -0
- package/dist/handlers/invite-lookup.d.ts.map +1 -0
- package/dist/handlers/invite-lookup.js +20 -0
- package/dist/handlers/invite-lookup.js.map +1 -0
- package/dist/handlers/invites.d.ts +31 -0
- package/dist/handlers/invites.d.ts.map +1 -0
- package/dist/handlers/invites.js +148 -0
- package/dist/handlers/invites.js.map +1 -0
- package/dist/handlers/me.d.ts +8 -0
- package/dist/handlers/me.d.ts.map +1 -0
- package/dist/handlers/me.js +21 -0
- package/dist/handlers/me.js.map +1 -0
- package/dist/handlers/me.starred.d.ts +11 -0
- package/dist/handlers/me.starred.d.ts.map +1 -0
- package/dist/handlers/me.starred.js +21 -0
- package/dist/handlers/me.starred.js.map +1 -0
- package/dist/handlers/orgAssets.d.ts +13 -0
- package/dist/handlers/orgAssets.d.ts.map +1 -0
- package/dist/handlers/orgAssets.js +54 -0
- package/dist/handlers/orgAssets.js.map +1 -0
- package/dist/handlers/orgCompute.d.ts +16 -0
- package/dist/handlers/orgCompute.d.ts.map +1 -0
- package/dist/handlers/orgCompute.js +96 -0
- package/dist/handlers/orgCompute.js.map +1 -0
- package/dist/handlers/orgMembers.d.ts +29 -0
- package/dist/handlers/orgMembers.d.ts.map +1 -0
- package/dist/handlers/orgMembers.js +200 -0
- package/dist/handlers/orgMembers.js.map +1 -0
- package/dist/handlers/orgs.d.ts +16 -0
- package/dist/handlers/orgs.d.ts.map +1 -0
- package/dist/handlers/orgs.js +26 -0
- package/dist/handlers/orgs.js.map +1 -0
- package/dist/handlers/projectMembers.d.ts +15 -0
- package/dist/handlers/projectMembers.d.ts.map +1 -0
- package/dist/handlers/projectMembers.js +95 -0
- package/dist/handlers/projectMembers.js.map +1 -0
- package/dist/handlers/projects.d.ts +21 -0
- package/dist/handlers/projects.d.ts.map +1 -0
- package/dist/handlers/projects.js +164 -0
- package/dist/handlers/projects.js.map +1 -0
- package/dist/handlers/reclaim.d.ts +10 -0
- package/dist/handlers/reclaim.d.ts.map +1 -0
- package/dist/handlers/reclaim.js +38 -0
- package/dist/handlers/reclaim.js.map +1 -0
- package/dist/handlers/services.d.ts +22 -0
- package/dist/handlers/services.d.ts.map +1 -0
- package/dist/handlers/services.js +37 -0
- package/dist/handlers/services.js.map +1 -0
- package/dist/handlers/shareLinks.d.ts +23 -0
- package/dist/handlers/shareLinks.d.ts.map +1 -0
- package/dist/handlers/shareLinks.js +85 -0
- package/dist/handlers/shareLinks.js.map +1 -0
- package/dist/http/index.d.ts +1 -0
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +1 -0
- package/dist/http/index.js.map +1 -1
- package/dist/http/login-rate-limit.d.ts +72 -0
- package/dist/http/login-rate-limit.d.ts.map +1 -0
- package/dist/http/login-rate-limit.js +84 -0
- package/dist/http/login-rate-limit.js.map +1 -0
- package/dist/notifications/deliver-invite.d.ts +27 -0
- package/dist/notifications/deliver-invite.d.ts.map +1 -0
- package/dist/notifications/deliver-invite.js +32 -0
- package/dist/notifications/deliver-invite.js.map +1 -0
- package/dist/notifications/index.d.ts +1 -0
- package/dist/notifications/index.d.ts.map +1 -1
- package/dist/notifications/index.js +1 -0
- package/dist/notifications/index.js.map +1 -1
- package/dist/organizations/index.d.ts +3 -0
- package/dist/organizations/index.d.ts.map +1 -0
- package/dist/organizations/index.js +5 -0
- package/dist/organizations/index.js.map +1 -0
- package/dist/organizations/list-all-members.d.ts +10 -0
- package/dist/organizations/list-all-members.d.ts.map +1 -0
- package/dist/organizations/list-all-members.js +36 -0
- package/dist/organizations/list-all-members.js.map +1 -0
- package/dist/organizations/org-asset-service.d.ts +39 -0
- package/dist/organizations/org-asset-service.d.ts.map +1 -0
- package/dist/organizations/org-asset-service.js +71 -0
- package/dist/organizations/org-asset-service.js.map +1 -0
- package/dist/projects/create-project.d.ts +30 -0
- package/dist/projects/create-project.d.ts.map +1 -0
- package/dist/projects/create-project.js +56 -0
- package/dist/projects/create-project.js.map +1 -0
- package/dist/projects/index.d.ts +2 -0
- package/dist/projects/index.d.ts.map +1 -0
- package/dist/projects/index.js +3 -0
- package/dist/projects/index.js.map +1 -0
- package/dist/providers/auth-lookup.d.ts +14 -0
- package/dist/providers/auth-lookup.d.ts.map +1 -0
- package/dist/providers/auth-lookup.js +34 -0
- package/dist/providers/auth-lookup.js.map +1 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +1 -0
- package/dist/providers/index.js.map +1 -1
- package/dist/testing/harness.d.ts +168 -0
- package/dist/testing/harness.d.ts.map +1 -0
- package/dist/testing/harness.js +314 -0
- package/dist/testing/harness.js.map +1 -0
- package/dist/testing/index.d.ts +18 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +15 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/scenarios.d.ts +67 -0
- package/dist/testing/scenarios.d.ts.map +1 -0
- package/dist/testing/scenarios.js +104 -0
- package/dist/testing/scenarios.js.map +1 -0
- package/dist/testing/seed-adapter.d.ts +31 -0
- package/dist/testing/seed-adapter.d.ts.map +1 -0
- package/dist/testing/seed-adapter.js +19 -0
- package/dist/testing/seed-adapter.js.map +1 -0
- package/package.json +30 -2
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The permission guards every API handler runs before touching a store.
|
|
3
|
+
*
|
|
4
|
+
* These name no framework. A guard raises `ApiError`, which `runHandler` folds
|
|
5
|
+
* into the response envelope — so the same guard protects a SvelteKit route, a
|
|
6
|
+
* Next route handler, or a Hono route behind that host's own adapter.
|
|
7
|
+
*
|
|
8
|
+
* **Guards that redirect stay with the host.** A redirect is a browser-page
|
|
9
|
+
* concept, not an API one, and a framework implements it by throwing a value
|
|
10
|
+
* only that framework understands.
|
|
11
|
+
*
|
|
12
|
+
* A caller outside an API route — a page load, or a route that builds its own
|
|
13
|
+
* `Response` — has to convert the `ApiError` at its boundary, since a framework
|
|
14
|
+
* will not recognize it. Selva does that with `asHttpError` in
|
|
15
|
+
* `access.server.ts`; SvelteKit gives anything that is not its own `HttpError` a
|
|
16
|
+
* 500, so an unconverted guard denial reads as a crash.
|
|
17
|
+
*
|
|
18
|
+
* Providers arrive through {@link AccessDeps} rather than being resolved here.
|
|
19
|
+
* That is what keeps this module importable without booting an app: a guard
|
|
20
|
+
* that reached for a module global would drag the whole composition root — and
|
|
21
|
+
* its top-level `await createSelvaProviders()` — into every consumer.
|
|
22
|
+
*/
|
|
23
|
+
import type { AuthUser, DefinitionRecord, OrgPermission, OrgRole, PlatformPermission, Project, RequestContext, SelvaConfig } from '@selvajs/platform';
|
|
24
|
+
import { type ProjectAccessInputBuilder } from './project-access-input.js';
|
|
25
|
+
import type { SelvaDeps } from '../api/deps.js';
|
|
26
|
+
export type AnyPermission = PlatformPermission | OrgPermission;
|
|
27
|
+
/**
|
|
28
|
+
* What the permission-only guards read.
|
|
29
|
+
*
|
|
30
|
+
* `deps` is absent here on purpose: `requirePermission` and friends check
|
|
31
|
+
* `ctx.platformPermissions` and touch no store, so demanding providers from
|
|
32
|
+
* their callers — the ~20 admin routes and page loads that only ever ask "may
|
|
33
|
+
* this user do X?" — would be a cost with nothing behind it. The guards that do
|
|
34
|
+
* read stores take `HasDeps` instead, which requires them.
|
|
35
|
+
*/
|
|
36
|
+
export interface Locals {
|
|
37
|
+
user?: AuthUser;
|
|
38
|
+
ctx?: RequestContext;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* What a store-reading guard takes: identity plus the providers to read with.
|
|
42
|
+
*
|
|
43
|
+
* `ApiRequest` satisfies this structurally, so a mounted handler passes itself.
|
|
44
|
+
* Everyone else passes `scoped(locals)`.
|
|
45
|
+
*/
|
|
46
|
+
type ScopedLocals = Locals & HasDeps;
|
|
47
|
+
/**
|
|
48
|
+
* The stores a guard reads, injected rather than resolved.
|
|
49
|
+
*
|
|
50
|
+
* `ApiRequest` satisfies this structurally, so a mounted handler passes itself
|
|
51
|
+
* and the guard runs against that request's providers.
|
|
52
|
+
*
|
|
53
|
+
* **Required, not optional.** These guards used to fall back to a host's module
|
|
54
|
+
* globals when no `deps` arrived, which meant importing this file pulled in that
|
|
55
|
+
* host's composition root — in Selva a module running a top-level
|
|
56
|
+
* `await createSelvaProviders()`, so any handler importing a guard booted the
|
|
57
|
+
* whole provider stack. That is what kept these guards in the app; a caller with
|
|
58
|
+
* no `deps` in hand builds them with `accessDepsFromConfig`.
|
|
59
|
+
*/
|
|
60
|
+
export type AccessDeps = Pick<SelvaDeps, 'orgs' | 'projects' | 'definitionMeta' | 'platformProjectGrants' | 'flag'>;
|
|
61
|
+
interface HasDeps {
|
|
62
|
+
deps: AccessDeps;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Derive the stores a guard needs from a resolved config.
|
|
66
|
+
*
|
|
67
|
+
* Pure — it reads the config it is handed and nothing else, which is what keeps
|
|
68
|
+
* this module free of any import that boots the app. Page loads pass
|
|
69
|
+
* `locals.providers`; `hooks.server.ts` sets it on every request.
|
|
70
|
+
*/
|
|
71
|
+
export declare function accessDepsFromConfig(config: SelvaConfig): AccessDeps;
|
|
72
|
+
/** `locals` as a store-reading guard wants it. */
|
|
73
|
+
export declare function scoped<L extends Locals & {
|
|
74
|
+
providers: SelvaConfig;
|
|
75
|
+
}>(locals: L): L & {
|
|
76
|
+
deps: AccessDeps;
|
|
77
|
+
};
|
|
78
|
+
export declare function requireAuthed(locals: Locals): {
|
|
79
|
+
user: AuthUser;
|
|
80
|
+
ctx: RequestContext;
|
|
81
|
+
};
|
|
82
|
+
/** Throws 403 — use in API routes. */
|
|
83
|
+
export declare function requirePermission(locals: Locals, permission: AnyPermission): AuthUser;
|
|
84
|
+
export declare const requireManageInstanceUsers: (locals: Locals) => AuthUser;
|
|
85
|
+
export declare const requireManageCompute: (locals: Locals) => AuthUser;
|
|
86
|
+
export declare const requireManageOrgMembers: (locals: Locals) => AuthUser;
|
|
87
|
+
export declare const requireManageOrgCompute: (locals: Locals) => AuthUser;
|
|
88
|
+
export declare const requireInstanceAdmin: (locals: Locals) => AuthUser;
|
|
89
|
+
/**
|
|
90
|
+
* Platform scope is not delegable: `manage_instance_users` runs the user-admin
|
|
91
|
+
* surface but must not be able to mint an `instance_admin`, or an org admin
|
|
92
|
+
* holding it self-elevates. Three routes write platform permissions — the two
|
|
93
|
+
* `/api/admin/users` handlers and the invite mint route — and each carried its
|
|
94
|
+
* own copy of this check.
|
|
95
|
+
*
|
|
96
|
+
* Pass `current` on an update. Revoking is a platform-scope change too, so a
|
|
97
|
+
* PATCH that drops `instance_admin` is refused for the same reason granting it
|
|
98
|
+
* is; without `current` the caller is creating (a user, an invite) and there is
|
|
99
|
+
* nothing to compare against.
|
|
100
|
+
*
|
|
101
|
+
* Requesting nothing on a create is always allowed — that is a
|
|
102
|
+
* `manage_instance_users` operation, not a platform-scope one.
|
|
103
|
+
*/
|
|
104
|
+
export declare function assertCanGrantPlatformPermissions(ctx: RequestContext, requested: readonly PlatformPermission[], current?: readonly PlatformPermission[]): void;
|
|
105
|
+
/**
|
|
106
|
+
* Tenancy gate for `/api/v1/orgs/{orgId}/…`. The URL id is never trusted alone
|
|
107
|
+
* — the acting context decides which tenant a request applies to, so a
|
|
108
|
+
* mismatch is 403 rather than a silent read of the caller's own org.
|
|
109
|
+
*/
|
|
110
|
+
export declare function requireActingOrg(locals: Locals, orgId: string | undefined): {
|
|
111
|
+
ctx: RequestContext;
|
|
112
|
+
orgId: string;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Assemble a rule input from rows the caller already loaded.
|
|
116
|
+
*
|
|
117
|
+
* Unlike the other builders this one issues no reads — the caller batched them.
|
|
118
|
+
* It still needs `deps` for the flag lookups, which decide whether a
|
|
119
|
+
* cross-org-public or platform project is visible at all.
|
|
120
|
+
*/
|
|
121
|
+
export declare function projectAccessInputFromRowsWith(src: HasDeps, ...args: Parameters<ProjectAccessInputBuilder['projectAccessInputFromRows']>): import("@selvajs/platform").ProjectAccessInput;
|
|
122
|
+
/**
|
|
123
|
+
* Gates creation of a *new* definition. Container projects require project
|
|
124
|
+
* owner/editor (canEdit). Commons projects (`autoJoinOnUpload=true`) accept
|
|
125
|
+
* any authenticated user — the handler stamps `ownerId = user.id` so the
|
|
126
|
+
* uploader becomes the owner.
|
|
127
|
+
*/
|
|
128
|
+
export declare function requireCanCreateDefinition(locals: ScopedLocals, projectId: string): Promise<{
|
|
129
|
+
user: AuthUser;
|
|
130
|
+
ctx: RequestContext;
|
|
131
|
+
project: Project;
|
|
132
|
+
}>;
|
|
133
|
+
/**
|
|
134
|
+
* Org-content gate — the caller must be a member of `orgId`. Used by the
|
|
135
|
+
* file-serving proxy for org-private assets (e.g. pricing sheets under
|
|
136
|
+
* `orgs/{id}/private/*`). Org membership is the only rule; runs through
|
|
137
|
+
* `contentCheck` (no `instance_admin` bypass) — platform staff use Reclaim
|
|
138
|
+
* if they need access without membership.
|
|
139
|
+
*
|
|
140
|
+
* Throws 401 unauthenticated, 403 when not a member.
|
|
141
|
+
*/
|
|
142
|
+
export declare function requireCanViewOrg(locals: ScopedLocals, orgId: string): Promise<AuthUser>;
|
|
143
|
+
/**
|
|
144
|
+
* Project members must belong to the project's parent org. Enforced at the
|
|
145
|
+
* rule layer, not as a DB constraint, to leave room for cross-org guests
|
|
146
|
+
* later without a schema migration.
|
|
147
|
+
*/
|
|
148
|
+
export declare function requireTargetIsOrgMember(locals: ScopedLocals, orgId: string, targetUserId: string): Promise<void>;
|
|
149
|
+
/**
|
|
150
|
+
* `canChangeOrgRole` with the actor's membership row loaded — whether the
|
|
151
|
+
* caller may grant or revoke org `owner`/`admin` standing (§3).
|
|
152
|
+
*
|
|
153
|
+
* Returns rather than throws: the three callers each phrase the refusal for
|
|
154
|
+
* what they were doing ("invite someone as owner", "change roles", "remove
|
|
155
|
+
* another owner") and raise it through `apiError`. What must not diverge is the
|
|
156
|
+
* decision, which is why that half lives in `rules.ts` and this loads its input.
|
|
157
|
+
*/
|
|
158
|
+
export declare function canActorChangeOrgRole(ctx: RequestContext, orgId: string, role: OrgRole, src: HasDeps): Promise<boolean>;
|
|
159
|
+
/**
|
|
160
|
+
* `canReclaim` — org owner/admin escape hatch. Returns the project so the
|
|
161
|
+
* handler can use its `orgId` without re-fetching.
|
|
162
|
+
*/
|
|
163
|
+
export declare function requireCanReclaim(locals: ScopedLocals, projectId: string): Promise<{
|
|
164
|
+
user: AuthUser;
|
|
165
|
+
ctx: RequestContext;
|
|
166
|
+
project: Project;
|
|
167
|
+
}>;
|
|
168
|
+
/**
|
|
169
|
+
* `canCreateProject` — owner/admin always; member needs `manage_projects`.
|
|
170
|
+
* Tenancy is enforced via `actingOrgId`.
|
|
171
|
+
*/
|
|
172
|
+
export declare function requireCanCreateProject(locals: ScopedLocals, targetOrgId: string): Promise<{
|
|
173
|
+
user: AuthUser;
|
|
174
|
+
ctx: RequestContext;
|
|
175
|
+
}>;
|
|
176
|
+
/**
|
|
177
|
+
* Project-management gate (`canManage` — owner, or `instance_admin` via the
|
|
178
|
+
* bypass). Managing members is the same authority as managing the project, so
|
|
179
|
+
* both callers share this; `action` only shapes the 403 message.
|
|
180
|
+
*/
|
|
181
|
+
export declare function requireCanManage(locals: ScopedLocals, projectId: string, action?: 'project' | 'members'): Promise<AuthUser>;
|
|
182
|
+
export declare function requireCanEditProjectSettings(locals: ScopedLocals, projectId: string): Promise<{
|
|
183
|
+
user: AuthUser;
|
|
184
|
+
ctx: RequestContext;
|
|
185
|
+
project: Project;
|
|
186
|
+
}>;
|
|
187
|
+
export declare function requireCanViewProject(locals: ScopedLocals, projectId: string): Promise<AuthUser>;
|
|
188
|
+
/**
|
|
189
|
+
* Solve gating. Today `canSolve === canView` for non-platform projects, but
|
|
190
|
+
* the rule lives in its own function so future cost-gating (quotas, rate
|
|
191
|
+
* limits) lands without touching view semantics. `viewer` project role
|
|
192
|
+
* passes; platform projects narrow to grants with `canSolve=true`.
|
|
193
|
+
*/
|
|
194
|
+
export declare function requireCanSolve(locals: ScopedLocals, projectId: string, preloadedProject?: Project): Promise<{
|
|
195
|
+
user: AuthUser;
|
|
196
|
+
ctx: RequestContext;
|
|
197
|
+
project: Project;
|
|
198
|
+
}>;
|
|
199
|
+
/**
|
|
200
|
+
* Loads the record and gates editing. Returns the record AND the project it
|
|
201
|
+
* loads for the gate, so callers skip a re-fetch of either.
|
|
202
|
+
*/
|
|
203
|
+
export declare function requireEditableDefinition(locals: ScopedLocals, guid: string): Promise<{
|
|
204
|
+
record: DefinitionRecord;
|
|
205
|
+
ctx: RequestContext;
|
|
206
|
+
project: Project | null;
|
|
207
|
+
}>;
|
|
208
|
+
export declare function requireCanEditDefinition(locals: ScopedLocals, projectId: string, definitionGuid: string, preloaded?: {
|
|
209
|
+
project?: Project | null;
|
|
210
|
+
definition?: DefinitionRecord | null;
|
|
211
|
+
}): Promise<AuthUser>;
|
|
212
|
+
export {};
|
|
213
|
+
//# sourceMappingURL=guards.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.d.ts","sourceRoot":"","sources":["../../src/access/guards.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,417 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The permission guards every API handler runs before touching a store.
|
|
3
|
+
*
|
|
4
|
+
* These name no framework. A guard raises `ApiError`, which `runHandler` folds
|
|
5
|
+
* into the response envelope — so the same guard protects a SvelteKit route, a
|
|
6
|
+
* Next route handler, or a Hono route behind that host's own adapter.
|
|
7
|
+
*
|
|
8
|
+
* **Guards that redirect stay with the host.** A redirect is a browser-page
|
|
9
|
+
* concept, not an API one, and a framework implements it by throwing a value
|
|
10
|
+
* only that framework understands.
|
|
11
|
+
*
|
|
12
|
+
* A caller outside an API route — a page load, or a route that builds its own
|
|
13
|
+
* `Response` — has to convert the `ApiError` at its boundary, since a framework
|
|
14
|
+
* will not recognize it. Selva does that with `asHttpError` in
|
|
15
|
+
* `access.server.ts`; SvelteKit gives anything that is not its own `HttpError` a
|
|
16
|
+
* 500, so an unconverted guard denial reads as a crash.
|
|
17
|
+
*
|
|
18
|
+
* Providers arrive through {@link AccessDeps} rather than being resolved here.
|
|
19
|
+
* That is what keeps this module importable without booting an app: a guard
|
|
20
|
+
* that reached for a module global would drag the whole composition root — and
|
|
21
|
+
* its top-level `await createSelvaProviders()` — into every consumer.
|
|
22
|
+
*/
|
|
23
|
+
import { isFlagEnabled, hasPermission, canReclaim, canCreateProject, canChangeOrgRole, canView, canSolve, canEdit, canManage, canEditProjectSettings, canEditDefinition } from '@selvajs/platform';
|
|
24
|
+
import { createProjectAccessInputBuilder } from './project-access-input.js';
|
|
25
|
+
import { apiError, ApiErrorCode } from '../api/errors.js';
|
|
26
|
+
/**
|
|
27
|
+
* Derive the stores a guard needs from a resolved config.
|
|
28
|
+
*
|
|
29
|
+
* Pure — it reads the config it is handed and nothing else, which is what keeps
|
|
30
|
+
* this module free of any import that boots the app. Page loads pass
|
|
31
|
+
* `locals.providers`; `hooks.server.ts` sets it on every request.
|
|
32
|
+
*/
|
|
33
|
+
export function accessDepsFromConfig(config) {
|
|
34
|
+
return {
|
|
35
|
+
orgs: config.data.orgs,
|
|
36
|
+
projects: config.data.projects,
|
|
37
|
+
definitionMeta: config.data.definitions,
|
|
38
|
+
platformProjectGrants: config.data.platformProjectGrants,
|
|
39
|
+
flag: (name) => isFlagEnabled(config, name)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/** `locals` as a store-reading guard wants it. */
|
|
43
|
+
export function scoped(locals) {
|
|
44
|
+
return { ...locals, deps: accessDepsFromConfig(locals.providers) };
|
|
45
|
+
}
|
|
46
|
+
// Accessors rather than `src.deps.orgs` inline: they keep the 17 call sites
|
|
47
|
+
// below reading the same as before, and they are the single place that would
|
|
48
|
+
// change if `AccessDeps` grew a store.
|
|
49
|
+
const orgsOf = (src) => src.deps.orgs;
|
|
50
|
+
const projectsOf = (src) => src.deps.projects;
|
|
51
|
+
const definitionMetaOf = (src) => src.deps.definitionMeta;
|
|
52
|
+
const flagOf = (src) => src.deps.flag;
|
|
53
|
+
export function requireAuthed(locals) {
|
|
54
|
+
const { user, ctx } = locals;
|
|
55
|
+
if (!user || !ctx)
|
|
56
|
+
apiError(401, ApiErrorCode.UNAUTHORIZED, 'Unauthorized');
|
|
57
|
+
return { user, ctx };
|
|
58
|
+
}
|
|
59
|
+
/** Throws 403 — use in API routes. */
|
|
60
|
+
export function requirePermission(locals, permission) {
|
|
61
|
+
const { user, ctx } = requireAuthed(locals);
|
|
62
|
+
if (!hasPermission(ctx, permission)) {
|
|
63
|
+
apiError(403, ApiErrorCode.FORBIDDEN, `You don't have permission to do this.`);
|
|
64
|
+
}
|
|
65
|
+
return user;
|
|
66
|
+
}
|
|
67
|
+
// Named aliases exist only for permissions with real call sites. Routes gating
|
|
68
|
+
// on anything else call `requirePermission(locals, '…')` directly rather than
|
|
69
|
+
// growing an alias per permission — `manage_definitions` and `manage_projects`
|
|
70
|
+
// had wrappers that nothing ever called.
|
|
71
|
+
export const requireManageInstanceUsers = (locals) => requirePermission(locals, 'manage_instance_users');
|
|
72
|
+
export const requireManageCompute = (locals) => requirePermission(locals, 'manage_compute');
|
|
73
|
+
export const requireManageOrgMembers = (locals) => requirePermission(locals, 'manage_org_members');
|
|
74
|
+
export const requireManageOrgCompute = (locals) => requirePermission(locals, 'manage_org_compute');
|
|
75
|
+
export const requireInstanceAdmin = (locals) => requirePermission(locals, 'instance_admin');
|
|
76
|
+
/**
|
|
77
|
+
* Platform scope is not delegable: `manage_instance_users` runs the user-admin
|
|
78
|
+
* surface but must not be able to mint an `instance_admin`, or an org admin
|
|
79
|
+
* holding it self-elevates. Three routes write platform permissions — the two
|
|
80
|
+
* `/api/admin/users` handlers and the invite mint route — and each carried its
|
|
81
|
+
* own copy of this check.
|
|
82
|
+
*
|
|
83
|
+
* Pass `current` on an update. Revoking is a platform-scope change too, so a
|
|
84
|
+
* PATCH that drops `instance_admin` is refused for the same reason granting it
|
|
85
|
+
* is; without `current` the caller is creating (a user, an invite) and there is
|
|
86
|
+
* nothing to compare against.
|
|
87
|
+
*
|
|
88
|
+
* Requesting nothing on a create is always allowed — that is a
|
|
89
|
+
* `manage_instance_users` operation, not a platform-scope one.
|
|
90
|
+
*/
|
|
91
|
+
export function assertCanGrantPlatformPermissions(ctx, requested, current) {
|
|
92
|
+
const changed = current
|
|
93
|
+
? requested.length !== current.length ||
|
|
94
|
+
requested.some((p) => !current.includes(p)) ||
|
|
95
|
+
current.some((p) => !requested.includes(p))
|
|
96
|
+
: requested.length > 0;
|
|
97
|
+
if (!changed)
|
|
98
|
+
return;
|
|
99
|
+
if (hasPermission(ctx, 'instance_admin'))
|
|
100
|
+
return;
|
|
101
|
+
apiError(403, ApiErrorCode.FORBIDDEN, current
|
|
102
|
+
? 'Only a platform admin can change platform-scope permissions'
|
|
103
|
+
: 'Only a platform admin can grant platform-scope permissions');
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Tenancy gate for `/api/v1/orgs/{orgId}/…`. The URL id is never trusted alone
|
|
107
|
+
* — the acting context decides which tenant a request applies to, so a
|
|
108
|
+
* mismatch is 403 rather than a silent read of the caller's own org.
|
|
109
|
+
*/
|
|
110
|
+
export function requireActingOrg(locals, orgId) {
|
|
111
|
+
const ctx = locals.ctx;
|
|
112
|
+
if (!ctx)
|
|
113
|
+
apiError(401, ApiErrorCode.UNAUTHORIZED, 'Unauthorized');
|
|
114
|
+
if (!orgId)
|
|
115
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, 'Missing org ID');
|
|
116
|
+
if (!ctx.actingOrgId)
|
|
117
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, 'No active organization');
|
|
118
|
+
if (ctx.actingOrgId !== orgId) {
|
|
119
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Acting org does not match the target org.');
|
|
120
|
+
}
|
|
121
|
+
return { ctx, orgId };
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Gate for pages reachable by any platform-class permission holder (the
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Management-scope bypass — used for org governance and project management
|
|
128
|
+
* actions (Reclaim, create project, delete project, manage members, edit
|
|
129
|
+
* settings). `instance_admin` bypasses these so platform staff can administer
|
|
130
|
+
* the instance without being a member of every org.
|
|
131
|
+
*
|
|
132
|
+
* NOT used for content access (view, solve, edit definitions):
|
|
133
|
+
* `instance_admin` follows the same `canView`/`canEdit` rules as any other
|
|
134
|
+
* user there, keeping blast radius small and forcing content escalation
|
|
135
|
+
* through Reclaim, which leaves an audit trail.
|
|
136
|
+
*/
|
|
137
|
+
async function managementBypassOrRun(ctx, check) {
|
|
138
|
+
if (hasPermission(ctx, 'instance_admin'))
|
|
139
|
+
return true;
|
|
140
|
+
return await check();
|
|
141
|
+
}
|
|
142
|
+
// Content-scope check — NO `instance_admin` bypass. `canView`, `canSolve`,
|
|
143
|
+
// `canEdit`, and `canEditDefinition` run as-is regardless of platform role;
|
|
144
|
+
// platform staff use Reclaim first if they need content access.
|
|
145
|
+
async function contentCheck(check) {
|
|
146
|
+
return await check();
|
|
147
|
+
}
|
|
148
|
+
async function loadProjectOr404(ctx, projectId, src) {
|
|
149
|
+
const project = await projectsOf(src).getProject(ctx, projectId);
|
|
150
|
+
if (!project)
|
|
151
|
+
apiError(404, ApiErrorCode.NOT_FOUND, 'Project not found');
|
|
152
|
+
return project;
|
|
153
|
+
}
|
|
154
|
+
// Rule-input assembly (the "which rows does each visibility need" knowledge)
|
|
155
|
+
// lives in `@selvajs/server/access`; this binding wires it to the provider set
|
|
156
|
+
// the caller carries.
|
|
157
|
+
function accessInputsFor(src) {
|
|
158
|
+
const readFlag = flagOf(src);
|
|
159
|
+
return createProjectAccessInputBuilder({
|
|
160
|
+
getProjectMember: (ctx, projectId, userId) => projectsOf(src).getProjectMember(ctx, projectId, userId),
|
|
161
|
+
getOrgMember: (ctx, orgId, userId) => orgsOf(src).getOrgMember(ctx, orgId, userId),
|
|
162
|
+
listPlatformGrants: (ctx, projectId) => src.deps.platformProjectGrants.listByProject(ctx, projectId),
|
|
163
|
+
flags: () => ({
|
|
164
|
+
allowCrossOrgPublic: readFlag('ALLOW_CROSS_ORG_PUBLIC'),
|
|
165
|
+
enablePlatformProjects: readFlag('ENABLE_PLATFORM_PROJECTS')
|
|
166
|
+
})
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function buildProjectAccessInput(ctx, project, src, overrides) {
|
|
170
|
+
return accessInputsFor(src).buildProjectAccessInput(ctx, project, overrides);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Assemble a rule input from rows the caller already loaded.
|
|
174
|
+
*
|
|
175
|
+
* Unlike the other builders this one issues no reads — the caller batched them.
|
|
176
|
+
* It still needs `deps` for the flag lookups, which decide whether a
|
|
177
|
+
* cross-org-public or platform project is visible at all.
|
|
178
|
+
*/
|
|
179
|
+
export function projectAccessInputFromRowsWith(src, ...args) {
|
|
180
|
+
return accessInputsFor(src).projectAccessInputFromRows(...args);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Gates creation of a *new* definition. Container projects require project
|
|
184
|
+
* owner/editor (canEdit). Commons projects (`autoJoinOnUpload=true`) accept
|
|
185
|
+
* any authenticated user — the handler stamps `ownerId = user.id` so the
|
|
186
|
+
* uploader becomes the owner.
|
|
187
|
+
*/
|
|
188
|
+
export async function requireCanCreateDefinition(locals, projectId) {
|
|
189
|
+
const { user, ctx } = requireAuthed(locals);
|
|
190
|
+
const project = await loadProjectOr404(ctx, projectId, locals);
|
|
191
|
+
const allowed = await contentCheck(async () => {
|
|
192
|
+
if (project.autoJoinOnUpload)
|
|
193
|
+
return true;
|
|
194
|
+
return canEdit(await buildProjectAccessInput(ctx, project, locals));
|
|
195
|
+
});
|
|
196
|
+
if (!allowed) {
|
|
197
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have permission to upload definitions to this project.');
|
|
198
|
+
}
|
|
199
|
+
return { user, ctx, project };
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Org-content gate — the caller must be a member of `orgId`. Used by the
|
|
203
|
+
* file-serving proxy for org-private assets (e.g. pricing sheets under
|
|
204
|
+
* `orgs/{id}/private/*`). Org membership is the only rule; runs through
|
|
205
|
+
* `contentCheck` (no `instance_admin` bypass) — platform staff use Reclaim
|
|
206
|
+
* if they need access without membership.
|
|
207
|
+
*
|
|
208
|
+
* Throws 401 unauthenticated, 403 when not a member.
|
|
209
|
+
*/
|
|
210
|
+
export async function requireCanViewOrg(locals, orgId) {
|
|
211
|
+
const { user, ctx } = requireAuthed(locals);
|
|
212
|
+
const allowed = await contentCheck(async () => {
|
|
213
|
+
const member = await orgsOf(locals).getOrgMember(ctx, orgId, ctx.userId);
|
|
214
|
+
return member !== null;
|
|
215
|
+
});
|
|
216
|
+
if (!allowed)
|
|
217
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have access to this organization.');
|
|
218
|
+
return user;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Project members must belong to the project's parent org. Enforced at the
|
|
222
|
+
* rule layer, not as a DB constraint, to leave room for cross-org guests
|
|
223
|
+
* later without a schema migration.
|
|
224
|
+
*/
|
|
225
|
+
export async function requireTargetIsOrgMember(locals, orgId, targetUserId) {
|
|
226
|
+
const { ctx } = requireAuthed(locals);
|
|
227
|
+
const member = await orgsOf(locals).getOrgMember(ctx, orgId, targetUserId);
|
|
228
|
+
if (!member) {
|
|
229
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, 'User must be a member of this organization to be added to a project.');
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* `canChangeOrgRole` with the actor's membership row loaded — whether the
|
|
234
|
+
* caller may grant or revoke org `owner`/`admin` standing (§3).
|
|
235
|
+
*
|
|
236
|
+
* Returns rather than throws: the three callers each phrase the refusal for
|
|
237
|
+
* what they were doing ("invite someone as owner", "change roles", "remove
|
|
238
|
+
* another owner") and raise it through `apiError`. What must not diverge is the
|
|
239
|
+
* decision, which is why that half lives in `rules.ts` and this loads its input.
|
|
240
|
+
*/
|
|
241
|
+
export async function canActorChangeOrgRole(ctx, orgId, role, src) {
|
|
242
|
+
if (role === 'member')
|
|
243
|
+
return true;
|
|
244
|
+
const actorMember = await orgsOf(src).getOrgMember(ctx, orgId, ctx.userId);
|
|
245
|
+
return canChangeOrgRole({ actorMember, role });
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* `canReclaim` — org owner/admin escape hatch. Returns the project so the
|
|
249
|
+
* handler can use its `orgId` without re-fetching.
|
|
250
|
+
*/
|
|
251
|
+
export async function requireCanReclaim(locals, projectId) {
|
|
252
|
+
const { user, ctx } = requireAuthed(locals);
|
|
253
|
+
const project = await loadProjectOr404(ctx, projectId, locals);
|
|
254
|
+
// Ahead of the bypass, not inside the check: `instance_admin` short-circuits
|
|
255
|
+
// `managementBypassOrRun`, so `canReclaim`'s platform-project refusal (§4a)
|
|
256
|
+
// never ran for the one role that could reach it. Reclaim is content
|
|
257
|
+
// escalation wearing management clothing — the management bypass is not its
|
|
258
|
+
// to inherit.
|
|
259
|
+
if (project.visibility === 'platform') {
|
|
260
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Platform projects cannot be reclaimed.');
|
|
261
|
+
}
|
|
262
|
+
const allowed = await managementBypassOrRun(ctx, async () => {
|
|
263
|
+
const orgMember = await orgsOf(locals).getOrgMember(ctx, project.orgId, ctx.userId);
|
|
264
|
+
return canReclaim({
|
|
265
|
+
project,
|
|
266
|
+
orgMember,
|
|
267
|
+
actingOrgId: ctx.actingOrgId ?? null
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
if (!allowed) {
|
|
271
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Only org owners or admins of this project’s org can reclaim it.');
|
|
272
|
+
}
|
|
273
|
+
return { user, ctx, project };
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* `canCreateProject` — owner/admin always; member needs `manage_projects`.
|
|
277
|
+
* Tenancy is enforced via `actingOrgId`.
|
|
278
|
+
*/
|
|
279
|
+
export async function requireCanCreateProject(locals, targetOrgId) {
|
|
280
|
+
const { user, ctx } = requireAuthed(locals);
|
|
281
|
+
const allowed = await managementBypassOrRun(ctx, async () => {
|
|
282
|
+
const orgMember = await orgsOf(locals).getOrgMember(ctx, targetOrgId, ctx.userId);
|
|
283
|
+
return canCreateProject({
|
|
284
|
+
orgPermissions: ctx.orgPermissions,
|
|
285
|
+
orgMember,
|
|
286
|
+
actingOrgId: ctx.actingOrgId ?? null,
|
|
287
|
+
targetOrgId
|
|
288
|
+
});
|
|
289
|
+
});
|
|
290
|
+
if (!allowed)
|
|
291
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have permission to create projects in this org.');
|
|
292
|
+
return { user, ctx };
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Project-management gate (`canManage` — owner, or `instance_admin` via the
|
|
296
|
+
* bypass). Managing members is the same authority as managing the project, so
|
|
297
|
+
* both callers share this; `action` only shapes the 403 message.
|
|
298
|
+
*/
|
|
299
|
+
export async function requireCanManage(locals, projectId, action = 'project') {
|
|
300
|
+
const { user, ctx } = requireAuthed(locals);
|
|
301
|
+
const allowed = await managementBypassOrRun(ctx, async () => {
|
|
302
|
+
const project = await loadProjectOr404(ctx, projectId, locals);
|
|
303
|
+
return canManage(await buildProjectAccessInput(ctx, project, locals));
|
|
304
|
+
});
|
|
305
|
+
if (!allowed) {
|
|
306
|
+
apiError(403, ApiErrorCode.FORBIDDEN, action === 'members'
|
|
307
|
+
? 'Only project owners can manage members.'
|
|
308
|
+
: 'Only project owners can manage this project.');
|
|
309
|
+
}
|
|
310
|
+
return user;
|
|
311
|
+
}
|
|
312
|
+
// Owner-only gate for project settings, centralized so PATCH
|
|
313
|
+
// /api/projects/[id] matches the rest of the access layer.
|
|
314
|
+
export async function requireCanEditProjectSettings(locals, projectId) {
|
|
315
|
+
const { user, ctx } = requireAuthed(locals);
|
|
316
|
+
const project = await loadProjectOr404(ctx, projectId, locals);
|
|
317
|
+
const allowed = await managementBypassOrRun(ctx, async () => canEditProjectSettings(await buildProjectAccessInput(ctx, project, locals)));
|
|
318
|
+
if (!allowed)
|
|
319
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Only project owners can edit project settings.');
|
|
320
|
+
return { user, ctx, project };
|
|
321
|
+
}
|
|
322
|
+
export async function requireCanViewProject(locals, projectId) {
|
|
323
|
+
const { user, ctx } = requireAuthed(locals);
|
|
324
|
+
const allowed = await contentCheck(async () => {
|
|
325
|
+
const project = await loadProjectOr404(ctx, projectId, locals);
|
|
326
|
+
return canView(await buildProjectAccessInput(ctx, project, locals));
|
|
327
|
+
});
|
|
328
|
+
if (!allowed)
|
|
329
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have access to this project.');
|
|
330
|
+
return user;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Solve gating. Today `canSolve === canView` for non-platform projects, but
|
|
334
|
+
* the rule lives in its own function so future cost-gating (quotas, rate
|
|
335
|
+
* limits) lands without touching view semantics. `viewer` project role
|
|
336
|
+
* passes; platform projects narrow to grants with `canSolve=true`.
|
|
337
|
+
*/
|
|
338
|
+
export async function requireCanSolve(locals, projectId,
|
|
339
|
+
// Callers that already loaded the project (e.g. the solve endpoint, which
|
|
340
|
+
// reads orgId/pin off it) pass it to skip a redundant `getProject` here.
|
|
341
|
+
preloadedProject) {
|
|
342
|
+
const { user, ctx } = requireAuthed(locals);
|
|
343
|
+
const project = preloadedProject ?? (await loadProjectOr404(ctx, projectId, locals));
|
|
344
|
+
const allowed = await contentCheck(async () => canSolve(await buildProjectAccessInput(ctx, project, locals)));
|
|
345
|
+
if (!allowed)
|
|
346
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have access to this project.');
|
|
347
|
+
return { user, ctx, project };
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Org membership for the commons branch of `canEditDefinition`, or `null` when
|
|
351
|
+
* that branch cannot fire. Skipping the round-trip on container projects keeps
|
|
352
|
+
* the common edit path at the same two reads it had before commons gained the
|
|
353
|
+
* membership test.
|
|
354
|
+
*/
|
|
355
|
+
async function loadCommonsOrgMember(ctx, project, src) {
|
|
356
|
+
if (!project?.autoJoinOnUpload)
|
|
357
|
+
return null;
|
|
358
|
+
return await orgsOf(src).getOrgMember(ctx, project.orgId, ctx.userId);
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Loads the record and gates editing. Returns the record AND the project it
|
|
362
|
+
* loads for the gate, so callers skip a re-fetch of either.
|
|
363
|
+
*/
|
|
364
|
+
export async function requireEditableDefinition(locals, guid) {
|
|
365
|
+
const { ctx } = requireAuthed(locals);
|
|
366
|
+
const record = await definitionMetaOf(locals).get(ctx, guid);
|
|
367
|
+
if (!record)
|
|
368
|
+
apiError(404, ApiErrorCode.NOT_FOUND, 'Definition not found');
|
|
369
|
+
// Load project + member once up front; `project` is returned for reuse.
|
|
370
|
+
const [project, member] = await Promise.all([
|
|
371
|
+
projectsOf(locals).getProject(ctx, record.projectId),
|
|
372
|
+
projectsOf(locals).getProjectMember(ctx, record.projectId, ctx.userId)
|
|
373
|
+
]);
|
|
374
|
+
const allowed = await contentCheck(async () => canEditDefinition({
|
|
375
|
+
project,
|
|
376
|
+
definition: record,
|
|
377
|
+
member,
|
|
378
|
+
orgMember: await loadCommonsOrgMember(ctx, project, locals),
|
|
379
|
+
userId: ctx.userId,
|
|
380
|
+
platformPermissions: ctx.platformPermissions,
|
|
381
|
+
enablePlatformProjects: flagOf(locals)('ENABLE_PLATFORM_PROJECTS')
|
|
382
|
+
}));
|
|
383
|
+
if (!allowed)
|
|
384
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have permission to edit this definition.');
|
|
385
|
+
return { record, ctx, project };
|
|
386
|
+
}
|
|
387
|
+
export async function requireCanEditDefinition(locals, projectId, definitionGuid,
|
|
388
|
+
// Callers that already loaded the project and/or definition (e.g. the solve
|
|
389
|
+
// endpoint) pass them to skip the redundant fetches inside the gate. The
|
|
390
|
+
// member row still loads here (the caller doesn't have it).
|
|
391
|
+
preloaded) {
|
|
392
|
+
const { user, ctx } = requireAuthed(locals);
|
|
393
|
+
const allowed = await contentCheck(async () => {
|
|
394
|
+
const [project, definition, member] = await Promise.all([
|
|
395
|
+
preloaded?.project !== undefined
|
|
396
|
+
? Promise.resolve(preloaded.project)
|
|
397
|
+
: projectsOf(locals).getProject(ctx, projectId),
|
|
398
|
+
preloaded?.definition !== undefined
|
|
399
|
+
? Promise.resolve(preloaded.definition)
|
|
400
|
+
: definitionMetaOf(locals).get(ctx, definitionGuid),
|
|
401
|
+
projectsOf(locals).getProjectMember(ctx, projectId, ctx.userId)
|
|
402
|
+
]);
|
|
403
|
+
return canEditDefinition({
|
|
404
|
+
project,
|
|
405
|
+
definition,
|
|
406
|
+
member,
|
|
407
|
+
orgMember: await loadCommonsOrgMember(ctx, project, locals),
|
|
408
|
+
userId: ctx.userId,
|
|
409
|
+
platformPermissions: ctx.platformPermissions,
|
|
410
|
+
enablePlatformProjects: flagOf(locals)('ENABLE_PLATFORM_PROJECTS')
|
|
411
|
+
});
|
|
412
|
+
});
|
|
413
|
+
if (!allowed)
|
|
414
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You do not have permission to edit this definition.');
|
|
415
|
+
return user;
|
|
416
|
+
}
|
|
417
|
+
//# sourceMappingURL=guards.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/access/guards.ts"],"names":[],"mappings":"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"}
|
package/dist/access/index.d.ts
CHANGED
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { createProjectAccessInputBuilder, type ProjectAccessFlags, type ProjectAccessInputBuilder, type ProjectAccessInputDeps } from './project-access-input.js';
|
|
2
|
+
export * from './guards.js';
|
|
3
|
+
export { splitFlatPermissions, type SplitPermissions } from './permissions-scope.js';
|
|
2
4
|
//# sourceMappingURL=index.d.ts.map
|