@7365admin1/core 3.48.1-staging.196 → 3.48.1-staging.198
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/patrol-email-site-scope.md +5 -0
- package/.changeset/robot-site-scope.md +5 -0
- package/dist/index.js +25 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +25 -6
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/harness.mjs +25 -0
- package/test/e2e/patrol-email-scope.e2e.test.mjs +310 -0
- package/test/e2e/robot-scope.e2e.test.mjs +363 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the patrol log email route to its estate. `POST /api/patrol-logs/email` carried `requireAuth` and nothing more and the controller held no authorization identifier, so any signed-in account on the platform could name another client's site and that site's patrol log ids and have the report emailed — to a list of up to 25 addresses of their own choosing, from the platform's sending address. The service's own log-belongs-to-site check is internal consistency, not reach: name the other estate's site and its own logs and the two agree. Reach is now decided from the session, on the site named in the request body, before anything is read, recorded, rendered or sent. `createdBy` — the audit row for who emailed patrol logs out of the system — is taken from the session rather than from the request body.
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Scope the robot routes to their estate. `POST /api/robots` and `GET /api/robots/organization/:organization/site/:site` carried `requireAuth` and nothing more and the controller held no authorization identifier, so any signed-in account on the platform could page any estate's robot list — which projects `appKey` and `appToken`, the robot's credentials — and aim a robot registration at any estate. Reach is now decided from the session, on the site named in the request. A registration naming no estate is refused rather than falling through unscoped, and `createdBy` is taken from the session rather than from the request body.
|
package/dist/index.js
CHANGED
|
@@ -51619,15 +51619,25 @@ var import_joi70 = __toESM(require("joi"));
|
|
|
51619
51619
|
var import_node_server_utils143 = require("@7365admin1/node-server-utils");
|
|
51620
51620
|
function useRobotController() {
|
|
51621
51621
|
const { createRobot: _createRobot, getRobots: _getRobots } = useRobotService();
|
|
51622
|
+
async function requireRobotReach(req, site) {
|
|
51623
|
+
await requireSiteReach(req, site);
|
|
51624
|
+
}
|
|
51622
51625
|
async function createRobot(req, res, next) {
|
|
51623
|
-
const payload = { ...req.body };
|
|
51626
|
+
const payload = { ...req.body, createdBy: callerId(req) };
|
|
51624
51627
|
const { error } = robotSchema.validate(payload);
|
|
51625
51628
|
if (error) {
|
|
51626
51629
|
import_node_server_utils143.logger.log({ level: "error", message: error.message });
|
|
51627
51630
|
next(new import_node_server_utils143.BadRequestError(error.message));
|
|
51628
51631
|
return;
|
|
51629
51632
|
}
|
|
51633
|
+
if (!payload.metadata?.siteId) {
|
|
51634
|
+
const message = "metadata.siteId is required.";
|
|
51635
|
+
import_node_server_utils143.logger.log({ level: "error", message });
|
|
51636
|
+
next(new import_node_server_utils143.BadRequestError(message));
|
|
51637
|
+
return;
|
|
51638
|
+
}
|
|
51630
51639
|
try {
|
|
51640
|
+
await requireRobotReach(req, payload.metadata.siteId);
|
|
51631
51641
|
await _createRobot(payload);
|
|
51632
51642
|
res.status(201).json({ message: "Successfully created robot." });
|
|
51633
51643
|
return;
|
|
@@ -51666,6 +51676,7 @@ function useRobotController() {
|
|
|
51666
51676
|
const from = req.query.from ?? "";
|
|
51667
51677
|
const to = req.query.to ?? "";
|
|
51668
51678
|
try {
|
|
51679
|
+
await requireRobotReach(req, site);
|
|
51669
51680
|
const data = await _getRobots({
|
|
51670
51681
|
search,
|
|
51671
51682
|
page,
|
|
@@ -53595,9 +53606,12 @@ var schemaSendPatrolEmail = import_joi77.default.object({
|
|
|
53595
53606
|
"string.pattern.base": '"url" must be a root-relative path, for example "/org/site/patrol-logs/report?ids=..."'
|
|
53596
53607
|
}),
|
|
53597
53608
|
site: import_joi77.default.string().hex().length(24).required(),
|
|
53609
|
+
// Pinned from the session by the controller, never taken from the request.
|
|
53610
|
+
// `name` allows "" because it is denormalised from the account and an account
|
|
53611
|
+
// may hold none - the same shape `schemaPatrolEmailCreatedBy` already stores.
|
|
53598
53612
|
createdBy: import_joi77.default.object({
|
|
53599
53613
|
_id: import_joi77.default.string().hex().length(24).required(),
|
|
53600
|
-
name: import_joi77.default.string().trim().max(200).required()
|
|
53614
|
+
name: import_joi77.default.string().trim().max(200).required().allow("")
|
|
53601
53615
|
}).required()
|
|
53602
53616
|
});
|
|
53603
53617
|
function toObjectId15(value, label) {
|
|
@@ -54038,10 +54052,15 @@ function usePatrolEmailService() {
|
|
|
54038
54052
|
var import_node_server_utils159 = require("@7365admin1/node-server-utils");
|
|
54039
54053
|
function usePatrolEmailController() {
|
|
54040
54054
|
const { send: _send } = usePatrolEmailService();
|
|
54055
|
+
async function requirePatrolEmailReach(req, site) {
|
|
54056
|
+
await requireSiteReach(req, site);
|
|
54057
|
+
}
|
|
54041
54058
|
async function send2(req, res, next) {
|
|
54042
|
-
const
|
|
54043
|
-
|
|
54044
|
-
|
|
54059
|
+
const actor = await resolveInviteActor(callerId(req));
|
|
54060
|
+
const { error, value } = schemaSendPatrolEmail.validate(
|
|
54061
|
+
{ ...req.body, createdBy: { _id: actor.id, name: actor.name } },
|
|
54062
|
+
{ abortEarly: false }
|
|
54063
|
+
);
|
|
54045
54064
|
if (error) {
|
|
54046
54065
|
const messages = error.details.map((d) => d.message).join(", ");
|
|
54047
54066
|
import_node_server_utils159.logger.log({ level: "error", message: messages });
|
|
@@ -54049,6 +54068,7 @@ function usePatrolEmailController() {
|
|
|
54049
54068
|
return;
|
|
54050
54069
|
}
|
|
54051
54070
|
try {
|
|
54071
|
+
await requirePatrolEmailReach(req, value.site);
|
|
54052
54072
|
const cookieHeader = req.headers.cookie;
|
|
54053
54073
|
const data = await _send({
|
|
54054
54074
|
site: value.site,
|
|
@@ -54064,7 +54084,6 @@ function usePatrolEmailController() {
|
|
|
54064
54084
|
res.status(201).json({ message: "success", data });
|
|
54065
54085
|
return;
|
|
54066
54086
|
} catch (err) {
|
|
54067
|
-
console.log("err", err);
|
|
54068
54087
|
import_node_server_utils159.logger.log({ level: "error", message: `${err.message}` });
|
|
54069
54088
|
next(err);
|
|
54070
54089
|
return;
|