@7365admin1/core 3.48.1-staging.148 → 3.48.1-staging.150
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/member-write-scope.md +60 -0
- package/dist/index.d.ts +10 -3
- package/dist/index.js +14980 -14925
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14915 -14860
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/member-write-scope.e2e.test.mjs +378 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": minor
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the three remaining `/api/members` writes to the membership they name.
|
|
6
|
+
|
|
7
|
+
`PUT /api/members/id/:id/role/:role/type/:type/org/:org`,
|
|
8
|
+
`PUT /api/members/site` and `PUT /api/members/:id/onboarding/complete` all
|
|
9
|
+
carried `requireAuth` and nothing more, and each took the membership id straight
|
|
10
|
+
out of the request.
|
|
11
|
+
|
|
12
|
+
**The role write is the sharp one.** A role IS the permission set, so
|
|
13
|
+
re-pointing a membership at another role is an access grant. The service already
|
|
14
|
+
refused to hand a *Seven365 staff* role to a non-staff caller, but a **tenant**
|
|
15
|
+
role was still free: quoting another client's membership id re-pointed it at any
|
|
16
|
+
of that client's roles, their **owner** role included — and equally could demote
|
|
17
|
+
that client's own admin. The `org` in the URL was also what the service used to
|
|
18
|
+
look up owner roles for its "last owner" precondition, so a mismatched one ran
|
|
19
|
+
that safety check against the wrong client's roles entirely.
|
|
20
|
+
|
|
21
|
+
`PUT /api/members/site` took the membership id **and** the target site from the
|
|
22
|
+
body, so nothing said whose membership, or whose site, either one was — any
|
|
23
|
+
signed-in account could move any client's member onto any estate.
|
|
24
|
+
|
|
25
|
+
`PUT /api/members/:id/onboarding/complete` took the id from the URL and nothing
|
|
26
|
+
else, so any signed-in account could mark any client's membership onboarded and
|
|
27
|
+
skip that client's onboarding gate.
|
|
28
|
+
|
|
29
|
+
All three now decide from the **stored** membership, through the
|
|
30
|
+
`requireMemberOrg` helper this controller already uses for
|
|
31
|
+
`PUT /api/members/:id/:status`:
|
|
32
|
+
|
|
33
|
+
- the organisation recorded on the membership is authorised with
|
|
34
|
+
`requireOrgAccess` — Seven365 staff, or a live member of that organisation.
|
|
35
|
+
- a membership with **no** organisation is a platform staff row; only Seven365
|
|
36
|
+
staff may touch it. A missing org is refused, not waved through.
|
|
37
|
+
- the role write additionally refuses when the `org` in the URL disagrees with
|
|
38
|
+
the one on the membership, so the service's owner-role lookup can no longer be
|
|
39
|
+
pointed at another client.
|
|
40
|
+
- `PUT /api/members/site` puts the incoming site through `requireSiteReach`, the
|
|
41
|
+
same rule `/api/vehicles` and `/api/documents` use, so a member cannot be moved
|
|
42
|
+
onto an estate the caller cannot reach. An unreachable site answers as one that
|
|
43
|
+
does not exist (404), so site ids cannot be enumerated from the difference.
|
|
44
|
+
|
|
45
|
+
Guards sit **after** each handler's Joi validation, so a malformed id still
|
|
46
|
+
answers 400 exactly as it does today.
|
|
47
|
+
|
|
48
|
+
Scope note — deliberately NOT changed here: the four read-by-user routes
|
|
49
|
+
(`GET /api/members/user/:id`, `/users/:id`, `/user/:id/app/:type`,
|
|
50
|
+
`/user/:id/app/:type/org`). `layer-common ServiceProviderMain.vue:922,1320` and
|
|
51
|
+
`InvitationClientForm.vue:324` legitimately read the memberships of a user who
|
|
52
|
+
belongs to a **service provider's** organisation, not to the caller's, and no
|
|
53
|
+
existing helper expresses "an organisation my organisation has engaged". That
|
|
54
|
+
needs a product decision rather than a guess. Every other caller passes its own
|
|
55
|
+
user id. `POST /api/members/direct` and `POST /api/members/verification/:id` are
|
|
56
|
+
also unchanged — the latter is driven entirely by a single-use, expiring
|
|
57
|
+
invitation record and grants the caller nothing.
|
|
58
|
+
|
|
59
|
+
Nothing changes for a permitted caller: same response shape, same fields, same
|
|
60
|
+
status.
|
package/dist/index.d.ts
CHANGED
|
@@ -4890,6 +4890,12 @@ type TPatrolLog = {
|
|
|
4890
4890
|
cameras: Array<logCamera>;
|
|
4891
4891
|
status: Array<string>;
|
|
4892
4892
|
incidentReport: incidentReport;
|
|
4893
|
+
/**
|
|
4894
|
+
* The user who created the log. Stored as a reference only — the name is
|
|
4895
|
+
* resolved from `users` at read time, so a renamed account shows its current
|
|
4896
|
+
* name rather than whatever it was called when the log was filed.
|
|
4897
|
+
*/
|
|
4898
|
+
createdBy?: string | ObjectId | null;
|
|
4893
4899
|
platform?: string;
|
|
4894
4900
|
createdAt?: Date | string;
|
|
4895
4901
|
updatedAt?: Date | string;
|
|
@@ -4910,6 +4916,7 @@ declare function MPatrolLog(value: TPatrolLog): {
|
|
|
4910
4916
|
status: string[];
|
|
4911
4917
|
route: string | ObjectId | undefined;
|
|
4912
4918
|
incidentReport: incidentReport;
|
|
4919
|
+
createdBy: string | ObjectId | null;
|
|
4913
4920
|
platForm: string;
|
|
4914
4921
|
createdAt: string | Date;
|
|
4915
4922
|
updatedAt: string | Date;
|
|
@@ -9847,7 +9854,7 @@ declare function MHidAmicoIdentity(value: THidAmicoIdentity): {
|
|
|
9847
9854
|
member: ObjectId | undefined;
|
|
9848
9855
|
serviceProvider: ObjectId | undefined;
|
|
9849
9856
|
visitor: ObjectId | undefined;
|
|
9850
|
-
type: "admin" | "resident" | "contractor" | "
|
|
9857
|
+
type: "admin" | "resident" | "contractor" | "visitor" | "unknown" | "staff";
|
|
9851
9858
|
status: "deleted" | "active" | "inactive";
|
|
9852
9859
|
metadata: Record<string, unknown>;
|
|
9853
9860
|
createdAt: string | Date;
|
|
@@ -9951,7 +9958,7 @@ declare function useHidAmicoRepo(): {
|
|
|
9951
9958
|
member: ObjectId | undefined;
|
|
9952
9959
|
serviceProvider: ObjectId | undefined;
|
|
9953
9960
|
visitor: ObjectId | undefined;
|
|
9954
|
-
type: "admin" | "resident" | "contractor" | "
|
|
9961
|
+
type: "admin" | "resident" | "contractor" | "visitor" | "unknown" | "staff";
|
|
9955
9962
|
status: "deleted" | "active" | "inactive";
|
|
9956
9963
|
metadata: Record<string, unknown>;
|
|
9957
9964
|
createdAt: string | Date;
|
|
@@ -10308,7 +10315,7 @@ declare function useHidAmicoService(): {
|
|
|
10308
10315
|
member: bson.ObjectId | undefined;
|
|
10309
10316
|
serviceProvider: bson.ObjectId | undefined;
|
|
10310
10317
|
visitor: bson.ObjectId | undefined;
|
|
10311
|
-
type: "admin" | "resident" | "contractor" | "
|
|
10318
|
+
type: "admin" | "resident" | "contractor" | "visitor" | "unknown" | "staff";
|
|
10312
10319
|
status: "deleted" | "active" | "inactive";
|
|
10313
10320
|
metadata: Record<string, unknown>;
|
|
10314
10321
|
createdAt: string | Date;
|