@7365admin1/core 3.52.6 → 3.52.7-staging.253

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,15 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Scope the NFC patrol tag, route and settings endpoints to the caller's own estate.
6
+
7
+ `/api/nfc-patrol-tag`, `/api/nfc-patrol-route` and `/api/nfc-patrol-settings`
8
+ carried `requireAuth` and nothing more, and their three controllers held no
9
+ authorization identifier of any kind, so any signed-in account on the platform
10
+ could read and CHANGE another client's checkpoint register, patrol rounds and
11
+ patrol settings. They now ask the same `requireSiteReach` -> `entitleSite`
12
+ question the already-scoped `/api/nfc-patrol-log` and the rest of the
13
+ site-scoped modules ask, and answer `404 Site not found.` The five `/public`
14
+ mounts, which are reached without a credential while `ENFORCE_NFC_PUBLIC_AUTH`
15
+ is off, are unchanged.
package/dist/index.d.ts CHANGED
@@ -7662,6 +7662,41 @@ declare function useNfcPatrolTagService(): {
7662
7662
  updateNfcPatrolTagBySite: (updateType: "Configure" | "Reset" | "Edit", data: TNfcPatrolTagUpdateData) => Promise<string>;
7663
7663
  };
7664
7664
 
7665
+ /**
7666
+ * Who may see, or change, one estate's patrol TAGS.
7667
+ *
7668
+ * An NFC patrol tag is the physical disc screwed to a wall at a checkpoint. The
7669
+ * row here is what maps the disc's UID to the checkpoint it stands for, so it is
7670
+ * what turns a guard's tap into proof that they were at that spot.
7671
+ *
7672
+ * Every route on `/api/nfc-patrol-tag` carried `requireAuth` and nothing more,
7673
+ * and this controller held no authorization identifier of any kind, so being
7674
+ * signed in anywhere on the platform was enough to list another client's
7675
+ * checkpoint register, read one outright, add a tag to their estate, or - the
7676
+ * sharp one - `Configure`/`Reset`/`Edit` an existing tag. Re-pointing a tag is
7677
+ * not a read: the disc on the wall now stands for a different checkpoint, so a
7678
+ * guard who walks the whole round is recorded as having missed part of it, or a
7679
+ * guard who never left the lobby is recorded as having walked it.
7680
+ *
7681
+ * The estate is the scope and the rule is the existing `requireSiteReach` ->
7682
+ * `entitleSite` that `/api/nfc-patrol-log` and the rest already use. No new
7683
+ * mechanism.
7684
+ *
7685
+ * - `POST /` names its site in the body (required by the schema it validates).
7686
+ * - `GET /` names its site in the query (required).
7687
+ * - `GET /:id` names only a record, so the site is read off the STORED tag.
7688
+ * - `PUT /` names its site in the body (`schemaNfcPatrolTagUpdateData` has
7689
+ * `site` required) and the site is part of the repository's FILTER in all
7690
+ * three update types (`{ site, tagID }` for Configure and Reset, `{ _id,
7691
+ * site }` for Edit), so a caller cannot name their own site and reach
7692
+ * somebody else's row: checking the body's site is the whole of it.
7693
+ *
7694
+ * `GET /` and `PUT /` are ALSO mounted at `/public` behind
7695
+ * `requireSessionOrLegacyToken`, which is why they use
7696
+ * `requireSiteReachIfSignedIn` - see that function for what stays open until
7697
+ * `ENFORCE_NFC_PUBLIC_AUTH` is turned on. On the `requireAuth` mounts, which
7698
+ * always populate `req.user`, it is the unconditional check.
7699
+ */
7665
7700
  declare function useNfcPatrolTagController(): {
7666
7701
  add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
7667
7702
  getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -8200,6 +8235,46 @@ declare function useNfcPatrolRouteService(): {
8200
8235
  updateById: (id: string, data: TNfcPatrolRouteEdit) => Promise<string>;
8201
8236
  };
8202
8237
 
8238
+ /**
8239
+ * Who may see, or change, one estate's patrol ROUTES.
8240
+ *
8241
+ * A patrol route is the round itself: which checkpoints a guard must tap, in
8242
+ * what order, on which days, starting at what times, and how many minutes late
8243
+ * counts as late. It is the instruction the guard app reads and the standard the
8244
+ * patrol log is graded against.
8245
+ *
8246
+ * Every route on `/api/nfc-patrol-route` carried `requireAuth` and nothing more,
8247
+ * and this controller held no authorization identifier of any kind.
8248
+ * `requireAuth` proves a session exists; it makes no organisation or site
8249
+ * decision. So being signed in anywhere on the platform was enough to read
8250
+ * another client's rounds, add a round to their estate, or rewrite an existing
8251
+ * one - and rewriting a round is not a read: drop its checkpoints and the
8252
+ * estate's guards stop walking past the places the client is paying to have
8253
+ * watched, while every patrol log still reports a clean sheet.
8254
+ *
8255
+ * The estate is the scope, and the rule is the existing `requireSiteReach` ->
8256
+ * `entitleSite` that `/api/nfc-patrol-log`, `/api/occurrence-books`,
8257
+ * `/api/work-orders`, `/api/feedbacks` and the rest already use. No new
8258
+ * mechanism is introduced. The `customer.sites` branch is load-bearing here as
8259
+ * it is on the patrol log: the people who walk and supervise these rounds are
8260
+ * the contracted security agency's staff and hold no membership in the estate's
8261
+ * own organisation.
8262
+ *
8263
+ * - `POST /` names its site in the body (`schemaNfcPatrolRoute` has `site`
8264
+ * required), so the guard checks a site the request already names.
8265
+ * - `GET /` names its site in the query (required by the query schema).
8266
+ * - `GET /id/:id` names only a record, so the site is read off the STORED
8267
+ * route.
8268
+ * - `PATCH /id/:id` is checked TWICE, because `$set: value` includes `site`
8269
+ * and the filter is `{ _id }` alone - so this route can MOVE a round to
8270
+ * another estate. Both the round's current site and the destination site in
8271
+ * the body must be reachable, or a caller could park their own site's round
8272
+ * on somebody else's estate (or drag one of theirs onto ours).
8273
+ *
8274
+ * The two reads use `requireSiteReachIfSignedIn` because they are mounted
8275
+ * behind `requireSessionOrLegacyToken`, not `requireAuth` - see that function
8276
+ * for why, and for what stays open until `ENFORCE_NFC_PUBLIC_AUTH` is turned on.
8277
+ */
8203
8278
  declare function useNfcPatrolRouteController(): {
8204
8279
  add: (req: Request, res: Response, next: NextFunction) => Promise<void>;
8205
8280
  getAllBySite: (req: Request, res: Response, next: NextFunction) => Promise<void>;
@@ -8496,6 +8571,27 @@ declare function useNfcPatrolSettingsService(): {
8496
8571
  updateNfcPatrolSettings: (site: string | ObjectId, value: TNfcPatrolSettingsUpdate) => Promise<string>;
8497
8572
  };
8498
8573
 
8574
+ /**
8575
+ * Who may see, or change, one estate's patrol SETTINGS.
8576
+ *
8577
+ * These settings decide how the estate's rounds are supervised: the reporting
8578
+ * addresses the patrol summaries go to, and the thresholds a round is graded
8579
+ * against. Both routes on `/api/nfc-patrol-settings` take the site straight out
8580
+ * of the URL and neither made any organisation or site decision, so being signed
8581
+ * in anywhere on the platform was enough to read another client's supervision
8582
+ * settings, or to rewrite them - which is a quiet way to stop an estate's patrol
8583
+ * reporting reaching the people who read it.
8584
+ *
8585
+ * The rule is the existing `requireSiteReach` -> `entitleSite` used by
8586
+ * `/api/nfc-patrol-log` and the rest. No new mechanism. Both routes name their
8587
+ * site in the URL, so the guard checks a site the request already names and no
8588
+ * legitimate caller's contract changes.
8589
+ *
8590
+ * The read uses `requireSiteReachIfSignedIn` because it is mounted behind
8591
+ * `requireSessionOrLegacyToken` rather than `requireAuth` - see that function
8592
+ * for what stays open until `ENFORCE_NFC_PUBLIC_AUTH` is turned on. The WRITE is
8593
+ * behind `requireAuth`, so it is scoped unconditionally.
8594
+ */
8499
8595
  declare function useNfcPatrolSettingsController(): {
8500
8596
  getNfcPatrolSettingsBySite: (req: Request, res: Response, next: NextFunction) => Promise<void>;
8501
8597
  updateNfcPatrolSettings: (req: Request, res: Response, next: NextFunction) => Promise<void>;
package/dist/index.js CHANGED
@@ -26426,6 +26426,11 @@ async function siteReachOf(req) {
26426
26426
  }
26427
26427
  return { actor, canReach, only };
26428
26428
  }
26429
+ async function requireSiteReachIfSignedIn(req, site) {
26430
+ if (!req.user)
26431
+ return;
26432
+ await requireSiteReach(req, site);
26433
+ }
26429
26434
 
26430
26435
  // src/controllers/member.controller.ts
26431
26436
  async function requireMemberOrg(req, org) {
@@ -70236,6 +70241,7 @@ function useNfcPatrolTagController() {
70236
70241
  return;
70237
70242
  }
70238
70243
  try {
70244
+ await requireSiteReachIfSignedIn(req, value.site);
70239
70245
  const data = await _add(value);
70240
70246
  res.status(201).json(data);
70241
70247
  return;
@@ -70265,6 +70271,7 @@ function useNfcPatrolTagController() {
70265
70271
  const limit = parseInt(req.query.limit ?? "10");
70266
70272
  const site = req.query.site ?? "";
70267
70273
  try {
70274
+ await requireSiteReachIfSignedIn(req, site);
70268
70275
  const data = await _getAll({
70269
70276
  page,
70270
70277
  limit,
@@ -70295,6 +70302,7 @@ function useNfcPatrolTagController() {
70295
70302
  return;
70296
70303
  }
70297
70304
  try {
70305
+ await requireSiteReachIfSignedIn(req, payload.site);
70298
70306
  const { updateType, ...restBody } = payload;
70299
70307
  const result = await _updateNfcPatrolTagBySite(
70300
70308
  payload.updateType,
@@ -70323,6 +70331,7 @@ function useNfcPatrolTagController() {
70323
70331
  }
70324
70332
  try {
70325
70333
  const tag = await _getById(req.params.id);
70334
+ await requireSiteReachIfSignedIn(req, tag?.site);
70326
70335
  res.status(200).json(tag);
70327
70336
  return;
70328
70337
  } catch (error2) {
@@ -73745,6 +73754,7 @@ function useNfcPatrolRouteController() {
73745
73754
  return;
73746
73755
  }
73747
73756
  try {
73757
+ await requireSiteReachIfSignedIn(req, value.site);
73748
73758
  const data = await _add(value);
73749
73759
  res.status(201).json(data);
73750
73760
  return;
@@ -73778,6 +73788,7 @@ function useNfcPatrolRouteController() {
73778
73788
  const search = req.query.search ?? "";
73779
73789
  const filter = req.query.filter ?? "";
73780
73790
  try {
73791
+ await requireSiteReachIfSignedIn(req, site);
73781
73792
  const data = await _getAllBySite({
73782
73793
  page,
73783
73794
  limit,
@@ -73810,6 +73821,7 @@ function useNfcPatrolRouteController() {
73810
73821
  }
73811
73822
  try {
73812
73823
  const nfcPatrolRoute = await _getById(value?.id, value?.isStart);
73824
+ await requireSiteReachIfSignedIn(req, nfcPatrolRoute?.site);
73813
73825
  if (!nfcPatrolRoute) {
73814
73826
  throw new import_node_server_utils218.NotFoundError("NFC Patrol Route not found.");
73815
73827
  }
@@ -73831,6 +73843,9 @@ function useNfcPatrolRouteController() {
73831
73843
  ) : {};
73832
73844
  value.updatedBy = cookies["user"] || "";
73833
73845
  try {
73846
+ const existing = await _getById(id);
73847
+ await requireSiteReachIfSignedIn(req, existing?.site);
73848
+ await requireSiteReachIfSignedIn(req, value?.site);
73834
73849
  const result = await _updateById(id, value);
73835
73850
  res.json(result);
73836
73851
  return;
@@ -75425,6 +75440,7 @@ function useNfcPatrolSettingsController() {
75425
75440
  return;
75426
75441
  }
75427
75442
  try {
75443
+ await requireSiteReachIfSignedIn(req, site);
75428
75444
  const data = await _getNfcPatrolSettingsBySite(site);
75429
75445
  res.json(data);
75430
75446
  return;
@@ -75444,6 +75460,7 @@ function useNfcPatrolSettingsController() {
75444
75460
  const updatedBy = cookies["user"] || "";
75445
75461
  payload.updatedBy = updatedBy;
75446
75462
  try {
75463
+ await requireSiteReachIfSignedIn(req, site);
75447
75464
  await _updateNfcPatrolSettings(site, payload);
75448
75465
  res.json({ message: "NFC patrol settings updated successfully." });
75449
75466
  return;