@7365admin1/core 3.48.1-staging.201 → 3.48.1-staging.202
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/.changeset/invite-org-scope.md +38 -0
- package/dist/index.js +14 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/harness.mjs +28 -5
- package/test/e2e/invite-org-scoping.e2e.test.mjs +538 -0
- package/test/e2e/org-invite-seats.e2e.test.mjs +1 -1
- package/test/e2e/subscription-seat-update.e2e.test.mjs +1 -1
- package/test/invite-org-scope.test.mjs +111 -0
- package/test/member-staff-gate.test.mjs +12 -6
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": minor
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope invitation creation to an organisation the caller can reach, and stop a
|
|
6
|
+
non-staff caller minting a Seven365 staff invitation on the v1 endpoints.
|
|
7
|
+
|
|
8
|
+
Six endpoints took `metadata.org` — and the `app` that becomes the accepted
|
|
9
|
+
membership's `type` — straight from the request body, behind `requireAuth` and
|
|
10
|
+
nothing else:
|
|
11
|
+
|
|
12
|
+
- `POST /api/auth/invite` (`auth.route.ts:29`)
|
|
13
|
+
- `POST /api/auth/invite/user` (`auth.route.ts:30`)
|
|
14
|
+
- `POST /api/auth/invite/member` (`auth.route.ts:31`)
|
|
15
|
+
- `POST /api/auth/invite/service-provider/with-org` (`auth.route.ts:33`)
|
|
16
|
+
- `POST /api/auth/v2/invite` (`auth-v2.route.ts:22`)
|
|
17
|
+
- `POST /api/auth/v2/invite/organization` (`auth-v2.route.ts:23`)
|
|
18
|
+
|
|
19
|
+
Two things followed from that.
|
|
20
|
+
|
|
21
|
+
**The organisation.** The roles/members fix lets somebody holding an invitation
|
|
22
|
+
into an organisation reach it, because the client onboarding wizard needs that.
|
|
23
|
+
An attacker could therefore issue themselves the invitation the gate asks for —
|
|
24
|
+
one authenticated write naming any victim organisation — and walk straight back
|
|
25
|
+
into the chain that fix closed.
|
|
26
|
+
|
|
27
|
+
**`app`.** "admin" is what makes a membership Seven365 staff, and
|
|
28
|
+
`member.service.ts acceptInvite` writes `type: invite.metadata.app` verbatim.
|
|
29
|
+
`createMemberDirect` already refuses a staff membership from a non-staff caller;
|
|
30
|
+
the invitation road to the same place was open on the v1 mounts. The v2 twin
|
|
31
|
+
asked; the v1 mounts, which are the ones the web apps call, did not.
|
|
32
|
+
|
|
33
|
+
All six now call `requireInviteReach` (`utils/console-authz.util.ts`): Seven365
|
|
34
|
+
staff, a live member of the organisation, or somebody holding an invitation into
|
|
35
|
+
it — plus `requirePlatformStaff` when the invitation names the staff app. An
|
|
36
|
+
invitation that names no organisation is unchanged; it grants no organisation,
|
|
37
|
+
exactly as an org-less `GET /api/roles` does. The two service-provider invites
|
|
38
|
+
that already resolved their caller from the session are unchanged.
|
package/dist/index.js
CHANGED
|
@@ -18337,6 +18337,14 @@ async function requireOrgReach(req, orgId) {
|
|
|
18337
18337
|
return id;
|
|
18338
18338
|
throw new import_node_server_utils41.UnauthorizedError("Not authorized.");
|
|
18339
18339
|
}
|
|
18340
|
+
async function requireInviteReach(req, org, app) {
|
|
18341
|
+
const apps = Array.isArray(app) ? app : [app];
|
|
18342
|
+
if (apps.some((a) => a === PLATFORM_STAFF_MEMBER_TYPE)) {
|
|
18343
|
+
await requirePlatformStaff(req);
|
|
18344
|
+
}
|
|
18345
|
+
if (org)
|
|
18346
|
+
await requireOrgReach(req, org);
|
|
18347
|
+
}
|
|
18340
18348
|
|
|
18341
18349
|
// src/utils/user-response.util.ts
|
|
18342
18350
|
function withoutCredentials(user) {
|
|
@@ -26092,6 +26100,7 @@ function useVerificationController() {
|
|
|
26092
26100
|
const siteId = req.body.siteId ?? "";
|
|
26093
26101
|
const siteName = req.body.siteName ?? "";
|
|
26094
26102
|
try {
|
|
26103
|
+
await requireInviteReach(req, org, app);
|
|
26095
26104
|
await _createUserInvite({
|
|
26096
26105
|
email,
|
|
26097
26106
|
metadata: {
|
|
@@ -26145,6 +26154,7 @@ function useVerificationController() {
|
|
|
26145
26154
|
siteId,
|
|
26146
26155
|
siteName
|
|
26147
26156
|
} = value;
|
|
26157
|
+
await requireInviteReach(req, org, app);
|
|
26148
26158
|
const verificationIds = await _createSimpleUserInvite({
|
|
26149
26159
|
email,
|
|
26150
26160
|
metadata: {
|
|
@@ -26208,6 +26218,7 @@ function useVerificationController() {
|
|
|
26208
26218
|
const siteId = req.body.siteId ?? "";
|
|
26209
26219
|
const siteName = req.body.siteName ?? "";
|
|
26210
26220
|
try {
|
|
26221
|
+
await requireInviteReach(req, org, app);
|
|
26211
26222
|
await _createSimpleMemberInvite({
|
|
26212
26223
|
email,
|
|
26213
26224
|
metadata: {
|
|
@@ -26332,6 +26343,7 @@ function useVerificationController() {
|
|
|
26332
26343
|
const siteId = req.body.siteId ?? "";
|
|
26333
26344
|
const siteName = req.body.siteName ?? "";
|
|
26334
26345
|
try {
|
|
26346
|
+
await requireInviteReach(req, orgId, app);
|
|
26335
26347
|
await _createSimpleServiceProviderInvite({
|
|
26336
26348
|
email,
|
|
26337
26349
|
app,
|
|
@@ -81041,9 +81053,7 @@ function useVerificationControllerV2() {
|
|
|
81041
81053
|
}
|
|
81042
81054
|
const { email, app, role, name, org, siteId, siteName } = value;
|
|
81043
81055
|
try {
|
|
81044
|
-
|
|
81045
|
-
await requirePlatformStaff(req);
|
|
81046
|
-
}
|
|
81056
|
+
await requireInviteReach(req, org, app);
|
|
81047
81057
|
await _createUserInvite({
|
|
81048
81058
|
email,
|
|
81049
81059
|
metadata: {
|
|
@@ -81115,6 +81125,7 @@ function useVerificationControllerV2() {
|
|
|
81115
81125
|
}
|
|
81116
81126
|
try {
|
|
81117
81127
|
const { email, app, role, name, org, siteId, siteName } = value;
|
|
81128
|
+
await requireInviteReach(req, org, app);
|
|
81118
81129
|
await _createOrganizationInvite({
|
|
81119
81130
|
email,
|
|
81120
81131
|
metadata: {
|