@7365admin1/core 3.48.1-staging.207 → 3.48.1-staging.208
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/access-management-record-scope.md +48 -0
- package/dist/index.d.ts +9 -7
- package/dist/index.js +78 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +78 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/access-management-scope.e2e.test.mjs +550 -13
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": minor
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the access-management routes that name a card, not a site.
|
|
6
|
+
|
|
7
|
+
`access-management-site-scope` closed the routes whose request already carries
|
|
8
|
+
an estate. Seven routes on the same mount carry none — they reach an access card
|
|
9
|
+
(or a unit) by `_id` and nothing else — so there was nothing for that rule to
|
|
10
|
+
read and they were left carrying `requireAuth` alone:
|
|
11
|
+
|
|
12
|
+
- `POST /sign-qr` — mints a working door credential. The card number is
|
|
13
|
+
RSA-encrypted into a QR payload the reader accepts for up to 24 hours when
|
|
14
|
+
`purpose` is `"vms"`. Any signed-in account could hand itself a valid pass for
|
|
15
|
+
any card in any estate on the platform.
|
|
16
|
+
- `PATCH /delete-card` — deactivates a card, which is what stops it opening a
|
|
17
|
+
door.
|
|
18
|
+
- `PATCH /nfc-status` — flips a card's status and activation.
|
|
19
|
+
- `PATCH /visitor-checkout` — releases a visitor's card and writes its history.
|
|
20
|
+
- `POST /card-replacement` — retires a card and hands its replacement to a unit.
|
|
21
|
+
- `POST /assign-user` — hands the cards on a unit to a list of people.
|
|
22
|
+
- `POST /settings` — rewrites an estate's access-management settings, including
|
|
23
|
+
the address of the Entrypass controller it talks to. This one DOES carry the
|
|
24
|
+
estate, in the body, and the repository upserts on it; it was simply never
|
|
25
|
+
checked.
|
|
26
|
+
|
|
27
|
+
For the six that name a record, the scope is now decided on the STORED row via
|
|
28
|
+
`siteReachOf` — the same rule `requireBulletinVideoReach` and
|
|
29
|
+
`requireEntryPassReach` already apply, and the same underlying `entitleSite`
|
|
30
|
+
verdict as `requireSiteReach`. `POST /settings` uses `requireSiteReach` on the
|
|
31
|
+
body's site, exactly as `GET /settings/:site` already does. No new mechanism and
|
|
32
|
+
no new permission string: reaching the estate is the whole rule, so the
|
|
33
|
+
contracted agency at the guardhouse, the org-wide manager and a resident reading
|
|
34
|
+
their own pass are all unaffected.
|
|
35
|
+
|
|
36
|
+
Where a write MOVES a card onto a unit (`card-replacement`, `assign-user`) the
|
|
37
|
+
destination unit is checked as well as the card, so a card cannot be re-parented
|
|
38
|
+
into an estate the caller cannot reach.
|
|
39
|
+
|
|
40
|
+
"Not yours" and "does not exist" answer identically (404), so card ids cannot be
|
|
41
|
+
enumerated. An id matching no row is refused rather than waved through, and a
|
|
42
|
+
row naming no estate fails closed. The guards sit after each handler's Joi
|
|
43
|
+
validation, so malformed input still answers 400 exactly as before.
|
|
44
|
+
|
|
45
|
+
`GET /door-access-levels`, `GET /lift-access-levels` and `GET /access-groups`
|
|
46
|
+
are deliberately NOT changed: they carry no estate and no record, only a
|
|
47
|
+
caller-supplied `acm_url`, so there is nothing to scope against without changing
|
|
48
|
+
their request contract. They are recorded as a separate piece of work.
|
package/dist/index.d.ts
CHANGED
|
@@ -6858,6 +6858,8 @@ declare function UseAccessManagementRepo(): {
|
|
|
6858
6858
|
insertedCount: number;
|
|
6859
6859
|
insertedIds: Record<number, ObjectId>;
|
|
6860
6860
|
}>;
|
|
6861
|
+
cardSitesRepo: (cardIds: Array<string | ObjectId>) => Promise<mongodb.WithId<bson.Document>[]>;
|
|
6862
|
+
unitSiteRepo: (unitId: string | ObjectId) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
6861
6863
|
accessManagementSettingsRepo: (params: TAccessMngmntSettings) => Promise<mongodb.UpdateResult<bson.Document>>;
|
|
6862
6864
|
allAccessCardsCountsRepo: (params: {
|
|
6863
6865
|
site: string;
|
|
@@ -7125,7 +7127,7 @@ declare function useAccessManagementController(): {
|
|
|
7125
7127
|
doorAccessLevels: (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
7126
7128
|
liftAccessLevels: (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
7127
7129
|
accessGroups: (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
7128
|
-
accessManagementSettings: (req: Request, res: Response) => Promise<Response<any, Record<string, any
|
|
7130
|
+
accessManagementSettings: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7129
7131
|
allAccessCardsCounts: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7130
7132
|
availableAccessCards: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7131
7133
|
userTypeAccessCards: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
@@ -7134,23 +7136,23 @@ declare function useAccessManagementController(): {
|
|
|
7134
7136
|
acknowlegdeCard: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7135
7137
|
accessandLiftCards: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7136
7138
|
replaceCard: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7137
|
-
updateNFCStatus: (req: Request, res: Response) => Promise<Response<any, Record<string, any
|
|
7139
|
+
updateNFCStatus: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7138
7140
|
doorAndLiftDropdown: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7139
|
-
cardReplacement: (req: Request, res: Response) => Promise<Response<any, Record<string, any
|
|
7141
|
+
cardReplacement: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7140
7142
|
visitorAccessCards: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7141
7143
|
getCardReplacement: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7142
7144
|
getAccessManagementSettings: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7143
7145
|
bulkPhysicalAccessCard: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7144
7146
|
assignAccessCardToUnit: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7145
|
-
deleteCard: (req: Request, res: Response) => Promise<Response<any, Record<string, any
|
|
7147
|
+
deleteCard: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7146
7148
|
getCardDetails: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7147
7149
|
addQrTag: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7148
7150
|
allQrTag: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7149
7151
|
availableCardContractors: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7150
7152
|
vmsgenerateQrCodes: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7151
7153
|
addVisitorAccessCard: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7152
|
-
signQrCode: (req: Request, res: Response) => Promise<Response<any, Record<string, any
|
|
7153
|
-
checkoutVisitor: (req: Request, res: Response) => Promise<Response<any, Record<string, any
|
|
7154
|
+
signQrCode: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7155
|
+
checkoutVisitor: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7154
7156
|
removeAccessCard: ({ cardNo, staffNo, url, }: {
|
|
7155
7157
|
cardNo: string;
|
|
7156
7158
|
staffNo: string;
|
|
@@ -7158,7 +7160,7 @@ declare function useAccessManagementController(): {
|
|
|
7158
7160
|
}) => Promise<void>;
|
|
7159
7161
|
getBlockLevelAndUnitList: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7160
7162
|
getTransactions: (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
7161
|
-
assignMultipleCards: (req: Request, res: Response) => Promise<Response<any, Record<string, any
|
|
7163
|
+
assignMultipleCards: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7162
7164
|
visitorCheckout: (req: Request, res: Response) => Promise<Response<any, Record<string, any>>>;
|
|
7163
7165
|
uploadTemplate: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
|
7164
7166
|
getResidents: (req: Request, res: Response) => Promise<Response<any, Record<string, any>> | undefined>;
|
package/dist/index.js
CHANGED
|
@@ -62041,6 +62041,24 @@ function UseAccessManagementRepo() {
|
|
|
62041
62041
|
throw new Error(error.message);
|
|
62042
62042
|
}
|
|
62043
62043
|
}
|
|
62044
|
+
async function cardSitesRepo(cardIds) {
|
|
62045
|
+
try {
|
|
62046
|
+
const ids2 = cardIds.map((id) => new import_mongodb121.ObjectId(id));
|
|
62047
|
+
return await collection().find({ _id: { $in: ids2 } }, { projection: { site: 1, org: 1 } }).toArray();
|
|
62048
|
+
} catch (error) {
|
|
62049
|
+
throw new Error(error.message);
|
|
62050
|
+
}
|
|
62051
|
+
}
|
|
62052
|
+
async function unitSiteRepo(unitId) {
|
|
62053
|
+
try {
|
|
62054
|
+
return await collectionName("building-units").findOne(
|
|
62055
|
+
{ _id: new import_mongodb121.ObjectId(unitId) },
|
|
62056
|
+
{ projection: { site: 1, org: 1 } }
|
|
62057
|
+
);
|
|
62058
|
+
} catch (error) {
|
|
62059
|
+
throw new Error(error.message);
|
|
62060
|
+
}
|
|
62061
|
+
}
|
|
62044
62062
|
async function accessManagementSettingsRepo(params) {
|
|
62045
62063
|
try {
|
|
62046
62064
|
params.site = new import_mongodb121.ObjectId(params.site);
|
|
@@ -64723,6 +64741,8 @@ function UseAccessManagementRepo() {
|
|
|
64723
64741
|
createIndexForEntrypass,
|
|
64724
64742
|
addPhysicalCardRepo,
|
|
64725
64743
|
addNonPhysicalCardRepo,
|
|
64744
|
+
cardSitesRepo,
|
|
64745
|
+
unitSiteRepo,
|
|
64726
64746
|
accessManagementSettingsRepo,
|
|
64727
64747
|
allAccessCardsCountsRepo,
|
|
64728
64748
|
availableAccessCardsRepo,
|
|
@@ -64775,6 +64795,8 @@ function useAccessManagementSvc() {
|
|
|
64775
64795
|
const {
|
|
64776
64796
|
addPhysicalCardRepo,
|
|
64777
64797
|
addNonPhysicalCardRepo,
|
|
64798
|
+
cardSitesRepo,
|
|
64799
|
+
unitSiteRepo,
|
|
64778
64800
|
accessManagementSettingsRepo,
|
|
64779
64801
|
allAccessCardsCountsRepo,
|
|
64780
64802
|
availableAccessCardsRepo,
|
|
@@ -64915,6 +64937,20 @@ function useAccessManagementSvc() {
|
|
|
64915
64937
|
throw new Error(err.message);
|
|
64916
64938
|
}
|
|
64917
64939
|
};
|
|
64940
|
+
const cardSitesSvc = async (cardIds) => {
|
|
64941
|
+
try {
|
|
64942
|
+
return await cardSitesRepo(cardIds);
|
|
64943
|
+
} catch (err) {
|
|
64944
|
+
throw new Error(err.message);
|
|
64945
|
+
}
|
|
64946
|
+
};
|
|
64947
|
+
const unitSiteSvc = async (unitId) => {
|
|
64948
|
+
try {
|
|
64949
|
+
return await unitSiteRepo(unitId);
|
|
64950
|
+
} catch (err) {
|
|
64951
|
+
throw new Error(err.message);
|
|
64952
|
+
}
|
|
64953
|
+
};
|
|
64918
64954
|
const accessManagementSettingsSvc = async (settings) => {
|
|
64919
64955
|
try {
|
|
64920
64956
|
const response = await accessManagementSettingsRepo({ ...settings });
|
|
@@ -65276,6 +65312,8 @@ function useAccessManagementSvc() {
|
|
|
65276
65312
|
accessGroupsSvc,
|
|
65277
65313
|
setCache,
|
|
65278
65314
|
getCache,
|
|
65315
|
+
cardSitesSvc,
|
|
65316
|
+
unitSiteSvc,
|
|
65279
65317
|
accessManagementSettingsSvc,
|
|
65280
65318
|
allAccessCardsCountsSvc,
|
|
65281
65319
|
availableAccessCardsSvc,
|
|
@@ -65328,6 +65366,26 @@ function useAccessManagementController() {
|
|
|
65328
65366
|
return true;
|
|
65329
65367
|
}
|
|
65330
65368
|
};
|
|
65369
|
+
const refuseUnreachableCards = async (req, res, cardIds) => {
|
|
65370
|
+
const ids2 = [...new Set(cardIds.map((id) => String(id)))];
|
|
65371
|
+
const cards = await cardSitesSvc(ids2);
|
|
65372
|
+
const { canReach } = await siteReachOf(req);
|
|
65373
|
+
const reached = await Promise.all(cards.map((card) => canReach(card)));
|
|
65374
|
+
if (cards.length !== ids2.length || reached.includes(false)) {
|
|
65375
|
+
res.status(404).json({ data: null, message: "Card not found." });
|
|
65376
|
+
return true;
|
|
65377
|
+
}
|
|
65378
|
+
return false;
|
|
65379
|
+
};
|
|
65380
|
+
const refuseUnreachableUnit = async (req, res, unitId) => {
|
|
65381
|
+
const unit = await unitSiteSvc(unitId);
|
|
65382
|
+
const { canReach } = await siteReachOf(req);
|
|
65383
|
+
if (!await canReach(unit)) {
|
|
65384
|
+
res.status(404).json({ data: null, message: "Unit not found." });
|
|
65385
|
+
return true;
|
|
65386
|
+
}
|
|
65387
|
+
return false;
|
|
65388
|
+
};
|
|
65331
65389
|
const {
|
|
65332
65390
|
addPhysicalCardSvc,
|
|
65333
65391
|
addNonPhysicalCardSvc,
|
|
@@ -65336,6 +65394,8 @@ function useAccessManagementController() {
|
|
|
65336
65394
|
accessGroupsSvc,
|
|
65337
65395
|
setCache,
|
|
65338
65396
|
getCache,
|
|
65397
|
+
cardSitesSvc,
|
|
65398
|
+
unitSiteSvc,
|
|
65339
65399
|
accessManagementSettingsSvc,
|
|
65340
65400
|
allAccessCardsCountsSvc,
|
|
65341
65401
|
availableAccessCardsSvc,
|
|
@@ -65555,6 +65615,8 @@ function useAccessManagementController() {
|
|
|
65555
65615
|
const accessManagementSettings = async (req, res) => {
|
|
65556
65616
|
try {
|
|
65557
65617
|
const settings = req.body;
|
|
65618
|
+
if (await refuseUnreachableSite(req, res, settings?.site))
|
|
65619
|
+
return;
|
|
65558
65620
|
const result = await accessManagementSettingsSvc(settings);
|
|
65559
65621
|
return res.status(201).json({ message: "Success", data: result });
|
|
65560
65622
|
} catch (error) {
|
|
@@ -65854,6 +65916,8 @@ function useAccessManagementController() {
|
|
|
65854
65916
|
if (error) {
|
|
65855
65917
|
return res.status(400).json({ message: error.message });
|
|
65856
65918
|
}
|
|
65919
|
+
if (await refuseUnreachableCards(req, res, nfcList.map((nfc) => nfc._id)))
|
|
65920
|
+
return;
|
|
65857
65921
|
const result = await updateNFCStatusSvc({ nfcList, visitorId });
|
|
65858
65922
|
return res.status(200).json({ message: "Success", data: result });
|
|
65859
65923
|
} catch (error) {
|
|
@@ -65906,6 +65970,10 @@ function useAccessManagementController() {
|
|
|
65906
65970
|
if (error) {
|
|
65907
65971
|
return res.status(400).json({ message: error.message });
|
|
65908
65972
|
}
|
|
65973
|
+
if (await refuseUnreachableCards(req, res, [cardId, issuedCardId]))
|
|
65974
|
+
return;
|
|
65975
|
+
if (await refuseUnreachableUnit(req, res, unitId))
|
|
65976
|
+
return;
|
|
65909
65977
|
const result = await cardReplacementSvc({
|
|
65910
65978
|
cardId,
|
|
65911
65979
|
remarks,
|
|
@@ -66110,6 +66178,8 @@ function useAccessManagementController() {
|
|
|
66110
66178
|
if (error) {
|
|
66111
66179
|
return res.status(400).json({ message: error.message });
|
|
66112
66180
|
}
|
|
66181
|
+
if (await refuseUnreachableCards(req, res, [cardId]))
|
|
66182
|
+
return;
|
|
66113
66183
|
const result = await deleteCardSvc({ cardId, remarks });
|
|
66114
66184
|
return res.status(200).json({ message: "Success", data: result });
|
|
66115
66185
|
} catch (error) {
|
|
@@ -66329,6 +66399,8 @@ function useAccessManagementController() {
|
|
|
66329
66399
|
if (error) {
|
|
66330
66400
|
return res.status(400).json({ message: error.message });
|
|
66331
66401
|
}
|
|
66402
|
+
if (await refuseUnreachableCards(req, res, [cardId]))
|
|
66403
|
+
return;
|
|
66332
66404
|
const result = await signQrCodeSvc({ cardId, purpose });
|
|
66333
66405
|
return res.status(200).json({ message: "Success", data: result });
|
|
66334
66406
|
} catch (error) {
|
|
@@ -66355,6 +66427,8 @@ function useAccessManagementController() {
|
|
|
66355
66427
|
if (error) {
|
|
66356
66428
|
return res.status(400).json({ message: error.message });
|
|
66357
66429
|
}
|
|
66430
|
+
if (await refuseUnreachableCards(req, res, cards.map((card) => card.cardId)))
|
|
66431
|
+
return;
|
|
66358
66432
|
const result = await checkoutVisitorSvc({ cards });
|
|
66359
66433
|
return res.status(200).json({ message: "Success", data: result });
|
|
66360
66434
|
} catch (error) {
|
|
@@ -66434,6 +66508,10 @@ function useAccessManagementController() {
|
|
|
66434
66508
|
if (error) {
|
|
66435
66509
|
throw new Error(`${error.message}`);
|
|
66436
66510
|
}
|
|
66511
|
+
if (await refuseUnreachableUnit(req, res, unit))
|
|
66512
|
+
return;
|
|
66513
|
+
if (id && await refuseUnreachableCards(req, res, [id]))
|
|
66514
|
+
return;
|
|
66437
66515
|
const result = await assignMultipleCardsSvc({
|
|
66438
66516
|
assignees,
|
|
66439
66517
|
unit,
|