@7365admin1/core 3.48.1-staging.207 → 3.48.1-staging.209

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.
@@ -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
@@ -61151,7 +61151,7 @@ async function requireOwnUnit(req, site, unitId) {
61151
61151
  const db2 = import_node_server_utils190.useAtlas.getDb();
61152
61152
  if (!db2)
61153
61153
  throw new Error("Unable to connect to server.");
61154
- const own = await db2.collection("people").findOne({
61154
+ const own = await db2.collection("site.people").findOne({
61155
61155
  user: new import_mongodb119.ObjectId(actor.id),
61156
61156
  unit: new import_mongodb119.ObjectId(unit),
61157
61157
  site: new import_mongodb119.ObjectId(siteId),
@@ -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,