@7365admin1/core 3.52.16 → 3.52.18
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/CHANGELOG.md +39 -0
- package/dist/index.js +25 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +25 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/harness.mjs +5 -2
- package/test/e2e/patrol-email-scope.e2e.test.mjs +0 -1
- package/test/e2e/subscription-read-scope.e2e.test.mjs +182 -0
- package/test/e2e/user-email-lookup-leak.e2e.test.mjs +68 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
# @iservice365/core
|
|
2
2
|
|
|
3
|
+
## 3.52.18
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 5f38ea7: Narrow the account-by-e-mail lookup to identity only, and scope the two open subscription reads
|
|
8
|
+
|
|
9
|
+
`GET /api/users/email/:email` and its v2 twin `GET /api/users/v2/email/:email`
|
|
10
|
+
stripped the password hash and session id from the reply but answered every
|
|
11
|
+
other stored field, so any signed-in account could read any other account's
|
|
12
|
+
NRIC, contact number, date of birth, gender, default organisation, status and
|
|
13
|
+
profile just by knowing the e-mail address — across every client on the
|
|
14
|
+
platform. Both now answer `{_id, name, email}` and nothing else. An
|
|
15
|
+
organisation gate would have been the wrong fix: this endpoint exists for the
|
|
16
|
+
invite flow, where the person being looked up is deliberately not in the
|
|
17
|
+
caller's organisation yet.
|
|
18
|
+
|
|
19
|
+
`GET /api/subscriptions/org/:id` answered any organisation's billing record —
|
|
20
|
+
plan, seat count, price, currency, renewal date — to any signed-in account, and
|
|
21
|
+
`GET /api/subscriptions/` answered every subscription on the platform in one
|
|
22
|
+
list. They now carry `requireOrgAccess` and `requirePlatformStaff`, the two
|
|
23
|
+
gates already used elsewhere in the same file.
|
|
24
|
+
|
|
25
|
+
## 3.52.17
|
|
26
|
+
|
|
27
|
+
### Patch Changes
|
|
28
|
+
|
|
29
|
+
- edf3a60: Restore and extend the site scoping on the patrol-log email endpoints.
|
|
30
|
+
|
|
31
|
+
#1967 added a `requireSiteReach` guard to `POST /api/patrol-logs/email`. #1981,
|
|
32
|
+
branched before #1967 landed, rewrote the same controller to add the history
|
|
33
|
+
endpoints and dropped the guard. Neither repo runs its tests in CI, so the e2e
|
|
34
|
+
test #1967 shipped has been failing on `main` unnoticed ever since.
|
|
35
|
+
|
|
36
|
+
All five endpoints now resolve the caller from the session: the two that name a
|
|
37
|
+
site (`send`, `getAll`) check that site, and the three that name a record
|
|
38
|
+
(`resend`, `getById`, `deleteById`) check the site stored on the record. The
|
|
39
|
+
`createdBy` pinning is restored with them, so a send cannot be filed under
|
|
40
|
+
another user's name.
|
|
41
|
+
|
|
3
42
|
## 3.52.16
|
|
4
43
|
|
|
5
44
|
### Patch Changes
|
package/dist/index.js
CHANGED
|
@@ -18680,11 +18680,11 @@ async function requireUserFieldWrite(req, userId, field) {
|
|
|
18680
18680
|
}
|
|
18681
18681
|
|
|
18682
18682
|
// src/utils/user-response.util.ts
|
|
18683
|
-
function
|
|
18683
|
+
function publicIdentity(user) {
|
|
18684
18684
|
if (!user || typeof user !== "object")
|
|
18685
18685
|
return user;
|
|
18686
|
-
const {
|
|
18687
|
-
return
|
|
18686
|
+
const { _id, name, email } = user;
|
|
18687
|
+
return { _id, name, email };
|
|
18688
18688
|
}
|
|
18689
18689
|
|
|
18690
18690
|
// src/controllers/user.controller.ts
|
|
@@ -18776,7 +18776,7 @@ function useUserController() {
|
|
|
18776
18776
|
return;
|
|
18777
18777
|
}
|
|
18778
18778
|
const user = await _getByEmail(email);
|
|
18779
|
-
res.json(
|
|
18779
|
+
res.json(publicIdentity(user));
|
|
18780
18780
|
return;
|
|
18781
18781
|
} catch (error2) {
|
|
18782
18782
|
import_node_server_utils43.logger.log({ level: "error", message: `${error2.message}` });
|
|
@@ -31692,6 +31692,7 @@ function useSubscriptionController() {
|
|
|
31692
31692
|
return;
|
|
31693
31693
|
}
|
|
31694
31694
|
try {
|
|
31695
|
+
await requireOrgAccess(req, _id);
|
|
31695
31696
|
const data = await _getByOrgId(_id);
|
|
31696
31697
|
res.json(data);
|
|
31697
31698
|
return;
|
|
@@ -31718,6 +31719,7 @@ function useSubscriptionController() {
|
|
|
31718
31719
|
const page = parseInt(req.query.page ?? "1");
|
|
31719
31720
|
const status = req.query.status ?? "active";
|
|
31720
31721
|
try {
|
|
31722
|
+
await requirePlatformStaff(req);
|
|
31721
31723
|
const data = await _getSubscriptions({ search, page, status });
|
|
31722
31724
|
res.json(data);
|
|
31723
31725
|
return;
|
|
@@ -61485,10 +61487,20 @@ function usePatrolEmailController() {
|
|
|
61485
61487
|
getById: _getById,
|
|
61486
61488
|
deleteById: _deleteById
|
|
61487
61489
|
} = usePatrolEmailService();
|
|
61490
|
+
async function requirePatrolEmailReach(req, site) {
|
|
61491
|
+
await requireSiteReach(req, site);
|
|
61492
|
+
}
|
|
61493
|
+
async function requireRecordReach(req, id) {
|
|
61494
|
+
const record = await _getById(id);
|
|
61495
|
+
await requirePatrolEmailReach(req, record?.site);
|
|
61496
|
+
return record;
|
|
61497
|
+
}
|
|
61488
61498
|
async function send2(req, res, next) {
|
|
61489
|
-
const
|
|
61490
|
-
|
|
61491
|
-
|
|
61499
|
+
const actor = await resolveInviteActor(callerId(req));
|
|
61500
|
+
const { error, value } = schemaSendPatrolEmail.validate(
|
|
61501
|
+
{ ...req.body, createdBy: { _id: actor.id, name: actor.name } },
|
|
61502
|
+
{ abortEarly: false }
|
|
61503
|
+
);
|
|
61492
61504
|
if (error) {
|
|
61493
61505
|
const messages = error.details.map((d) => d.message).join(", ");
|
|
61494
61506
|
import_node_server_utils163.logger.log({ level: "error", message: messages });
|
|
@@ -61496,6 +61508,7 @@ function usePatrolEmailController() {
|
|
|
61496
61508
|
return;
|
|
61497
61509
|
}
|
|
61498
61510
|
try {
|
|
61511
|
+
await requirePatrolEmailReach(req, value.site);
|
|
61499
61512
|
const cookieHeader = req.headers.cookie;
|
|
61500
61513
|
const data = await _send({
|
|
61501
61514
|
site: value.site,
|
|
@@ -61539,6 +61552,7 @@ function usePatrolEmailController() {
|
|
|
61539
61552
|
return;
|
|
61540
61553
|
}
|
|
61541
61554
|
try {
|
|
61555
|
+
await requireRecordReach(req, params.value.id);
|
|
61542
61556
|
const data = await _resend({
|
|
61543
61557
|
id: params.value.id,
|
|
61544
61558
|
createdBy: value.createdBy,
|
|
@@ -61566,6 +61580,7 @@ function usePatrolEmailController() {
|
|
|
61566
61580
|
return;
|
|
61567
61581
|
}
|
|
61568
61582
|
try {
|
|
61583
|
+
await requirePatrolEmailReach(req, value.site);
|
|
61569
61584
|
res.json(await _getAll(value));
|
|
61570
61585
|
return;
|
|
61571
61586
|
} catch (err) {
|
|
@@ -61585,7 +61600,7 @@ function usePatrolEmailController() {
|
|
|
61585
61600
|
return;
|
|
61586
61601
|
}
|
|
61587
61602
|
try {
|
|
61588
|
-
res.json({ data: await
|
|
61603
|
+
res.json({ data: await requireRecordReach(req, value.id) });
|
|
61589
61604
|
return;
|
|
61590
61605
|
} catch (err) {
|
|
61591
61606
|
import_node_server_utils163.logger.log({ level: "error", message: `${err.message}` });
|
|
@@ -61604,6 +61619,7 @@ function usePatrolEmailController() {
|
|
|
61604
61619
|
return;
|
|
61605
61620
|
}
|
|
61606
61621
|
try {
|
|
61622
|
+
await requireRecordReach(req, value.id);
|
|
61607
61623
|
res.json({ message: await _deleteById(value.id) });
|
|
61608
61624
|
return;
|
|
61609
61625
|
} catch (err) {
|
|
@@ -86080,7 +86096,7 @@ function useUserControllerV2() {
|
|
|
86080
86096
|
return rejectValidation(error, next);
|
|
86081
86097
|
try {
|
|
86082
86098
|
const user = await _getUserByEmail(value);
|
|
86083
|
-
res.json(
|
|
86099
|
+
res.json(publicIdentity(user));
|
|
86084
86100
|
return;
|
|
86085
86101
|
} catch (err) {
|
|
86086
86102
|
import_node_server_utils269.logger.log({ level: "error", message: `${err.message}` });
|