@selvajs/server 1.5.0-beta.8 → 2.0.0-beta.15
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 +0 -10
- package/dist/access/guards.d.ts.map +1 -1
- package/dist/access/guards.js +23 -26
- package/dist/access/guards.js.map +1 -1
- package/dist/api/idempotency.d.ts +10 -3
- package/dist/api/idempotency.d.ts.map +1 -1
- package/dist/api/idempotency.js +32 -9
- package/dist/api/idempotency.js.map +1 -1
- package/dist/api/index.d.ts +2 -2
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +2 -2
- package/dist/api/index.js.map +1 -1
- package/dist/api/request.d.ts +12 -4
- package/dist/api/request.d.ts.map +1 -1
- package/dist/api/request.js +32 -5
- package/dist/api/request.js.map +1 -1
- package/dist/api/scope.d.ts +7 -0
- package/dist/api/scope.d.ts.map +1 -1
- package/dist/api/scope.js +15 -1
- package/dist/api/scope.js.map +1 -1
- package/dist/compute/idempotency.d.ts +8 -1
- package/dist/compute/idempotency.d.ts.map +1 -1
- package/dist/compute/idempotency.js +35 -5
- package/dist/compute/idempotency.js.map +1 -1
- package/dist/compute/index.d.ts +1 -1
- package/dist/compute/index.d.ts.map +1 -1
- package/dist/compute/index.js +1 -1
- package/dist/compute/index.js.map +1 -1
- package/dist/compute/limits.d.ts +0 -7
- package/dist/compute/limits.d.ts.map +1 -1
- package/dist/compute/limits.js +0 -1
- package/dist/compute/limits.js.map +1 -1
- package/dist/compute/server-config-write.d.ts +11 -0
- package/dist/compute/server-config-write.d.ts.map +1 -1
- package/dist/compute/server-config-write.js +34 -0
- package/dist/compute/server-config-write.js.map +1 -1
- package/dist/definitions/definition-service.d.ts.map +1 -1
- package/dist/definitions/definition-service.js +3 -2
- package/dist/definitions/definition-service.js.map +1 -1
- package/dist/definitions/visibility.d.ts.map +1 -1
- package/dist/definitions/visibility.js +3 -3
- package/dist/definitions/visibility.js.map +1 -1
- package/dist/handlers/apiTokens.d.ts.map +1 -1
- package/dist/handlers/apiTokens.js +3 -1
- package/dist/handlers/apiTokens.js.map +1 -1
- package/dist/handlers/definitionVersions.d.ts.map +1 -1
- package/dist/handlers/definitionVersions.js +2 -2
- package/dist/handlers/definitionVersions.js.map +1 -1
- package/dist/handlers/definitions.d.ts.map +1 -1
- package/dist/handlers/definitions.js +27 -15
- package/dist/handlers/definitions.js.map +1 -1
- package/dist/handlers/index.d.ts +1 -1
- package/dist/handlers/index.d.ts.map +1 -1
- package/dist/handlers/index.js +1 -1
- package/dist/handlers/index.js.map +1 -1
- package/dist/handlers/invites.d.ts +4 -3
- package/dist/handlers/invites.d.ts.map +1 -1
- package/dist/handlers/invites.js +17 -3
- package/dist/handlers/invites.js.map +1 -1
- package/dist/handlers/oauthConsent.d.ts +25 -13
- package/dist/handlers/oauthConsent.d.ts.map +1 -1
- package/dist/handlers/oauthConsent.js +29 -13
- package/dist/handlers/oauthConsent.js.map +1 -1
- package/dist/handlers/orgAssets.d.ts.map +1 -1
- package/dist/handlers/orgAssets.js +2 -2
- package/dist/handlers/orgAssets.js.map +1 -1
- package/dist/handlers/orgCompute.d.ts.map +1 -1
- package/dist/handlers/orgCompute.js +4 -2
- package/dist/handlers/orgCompute.js.map +1 -1
- package/dist/handlers/orgMembers.d.ts.map +1 -1
- package/dist/handlers/orgMembers.js +76 -56
- package/dist/handlers/orgMembers.js.map +1 -1
- package/dist/handlers/ownerChanges.d.ts +8 -0
- package/dist/handlers/ownerChanges.d.ts.map +1 -0
- package/dist/handlers/ownerChanges.js +19 -0
- package/dist/handlers/ownerChanges.js.map +1 -0
- package/dist/handlers/projectMembers.d.ts.map +1 -1
- package/dist/handlers/projectMembers.js +20 -15
- package/dist/handlers/projectMembers.js.map +1 -1
- package/dist/handlers/projects.d.ts.map +1 -1
- package/dist/handlers/projects.js +10 -3
- package/dist/handlers/projects.js.map +1 -1
- package/dist/http/api-token.d.ts +17 -0
- package/dist/http/api-token.d.ts.map +1 -1
- package/dist/http/api-token.js +49 -14
- package/dist/http/api-token.js.map +1 -1
- package/dist/http/csrf.d.ts.map +1 -1
- package/dist/http/csrf.js +4 -2
- package/dist/http/csrf.js.map +1 -1
- package/dist/http/index.d.ts +1 -1
- package/dist/http/index.d.ts.map +1 -1
- package/dist/http/index.js +1 -1
- package/dist/http/index.js.map +1 -1
- package/dist/http/redirect.d.ts.map +1 -1
- package/dist/http/redirect.js +5 -0
- package/dist/http/redirect.js.map +1 -1
- package/dist/notifications/smtp-provider.d.ts.map +1 -1
- package/dist/notifications/smtp-provider.js +13 -6
- package/dist/notifications/smtp-provider.js.map +1 -1
- package/dist/oauth/index.d.ts +3 -0
- package/dist/oauth/index.d.ts.map +1 -1
- package/dist/oauth/index.js +14 -8
- package/dist/oauth/index.js.map +1 -1
- package/dist/organizations/org-asset-service.d.ts +2 -2
- package/dist/organizations/org-asset-service.js +2 -2
- package/dist/projects/delete-with-blobs.d.ts +17 -0
- package/dist/projects/delete-with-blobs.d.ts.map +1 -0
- package/dist/projects/delete-with-blobs.js +49 -0
- package/dist/projects/delete-with-blobs.js.map +1 -0
- package/dist/projects/index.d.ts +1 -0
- package/dist/projects/index.d.ts.map +1 -1
- package/dist/projects/index.js +1 -0
- package/dist/projects/index.js.map +1 -1
- package/package.json +11 -10
|
@@ -11,9 +11,10 @@
|
|
|
11
11
|
* demoting them does.
|
|
12
12
|
*/
|
|
13
13
|
import { apiError, ApiErrorCode, noContent, parseBody, requireParams, UpdateOrgMemberBodySchema } from '../api/index.js';
|
|
14
|
-
import { MEMBER_ASSIGNABLE_PERMISSIONS, ALL_ORG_PERMISSIONS, actorOf, canChangeOrgRole } from '@selvajs/platform';
|
|
14
|
+
import { MEMBER_ASSIGNABLE_PERMISSIONS, ALL_ORG_PERMISSIONS, actorOf, canChangeOrgRole, SYSTEM_CONTEXT } from '@selvajs/platform';
|
|
15
15
|
import { requireManageOrgMembers, requireActingOrg } from '../access/index.js';
|
|
16
16
|
import { revokeUserApiTokens } from './apiTokens.js';
|
|
17
|
+
import { serializeOwnerChanges } from './ownerChanges.js';
|
|
17
18
|
const ROSTER_PAGE_LIMIT = 200;
|
|
18
19
|
// Runaway guard against an adapter returning a non-advancing cursor. Matches
|
|
19
20
|
// `listAllOrgMembers`; 100 pages is 20k members, past any real org here.
|
|
@@ -68,11 +69,15 @@ async function hasAnotherOwner(req, ctx, orgId, exceptUserId) {
|
|
|
68
69
|
*
|
|
69
70
|
* MUST be called before the removal — afterwards the rows it reads are gone.
|
|
70
71
|
*/
|
|
71
|
-
async function findProjectsLosingSoleOwner(req,
|
|
72
|
+
async function findProjectsLosingSoleOwner(req, orgId, userId) {
|
|
73
|
+
// As system: RLS hides private projects from the acting admin, and those are the
|
|
74
|
+
// likeliest to lose their only owner.
|
|
72
75
|
const projects = req.deps.projects;
|
|
73
|
-
const orgProjects = await projects.listProjects(
|
|
76
|
+
const orgProjects = await projects.listProjects(SYSTEM_CONTEXT, orgId, {
|
|
77
|
+
limit: ROSTER_PAGE_LIMIT
|
|
78
|
+
});
|
|
74
79
|
const checks = await Promise.all(orgProjects.items.map(async (project) => {
|
|
75
|
-
const members = await projects.listProjectMembers(
|
|
80
|
+
const members = await projects.listProjectMembers(SYSTEM_CONTEXT, project.id, {
|
|
76
81
|
limit: ROSTER_PAGE_LIMIT
|
|
77
82
|
});
|
|
78
83
|
const owners = members.items.filter((m) => m.role === 'owner' && !m.deletedAt);
|
|
@@ -96,42 +101,54 @@ export const updateOrgMember = async (req) => {
|
|
|
96
101
|
const { ctx, orgId } = requireActingOrg(req, req.params.orgId);
|
|
97
102
|
const patch = await parseBody(req.request, UpdateOrgMemberBodySchema);
|
|
98
103
|
const orgs = req.deps.orgs;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if (patch.role !== undefined && patch.role !== target.role) {
|
|
109
|
-
// Gated on both the role being granted and the one being taken away —
|
|
110
|
-
// demoting an owner is an owner-only act even though `member` is not.
|
|
111
|
-
if (!canChangeOrgRole({ actorMember, role: patch.role }) ||
|
|
112
|
-
!canChangeOrgRole({ actorMember, role: target.role })) {
|
|
113
|
-
apiError(403, ApiErrorCode.FORBIDDEN, 'Only the org owner can change roles.');
|
|
104
|
+
return serializeOwnerChanges(orgId, async () => {
|
|
105
|
+
const [actorMember, target] = await Promise.all([
|
|
106
|
+
orgs.getOrgMember(ctx, orgId, ctx.userId),
|
|
107
|
+
orgs.getOrgMember(ctx, orgId, userId)
|
|
108
|
+
]);
|
|
109
|
+
if (!target)
|
|
110
|
+
apiError(404, ApiErrorCode.NOT_FOUND, 'Member not found in this organization.');
|
|
111
|
+
if (!actorMember) {
|
|
112
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'You are not a member of this organization.');
|
|
114
113
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
const roleChange = patch.role !== undefined && patch.role !== target.role;
|
|
115
|
+
if (roleChange) {
|
|
116
|
+
// Gated on both the role being granted and the one being taken away —
|
|
117
|
+
// demoting an owner is an owner-only act even though `member` is not.
|
|
118
|
+
if (!canChangeOrgRole({ actorMember, role: patch.role }) ||
|
|
119
|
+
!canChangeOrgRole({ actorMember, role: target.role })) {
|
|
120
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Only the org owner can change roles.');
|
|
121
|
+
}
|
|
122
|
+
if (target.role === 'owner' &&
|
|
123
|
+
patch.role !== 'owner' &&
|
|
124
|
+
!(await hasAnotherOwner(req, ctx, orgId, target.userId))) {
|
|
125
|
+
apiError(409, ApiErrorCode.CONFLICT, 'Cannot demote the sole owner of this organization. Promote another member to owner first.');
|
|
126
|
+
}
|
|
119
127
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
128
|
+
if (patch.permissions !== undefined) {
|
|
129
|
+
// Emptying an owner's or admin's set demotes them in all but name.
|
|
130
|
+
if (!canChangeOrgRole({ actorMember, role: target.role })) {
|
|
131
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Only the org owner can change an owner’s or admin’s permissions.');
|
|
132
|
+
}
|
|
133
|
+
// Validate against the role the member will have, not the one they had.
|
|
134
|
+
const effectiveRole = patch.role ?? target.role;
|
|
135
|
+
const valid = effectiveRole === 'member'
|
|
136
|
+
? new Set(MEMBER_ASSIGNABLE_PERMISSIONS)
|
|
137
|
+
: new Set(ALL_ORG_PERMISSIONS);
|
|
138
|
+
const invalid = patch.permissions.filter((p) => !valid.has(p));
|
|
139
|
+
if (invalid.length > 0) {
|
|
140
|
+
apiError(400, ApiErrorCode.VALIDATION_FAILED, `Permissions [${invalid.join(', ')}] cannot be assigned to a ${effectiveRole}.`);
|
|
141
|
+
}
|
|
131
142
|
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
143
|
+
// Writes only after every check, so a refused permission set can't leave a
|
|
144
|
+
// role change behind.
|
|
145
|
+
if (roleChange)
|
|
146
|
+
await orgs.updateOrgMemberRole(ctx, orgId, userId, patch.role);
|
|
147
|
+
if (patch.permissions !== undefined) {
|
|
148
|
+
await orgs.updateOrgMemberPermissions(ctx, orgId, userId, patch.permissions);
|
|
149
|
+
}
|
|
150
|
+
return noContent();
|
|
151
|
+
});
|
|
135
152
|
};
|
|
136
153
|
/**
|
|
137
154
|
* Remove a member from the org. Owner/admin via `manage_org_members`, same
|
|
@@ -143,25 +160,28 @@ export const removeOrgMember = async (req) => {
|
|
|
143
160
|
requireManageOrgMembers(req);
|
|
144
161
|
const { ctx, orgId } = requireActingOrg(req, req.params.orgId);
|
|
145
162
|
const orgs = req.deps.orgs;
|
|
146
|
-
const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
163
|
+
const orphaned = await serializeOwnerChanges(orgId, async () => {
|
|
164
|
+
const [actorMember, target] = await Promise.all([
|
|
165
|
+
orgs.getOrgMember(ctx, orgId, ctx.userId),
|
|
166
|
+
orgs.getOrgMember(ctx, orgId, userId)
|
|
167
|
+
]);
|
|
168
|
+
if (!target)
|
|
169
|
+
apiError(404, ApiErrorCode.NOT_FOUND, 'Member not found in this organization.');
|
|
170
|
+
// Same owner-only gate PATCH applies to demotion. Removing an owner ends
|
|
171
|
+
// their role just as demoting them does, so an admin got 403 on the demote
|
|
172
|
+
// and 204 on the remove — the harder-to-reverse of the two.
|
|
173
|
+
if (!canChangeOrgRole({ actorMember, role: target.role })) {
|
|
174
|
+
apiError(403, ApiErrorCode.FORBIDDEN, 'Only the org owner can remove another owner.');
|
|
175
|
+
}
|
|
176
|
+
if (target.role === 'owner' && !(await hasAnotherOwner(req, ctx, orgId, target.userId))) {
|
|
177
|
+
apiError(409, ApiErrorCode.CONFLICT, 'Cannot remove the sole owner of this organization. Promote another member to owner first.');
|
|
178
|
+
}
|
|
179
|
+
// Must run before the removal: the cascade soft-deletes the very rows this
|
|
180
|
+
// reads. Reported, not blocked — see the docblock on `findProjectsLosingSoleOwner`.
|
|
181
|
+
const losing = await findProjectsLosingSoleOwner(req, orgId, userId);
|
|
182
|
+
await orgs.removeOrgMember(ctx, orgId, userId);
|
|
183
|
+
return losing;
|
|
184
|
+
});
|
|
165
185
|
if (orphaned.length > 0) {
|
|
166
186
|
await req.deps.events.emit({
|
|
167
187
|
type: 'org_member.removed_orphaning_projects',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orgMembers.js","sourceRoot":"","sources":["../../src/handlers/orgMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACN,QAAQ,EACR,YAAY,EACZ,SAAS,EACT,SAAS,EACT,aAAa,EACb,yBAAyB,EACzB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACN,6BAA6B,EAC7B,mBAAmB,EACnB,OAAO,EACP,gBAAgB,
|
|
1
|
+
{"version":3,"file":"orgMembers.js","sourceRoot":"","sources":["../../src/handlers/orgMembers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs one org's or project's member changes one at a time. The sole-owner check
|
|
3
|
+
* reads, then writes: two owners acting on each other at once would each see the
|
|
4
|
+
* other as the survivor and leave none. Per process only; replicas still need an
|
|
5
|
+
* atomic store write to close it.
|
|
6
|
+
*/
|
|
7
|
+
export declare function serializeOwnerChanges<T>(id: string, run: () => Promise<T>): Promise<T>;
|
|
8
|
+
//# sourceMappingURL=ownerChanges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownerChanges.d.ts","sourceRoot":"","sources":["../../src/handlers/ownerChanges.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAStF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const ownerChangeQueues = new Map();
|
|
2
|
+
/**
|
|
3
|
+
* Runs one org's or project's member changes one at a time. The sole-owner check
|
|
4
|
+
* reads, then writes: two owners acting on each other at once would each see the
|
|
5
|
+
* other as the survivor and leave none. Per process only; replicas still need an
|
|
6
|
+
* atomic store write to close it.
|
|
7
|
+
*/
|
|
8
|
+
export function serializeOwnerChanges(id, run) {
|
|
9
|
+
const previous = ownerChangeQueues.get(id) ?? Promise.resolve();
|
|
10
|
+
const next = previous.catch(() => { }).then(run);
|
|
11
|
+
const tail = next.catch(() => { });
|
|
12
|
+
ownerChangeQueues.set(id, tail);
|
|
13
|
+
void tail.then(() => {
|
|
14
|
+
if (ownerChangeQueues.get(id) === tail)
|
|
15
|
+
ownerChangeQueues.delete(id);
|
|
16
|
+
});
|
|
17
|
+
return next;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=ownerChanges.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ownerChanges.js","sourceRoot":"","sources":["../../src/handlers/ownerChanges.ts"],"names":[],"mappings":"AAAA,MAAM,iBAAiB,GAAG,IAAI,GAAG,EAA4B,CAAC;AAE9D;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAI,EAAU,EAAE,GAAqB;IACzE,MAAM,QAAQ,GAAG,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;IAChE,MAAM,IAAI,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAClC,iBAAiB,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAChC,KAAK,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;QACnB,IAAI,iBAAiB,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,IAAI;YAAE,iBAAiB,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectMembers.d.ts","sourceRoot":"","sources":["../../src/handlers/projectMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"projectMembers.d.ts","sourceRoot":"","sources":["../../src/handlers/projectMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAeH,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,iBAAiB,CAAC;AAK9D,eAAO,MAAM,kBAAkB,EAAE,UAMhC,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,UAwB9B,CAAC;AAuCF,eAAO,MAAM,uBAAuB,EAAE,UAqBrC,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,UAiBjC,CAAC"}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import { AddProjectMemberBodySchema, apiError, ApiErrorCode, collection, created, noContent, parseBody, parseListOptions, requireCaller, requireParams, UpdateProjectMemberBodySchema } from '../api/index.js';
|
|
11
11
|
import { checkOwnerRemoval } from '@selvajs/platform';
|
|
12
12
|
import { requireCanManage, requireTargetIsOrgMember } from '../access/index.js';
|
|
13
|
+
import { serializeOwnerChanges } from './ownerChanges.js';
|
|
13
14
|
export const listProjectMembers = async (req) => {
|
|
14
15
|
const { id } = requireParams(req.params, 'id');
|
|
15
16
|
const { ctx } = requireCaller(req);
|
|
@@ -69,27 +70,31 @@ export const updateProjectMemberRole = async (req) => {
|
|
|
69
70
|
// it runs the same guard DELETE does. Without this a sole owner can PATCH
|
|
70
71
|
// themselves to `viewer` and lock the project — `canManage`,
|
|
71
72
|
// `canEditProjectSettings` and `canEdit` all go false at once.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
return serializeOwnerChanges(id, async () => {
|
|
74
|
+
if (role !== 'owner') {
|
|
75
|
+
const target = await req.deps.projects.getProjectMember(ctx, id, userId);
|
|
76
|
+
if (target?.role === 'owner') {
|
|
77
|
+
await assertOwnerRemovable(req, id, target, 'demote');
|
|
78
|
+
}
|
|
76
79
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
await req.deps.projects.updateProjectMemberRole(ctx, id, userId, role);
|
|
81
|
+
return noContent();
|
|
82
|
+
});
|
|
80
83
|
};
|
|
81
84
|
export const removeProjectMember = async (req) => {
|
|
82
85
|
const { id, userId } = requireParams(req.params, 'id', 'userId');
|
|
83
86
|
const { ctx } = requireCaller(req);
|
|
84
87
|
await requireCanManage(req, id, 'members');
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
+
return serializeOwnerChanges(id, async () => {
|
|
89
|
+
const target = await req.deps.projects.getProjectMember(ctx, id, userId);
|
|
90
|
+
// Idempotent: already gone, or never there.
|
|
91
|
+
if (!target)
|
|
92
|
+
return noContent();
|
|
93
|
+
if (target.role === 'owner') {
|
|
94
|
+
await assertOwnerRemovable(req, id, target, 'remove');
|
|
95
|
+
}
|
|
96
|
+
await req.deps.projects.removeProjectMember(ctx, id, userId);
|
|
88
97
|
return noContent();
|
|
89
|
-
|
|
90
|
-
await assertOwnerRemovable(req, id, target, 'remove');
|
|
91
|
-
}
|
|
92
|
-
await req.deps.projects.removeProjectMember(ctx, id, userId);
|
|
93
|
-
return noContent();
|
|
98
|
+
});
|
|
94
99
|
};
|
|
95
100
|
//# sourceMappingURL=projectMembers.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projectMembers.js","sourceRoot":"","sources":["../../src/handlers/projectMembers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EACN,0BAA0B,EAC1B,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,6BAA6B,EAC7B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,iBAAiB,EAAwC,MAAM,mBAAmB,CAAC;AAC5F,OAAO,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"projectMembers.js","sourceRoot":"","sources":["../../src/handlers/projectMembers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAYN,KAAK,UAAU,EACf,MAAM,iBAAiB,CAAC;AAyBzB;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,UAgC1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAiD3B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,UAmCxB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"projects.d.ts","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAYN,KAAK,UAAU,EACf,MAAM,iBAAiB,CAAC;AAyBzB;;;;GAIG;AACH,eAAO,MAAM,YAAY,EAAE,UAgC1B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAiD3B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,UAmCxB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAyE3B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,UAe3B,CAAC"}
|
|
@@ -11,7 +11,7 @@ import { apiError, ApiErrorCode, collection, created, noContent, parseBody, pars
|
|
|
11
11
|
import { canChangeVisibilityToPublic, canCreateDefinition, canEdit, canSolve, canView, hasPermission, slugify, SYSTEM_CONTEXT, outsideTokenOrg, scopeAllows, validateProjectFlags, withAdminBypass } from '@selvajs/platform';
|
|
12
12
|
import { resolveAccessibleProjects } from '../definitions/index.js';
|
|
13
13
|
import { projectAccessInputFromRowsWith, requireCanCreateProject, requireCanEditProjectSettings, requireCanManage } from '../access/index.js';
|
|
14
|
-
import { createProjectWithUniqueSlug } from '../projects/index.js';
|
|
14
|
+
import { createProjectWithUniqueSlug, deleteProjectWithBlobs } from '../projects/index.js';
|
|
15
15
|
/**
|
|
16
16
|
* Projects the caller can view. `canCreateDefinitions` says whether
|
|
17
17
|
* `POST /definitions` would take this project from this caller: the same rule
|
|
@@ -160,7 +160,10 @@ export const updateProject = async (req) => {
|
|
|
160
160
|
// A renamed project gets a re-derived slug; the two must not drift apart.
|
|
161
161
|
if (input.name !== undefined) {
|
|
162
162
|
patch.name = input.name;
|
|
163
|
-
|
|
163
|
+
// A name with no usable letters yields '', which keeps the current slug.
|
|
164
|
+
const slug = slugify(input.name);
|
|
165
|
+
if (slug)
|
|
166
|
+
patch.slug = slug;
|
|
164
167
|
}
|
|
165
168
|
if (input.description !== undefined)
|
|
166
169
|
patch.description = input.description ?? undefined;
|
|
@@ -175,7 +178,11 @@ export const deleteProject = async (req) => {
|
|
|
175
178
|
const { id } = requireParams(req.params, 'id');
|
|
176
179
|
const { ctx } = requireCaller(req);
|
|
177
180
|
await requireCanManage(req, id);
|
|
178
|
-
await
|
|
181
|
+
await deleteProjectWithBlobs({
|
|
182
|
+
projects: req.deps.projects,
|
|
183
|
+
definitions: req.deps.definitionMeta,
|
|
184
|
+
storage: req.deps.storage
|
|
185
|
+
}, ctx, id);
|
|
179
186
|
return noContent();
|
|
180
187
|
};
|
|
181
188
|
//# sourceMappingURL=projects.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACN,QAAQ,EACR,YAAY,EACZ,UAAU,EACV,OAAO,EACP,SAAS,EACT,SAAS,EACT,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,uBAAuB,EACvB,uBAAuB,EAEvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACN,2BAA2B,EAC3B,mBAAmB,EACnB,OAAO,EACP,QAAQ,EACR,OAAO,EACP,aAAa,EACb,OAAO,EACP,cAAc,EACd,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,eAAe,EAEf,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EACN,8BAA8B,EAC9B,uBAAuB,EACvB,6BAA6B,EAC7B,gBAAgB,EAChB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,2BAA2B,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"projects.js","sourceRoot":"","sources":["../../src/handlers/projects.ts"],"names":[],"mappings":"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"}
|
package/dist/http/api-token.d.ts
CHANGED
|
@@ -31,6 +31,11 @@ export interface ResolveApiTokenDeps {
|
|
|
31
31
|
* rule's project scan. Absent: every flag off, which only ever refuses more.
|
|
32
32
|
*/
|
|
33
33
|
flag?: (name: keyof SelvaFlags) => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Skips the holder check for a token that passed it within the cache's TTL.
|
|
36
|
+
* Absent: checked on every request.
|
|
37
|
+
*/
|
|
38
|
+
holderVerdicts?: HolderVerdictCache;
|
|
34
39
|
/** Receives background failures (the `lastUsedAt` write). Logs the token id only. */
|
|
35
40
|
log?: ILogger;
|
|
36
41
|
now?: () => number;
|
|
@@ -52,4 +57,16 @@ export interface ResolveApiTokenOptions {
|
|
|
52
57
|
* narrowed to the token's scopes.
|
|
53
58
|
*/
|
|
54
59
|
export declare function resolveApiToken(request: Request, deps: ResolveApiTokenDeps, { pathPrefix }?: ResolveApiTokenOptions): Promise<ApiTokenResolution>;
|
|
60
|
+
export interface HolderVerdictCache {
|
|
61
|
+
passed(tokenId: string, now: number): boolean;
|
|
62
|
+
remember(tokenId: string, now: number): void;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Remembers passed holder checks for `ttlMs`, so a busy upload key doesn't
|
|
66
|
+
* re-scan its org's projects on every request. A withdrawn right takes effect
|
|
67
|
+
* within the TTL; a disabled owner or a removed member is still refused at once.
|
|
68
|
+
*/
|
|
69
|
+
export declare function createHolderVerdictCache(ttlMs?: number, maxEntries?: number): HolderVerdictCache;
|
|
70
|
+
/** The bearer credential, or null. CSRF's exemption reads it here too: the two must agree. */
|
|
71
|
+
export declare function bearerOf(request: Request): string | null;
|
|
55
72
|
//# sourceMappingURL=api-token.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-token.d.ts","sourceRoot":"","sources":["../../src/http/api-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,aAAa,EACb,OAAO,EACP,cAAc,EACd,UAAU,EACV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAGN,KAAK,aAAa,EAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAoB,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAG5F,MAAM,MAAM,kBAAkB;AAC7B,2EAA2E;AACzE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE;AACtE,0EAA0E;GACxE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7E,MAAM,WAAW,mBAAmB;IACnC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,kBAAkB,CAAC,CAAC;IAC1D,IAAI,EAAE,IAAI,CACT,aAAa,EACb,WAAW,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,uBAAuB,GAAG,aAAa,CAC3F,CAAC;IACF,qHAAqH;IACrH,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,UAAU,KAAK,OAAO,CAAC;IAC3C,qFAAqF;IACrF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,mBAAmB,EACzB,EAAE,UAAuB,EAAE,GAAE,sBAA2B,GACtD,OAAO,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"api-token.d.ts","sourceRoot":"","sources":["../../src/http/api-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,QAAQ,EACR,QAAQ,EACR,aAAa,EACb,aAAa,EACb,OAAO,EACP,cAAc,EACd,UAAU,EACV,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAGN,KAAK,aAAa,EAClB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAoB,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAG5F,MAAM,MAAM,kBAAkB;AAC7B,2EAA2E;AACzE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,cAAc,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAA;CAAE;AACtE,0EAA0E;GACxE;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,YAAY,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7E,MAAM,WAAW,mBAAmB;IACnC,8EAA8E;IAC9E,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,kBAAkB,CAAC,CAAC;IAC1D,IAAI,EAAE,IAAI,CACT,aAAa,EACb,WAAW,GAAG,MAAM,GAAG,aAAa,GAAG,UAAU,GAAG,uBAAuB,GAAG,aAAa,CAC3F,CAAC;IACF,qHAAqH;IACrH,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC;;;OAGG;IACH,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,UAAU,KAAK,OAAO,CAAC;IAC3C;;;OAGG;IACH,cAAc,CAAC,EAAE,kBAAkB,CAAC;IACpC,qFAAqF;IACrF,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,sBAAsB;IACtC,mEAAmE;IACnE,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AA0BD;;;;;;;;;;;GAWG;AACH,wBAAsB,eAAe,CACpC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,mBAAmB,EACzB,EAAE,UAAuB,EAAE,GAAE,sBAA2B,GACtD,OAAO,CAAC,kBAAkB,CAAC,CAoF7B;AAED,MAAM,WAAW,kBAAkB;IAClC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,EAAE,UAAU,SAAS,GAAG,kBAAkB,CAoBhG;AAED,8FAA8F;AAC9F,wBAAgB,QAAQ,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAKxD"}
|
package/dist/http/api-token.js
CHANGED
|
@@ -79,18 +79,22 @@ export async function resolveApiToken(request, deps, { pathPrefix = '/api/v1/' }
|
|
|
79
79
|
if (!user || user.disabled || !member)
|
|
80
80
|
return UNAUTHORIZED;
|
|
81
81
|
const live = await buildRequestContext({ user, platformPermissions, membership: member, pinOrg: true }, { orgs: deps.data.orgs });
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
82
|
+
const now = deps.now?.() ?? Date.now();
|
|
83
|
+
if (!deps.holderVerdicts?.passed(token.id, now)) {
|
|
84
|
+
const holds = await canHoldApiTokens(live, token.scopes, {
|
|
85
|
+
policy: deps.mayHoldApiTokens,
|
|
86
|
+
deps: {
|
|
87
|
+
orgs: deps.data.orgs,
|
|
88
|
+
projects: deps.data.projects,
|
|
89
|
+
platformProjectGrants: deps.data.platformProjectGrants,
|
|
90
|
+
definitionMeta: deps.data.definitions,
|
|
91
|
+
flag: deps.flag ?? (() => false)
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
if (!holds)
|
|
95
|
+
return HOLDER_REFUSED;
|
|
96
|
+
deps.holderVerdicts?.remember(token.id, now);
|
|
97
|
+
}
|
|
94
98
|
let ctx = narrowApiTokenContext(live, token);
|
|
95
99
|
// Signed only after the user check above: a minted session can't be
|
|
96
100
|
// revoked, and row security doesn't look at bans.
|
|
@@ -98,7 +102,6 @@ export async function resolveApiToken(request, deps, { pathPrefix = '/api/v1/' }
|
|
|
98
102
|
const sessionToken = await delegated.mint(user.id, { orgId: token.orgId });
|
|
99
103
|
ctx = { ...ctx, adapterContext: { sessionToken } };
|
|
100
104
|
}
|
|
101
|
-
const now = deps.now?.() ?? Date.now();
|
|
102
105
|
if (!token.lastUsedAt || now - Date.parse(token.lastUsedAt) >= LAST_USED_WRITE_INTERVAL_MS) {
|
|
103
106
|
store.touchLastUsed(SYSTEM_CONTEXT, token.id, new Date(now).toISOString()).catch((err) => {
|
|
104
107
|
deps.log?.warn('Failed to record API token use', {
|
|
@@ -110,7 +113,39 @@ export async function resolveApiToken(request, deps, { pathPrefix = '/api/v1/' }
|
|
|
110
113
|
}
|
|
111
114
|
return { kind: 'ok', user, ctx, token };
|
|
112
115
|
}
|
|
113
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Remembers passed holder checks for `ttlMs`, so a busy upload key doesn't
|
|
118
|
+
* re-scan its org's projects on every request. A withdrawn right takes effect
|
|
119
|
+
* within the TTL; a disabled owner or a removed member is still refused at once.
|
|
120
|
+
*/
|
|
121
|
+
export function createHolderVerdictCache(ttlMs = 30_000, maxEntries = 10_000) {
|
|
122
|
+
const until = new Map();
|
|
123
|
+
return {
|
|
124
|
+
passed(tokenId, now) {
|
|
125
|
+
const expiry = until.get(tokenId);
|
|
126
|
+
if (expiry === undefined)
|
|
127
|
+
return false;
|
|
128
|
+
if (expiry > now)
|
|
129
|
+
return true;
|
|
130
|
+
until.delete(tokenId);
|
|
131
|
+
return false;
|
|
132
|
+
},
|
|
133
|
+
remember(tokenId, now) {
|
|
134
|
+
if (until.size >= maxEntries) {
|
|
135
|
+
for (const [id, expiry] of until)
|
|
136
|
+
if (expiry <= now)
|
|
137
|
+
until.delete(id);
|
|
138
|
+
// Still full of live entries: drop the oldest insert.
|
|
139
|
+
if (until.size >= maxEntries)
|
|
140
|
+
until.delete(until.keys().next().value);
|
|
141
|
+
}
|
|
142
|
+
until.delete(tokenId);
|
|
143
|
+
until.set(tokenId, now + ttlMs);
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
/** The bearer credential, or null. CSRF's exemption reads it here too: the two must agree. */
|
|
148
|
+
export function bearerOf(request) {
|
|
114
149
|
const header = request.headers.get('authorization');
|
|
115
150
|
if (!header)
|
|
116
151
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-token.js","sourceRoot":"","sources":["../../src/http/api-token.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,cAAc,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EACN,gBAAgB,EAChB,iBAAiB,EAEjB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,gBAAgB,EAA6B,MAAM,+BAA+B,CAAC;AAC5F,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"api-token.js","sourceRoot":"","sources":["../../src/http/api-token.ts"],"names":[],"mappings":"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"}
|
package/dist/http/csrf.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/http/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"csrf.d.ts","sourceRoot":"","sources":["../../src/http/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAeH,MAAM,WAAW,WAAW;IAC3B,sDAAsD;IACtD,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAChC;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAU9F"}
|
package/dist/http/csrf.js
CHANGED
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
* `Origin` (the OAuth token endpoint, per RFC 6749).
|
|
12
12
|
*/
|
|
13
13
|
import { API_TOKEN_PREFIX } from '../tokens/index.js';
|
|
14
|
+
import { bearerOf } from './api-token.js';
|
|
14
15
|
const UNSAFE_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
|
|
15
16
|
// The content types a browser form can send without a CORS preflight, plus
|
|
16
17
|
// SvelteKit's own binary form encoding.
|
|
@@ -26,8 +27,9 @@ export function isCrossSiteFormSubmission(request, options = {}) {
|
|
|
26
27
|
const type = (request.headers.get('content-type') ?? '').split(';')[0].trim().toLowerCase();
|
|
27
28
|
if (!FORM_TYPES.includes(type))
|
|
28
29
|
return false;
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
// The same parse `resolveApiToken` uses: a header one read as a key and the
|
|
31
|
+
// other didn't would skip this check and still run as the cookie session.
|
|
32
|
+
if (bearerOf(request)?.startsWith(API_TOKEN_PREFIX))
|
|
31
33
|
return false;
|
|
32
34
|
const url = new URL(request.url);
|
|
33
35
|
if (options.exemptPaths?.includes(url.pathname))
|
package/dist/http/csrf.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/http/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"csrf.js","sourceRoot":"","sources":["../../src/http/csrf.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAE1C,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AACnE,2EAA2E;AAC3E,wCAAwC;AACxC,MAAM,UAAU,GAAG;IAClB,mCAAmC;IACnC,qBAAqB;IACrB,YAAY;IACZ,kCAAkC;CAClC,CAAC;AAOF,MAAM,UAAU,yBAAyB,CAAC,OAAgB,EAAE,UAAuB,EAAE;IACpF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5F,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC7C,4EAA4E;IAC5E,0EAA0E;IAC1E,IAAI,QAAQ,CAAC,OAAO,CAAC,EAAE,UAAU,CAAC,gBAAgB,CAAC;QAAE,OAAO,KAAK,CAAC;IAClE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9D,OAAO,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,GAAG,CAAC,MAAM,CAAC;AACrD,CAAC"}
|
package/dist/http/index.d.ts
CHANGED
|
@@ -5,5 +5,5 @@ export { applySecurityHeaders, type SecurityHeaderOptions } from './security-hea
|
|
|
5
5
|
export { createRouteClassifier, type RouteClassifier, type RouteClassifierConfig } from './route-classifier.js';
|
|
6
6
|
export { createLoginRateLimiter, addressKeysCollapsed, type LoginRateLimiter, type LoginRateLimiterConfig } from './login-rate-limit.js';
|
|
7
7
|
export { buildRequestContext, type BuildRequestContextInput } from './request-context.js';
|
|
8
|
-
export { resolveApiToken, type ApiTokenResolution, type ResolveApiTokenDeps, type ResolveApiTokenOptions } from './api-token.js';
|
|
8
|
+
export { createHolderVerdictCache, resolveApiToken, type ApiTokenResolution, type HolderVerdictCache, type ResolveApiTokenDeps, type ResolveApiTokenOptions } from './api-token.js';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|