@7365admin1/core 3.47.1-staging.135 → 3.47.1-staging.137
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/vehicle-approve-permission-prefix.md +22 -0
- package/.changeset/verification-status-transition.md +35 -0
- package/dist/index.js +20 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +20 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/harness.mjs +5 -0
- package/test/e2e/verification-status.e2e.test.mjs +159 -0
- package/test/vehicle-approve-permission.test.mjs +47 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Check the vehicle-approval permission under the resource name the catalogues
|
|
6
|
+
actually grant.
|
|
7
|
+
|
|
8
|
+
When a security agency adds a vehicle, the vehicle is parked at `PENDING` unless
|
|
9
|
+
the caller may approve one. `vehicle.service.ts:125` asked for
|
|
10
|
+
`vehicleManagement:approve-vehicle`, but every catalogue that can grant a
|
|
11
|
+
permission spells that resource `vehicle-mgmt` — `web-app-security`
|
|
12
|
+
`composables/useSecurityPermission.ts:87,111`, `web-app-org`
|
|
13
|
+
`composables/usePropertyPermission.ts:312`, `ma-mobile-app`
|
|
14
|
+
`src/features/permissions/permission.catalog.ts:7`, `isecure365-mobile-app`
|
|
15
|
+
`src/features/permissions/permission.catalog.ts:32`. Only the prefix differed,
|
|
16
|
+
so the string checked here was one no role could hold and the bypass could never
|
|
17
|
+
be reached by granting the permission — the agency's vehicles stayed pending
|
|
18
|
+
however the role was set up. `vehicleManagement:` appears nowhere else in any
|
|
19
|
+
repository in the organisation.
|
|
20
|
+
|
|
21
|
+
The `*` wildcard branch is untouched, so a role holding all permissions behaves
|
|
22
|
+
exactly as before; this only makes the specific grant work as intended.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": minor
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Restrict the unauthenticated invitation-status write to the one transition its
|
|
6
|
+
callers actually perform.
|
|
7
|
+
|
|
8
|
+
`PATCH /api/auth/verification/status` (`API-core auth.route.ts:36`) carries no
|
|
9
|
+
middleware, and it cannot be given any: every caller is an invitation-landing
|
|
10
|
+
page opened from an emailed link **before an account exists** —
|
|
11
|
+
`web-app-main` `pages/verify/invitation/[id].vue`,
|
|
12
|
+
`pages/verify/service-provider/[id].vue`,
|
|
13
|
+
`pages/verify/service-provider-invite/[id].vue` and
|
|
14
|
+
`pages/sign-up-invite/service-provider/index.vue`, all through
|
|
15
|
+
`layer-common composables/useLocalAuth.ts:130`. Adding `requireAuth` would break
|
|
16
|
+
invitation acceptance for everybody, including the shipped clients.
|
|
17
|
+
|
|
18
|
+
What is restricted instead is what an anonymous caller may *do*. Each of those
|
|
19
|
+
pages calls `GET /auth/verify/:id` first, and `verify`
|
|
20
|
+
(`verification.service.ts:661-690`) already refuses an invitation that is
|
|
21
|
+
expired, cancelled or complete — so the only transition a real caller ever
|
|
22
|
+
performs is `pending -> complete`. Accepting the other three states let anyone
|
|
23
|
+
who learned an invitation id:
|
|
24
|
+
|
|
25
|
+
- set a used invitation back to `pending` and replay it,
|
|
26
|
+
- revive a `cancelled` or `expired` invitation, or
|
|
27
|
+
- burn somebody else's pending invitation by marking it `complete` before they
|
|
28
|
+
opened the email.
|
|
29
|
+
|
|
30
|
+
The handler now accepts only `complete`, loads the invitation and requires it to
|
|
31
|
+
be `pending`. Completing an already-complete invitation still answers 200 so a
|
|
32
|
+
page that calls this twice is not broken. Cancelling an invitation on purpose
|
|
33
|
+
keeps its own session-protected endpoint,
|
|
34
|
+
`PUT /api/verifications/:id/cancel` (`verification.route.ts:13`), so no
|
|
35
|
+
capability is removed.
|
package/dist/index.js
CHANGED
|
@@ -19440,7 +19440,7 @@ function useVerificationController() {
|
|
|
19440
19440
|
updateStatusById: _updateStatusById,
|
|
19441
19441
|
cancelUserInvitation: _cancelUserInvitation
|
|
19442
19442
|
} = useVerificationService();
|
|
19443
|
-
const { getVerifications: _getVerifications } = useVerificationRepo();
|
|
19443
|
+
const { getVerifications: _getVerifications, getById: _getVerificationById } = useVerificationRepo();
|
|
19444
19444
|
async function createUserInvite(req, res, next) {
|
|
19445
19445
|
const payload = { ...req.body };
|
|
19446
19446
|
const validation = import_joi21.default.object({
|
|
@@ -19825,7 +19825,7 @@ function useVerificationController() {
|
|
|
19825
19825
|
async function updateVerificationStatus(req, res, next) {
|
|
19826
19826
|
const validation = import_joi21.default.object({
|
|
19827
19827
|
id: import_joi21.default.string().hex().required(),
|
|
19828
|
-
status: import_joi21.default.string().valid("
|
|
19828
|
+
status: import_joi21.default.string().valid("complete").required()
|
|
19829
19829
|
});
|
|
19830
19830
|
const { error } = validation.validate(req.body);
|
|
19831
19831
|
if (error) {
|
|
@@ -19835,6 +19835,23 @@ function useVerificationController() {
|
|
|
19835
19835
|
}
|
|
19836
19836
|
try {
|
|
19837
19837
|
const { id, status } = req.body;
|
|
19838
|
+
const verification = await _getVerificationById(id);
|
|
19839
|
+
if (!verification) {
|
|
19840
|
+
next(new import_node_server_utils47.BadRequestError("Verification not found."));
|
|
19841
|
+
return;
|
|
19842
|
+
}
|
|
19843
|
+
if (verification.status === "complete") {
|
|
19844
|
+
res.json({ message: "Successfully updated verification status." });
|
|
19845
|
+
return;
|
|
19846
|
+
}
|
|
19847
|
+
if (verification.status !== "pending") {
|
|
19848
|
+
next(
|
|
19849
|
+
new import_node_server_utils47.BadRequestError(
|
|
19850
|
+
`Verification is ${verification.status} and cannot be completed.`
|
|
19851
|
+
)
|
|
19852
|
+
);
|
|
19853
|
+
return;
|
|
19854
|
+
}
|
|
19838
19855
|
const result = await _updateStatusById(id, status);
|
|
19839
19856
|
res.json({ message: result });
|
|
19840
19857
|
return;
|
|
@@ -32187,7 +32204,7 @@ function useVehicleService() {
|
|
|
32187
32204
|
user,
|
|
32188
32205
|
org: value.org
|
|
32189
32206
|
});
|
|
32190
|
-
const hasSecurityBypass = addedBySecurity && Array.isArray(userPermissions) && (userPermissions.includes("*") || userPermissions.includes("
|
|
32207
|
+
const hasSecurityBypass = addedBySecurity && Array.isArray(userPermissions) && (userPermissions.includes("*") || userPermissions.includes("vehicle-mgmt:approve-vehicle"));
|
|
32191
32208
|
if (hasSecurityBypass) {
|
|
32192
32209
|
addedByPM = true;
|
|
32193
32210
|
}
|