@epztickets/common 1.48.0 → 1.48.1
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,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ForbiddenError = void 0;
|
|
4
|
+
const custom_error_1 = require("./custom-error");
|
|
5
|
+
// 403 — the request is authenticated but the caller is not allowed to
|
|
6
|
+
// perform this action. Use this (not NotAuthorizedError) for role-based
|
|
7
|
+
// gates (requireOwner, requireAdmin) and per-resource ownership checks
|
|
8
|
+
// (e.g. "this room belongs to a different user").
|
|
9
|
+
//
|
|
10
|
+
// Why a separate error class from NotAuthorizedError (401):
|
|
11
|
+
//
|
|
12
|
+
// 401 means "we couldn't identify you" — your JWT is missing, expired, or
|
|
13
|
+
// malformed. The reasonable client response is to drop the session and ask
|
|
14
|
+
// the user to sign in again, which is what the frontend's axios
|
|
15
|
+
// interceptor does.
|
|
16
|
+
//
|
|
17
|
+
// 403 means "we know who you are but this isn't yours / your role can't
|
|
18
|
+
// do this". Forcing a re-signin would be hostile (the user's session is
|
|
19
|
+
// fine) and pointless (signing in again won't grant the missing role).
|
|
20
|
+
// The client should surface a normal error message instead and leave the
|
|
21
|
+
// session intact.
|
|
22
|
+
//
|
|
23
|
+
// HTTP RFC 9110 §15.5.4 ("the request was valid, but the server is
|
|
24
|
+
// refusing action; re-authenticating will make no difference") matches
|
|
25
|
+
// our intent here.
|
|
26
|
+
class ForbiddenError extends custom_error_1.CustomError {
|
|
27
|
+
constructor(message = "Forbidden") {
|
|
28
|
+
super(message);
|
|
29
|
+
this.message = message;
|
|
30
|
+
this.statusCode = 403;
|
|
31
|
+
Object.setPrototypeOf(this, ForbiddenError.prototype);
|
|
32
|
+
}
|
|
33
|
+
serializeErrors() {
|
|
34
|
+
return [{ message: this.message }];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.ForbiddenError = ForbiddenError;
|
package/build/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from "./errors/bad-request-error";
|
|
|
2
2
|
export * from "./errors/custom-error";
|
|
3
3
|
export * from "./errors/database-connection-error";
|
|
4
4
|
export * from "./errors/not-authorized-error";
|
|
5
|
+
export * from "./errors/forbidden-error";
|
|
5
6
|
export * from "./errors/not-found-error";
|
|
6
7
|
export * from "./errors/request-validation-error";
|
|
7
8
|
export * from "./middlewares/current-user";
|
package/build/index.js
CHANGED
|
@@ -19,6 +19,7 @@ __exportStar(require("./errors/bad-request-error"), exports);
|
|
|
19
19
|
__exportStar(require("./errors/custom-error"), exports);
|
|
20
20
|
__exportStar(require("./errors/database-connection-error"), exports);
|
|
21
21
|
__exportStar(require("./errors/not-authorized-error"), exports);
|
|
22
|
+
__exportStar(require("./errors/forbidden-error"), exports);
|
|
22
23
|
__exportStar(require("./errors/not-found-error"), exports);
|
|
23
24
|
__exportStar(require("./errors/request-validation-error"), exports);
|
|
24
25
|
// middlewares
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.requireAdmin = void 0;
|
|
4
|
-
const
|
|
4
|
+
const forbidden_error_1 = require("../errors/forbidden-error");
|
|
5
|
+
// Role gate: caller must be an admin. See require-owner.ts for the
|
|
6
|
+
// rationale on ForbiddenError (403) vs NotAuthorizedError (401).
|
|
5
7
|
const requireAdmin = (req, res, next) => {
|
|
6
8
|
var _a;
|
|
7
9
|
if (((_a = req.currentUser) === null || _a === void 0 ? void 0 : _a.role) !== "admin") {
|
|
8
|
-
throw new
|
|
10
|
+
throw new forbidden_error_1.ForbiddenError("Admin access required");
|
|
9
11
|
}
|
|
10
12
|
next();
|
|
11
13
|
};
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.requireOwner = void 0;
|
|
4
|
-
const
|
|
4
|
+
const forbidden_error_1 = require("../errors/forbidden-error");
|
|
5
|
+
// Role gate: caller must be an owner or admin.
|
|
6
|
+
//
|
|
7
|
+
// Throws ForbiddenError (403) — NOT NotAuthorizedError (401) — when the
|
|
8
|
+
// user is signed in but doesn't hold the required role. The distinction
|
|
9
|
+
// matters end-to-end: the frontend axios interceptor force-signs-out on
|
|
10
|
+
// 401 (assuming the JWT is bad), but on 403 it lets the caller render
|
|
11
|
+
// a "you don't have access" message without destroying the session.
|
|
12
|
+
//
|
|
13
|
+
// If req.currentUser is missing entirely (no JWT, expired JWT, etc.),
|
|
14
|
+
// that's an authentication failure and should be caught upstream by
|
|
15
|
+
// requireAuth, which still throws NotAuthorizedError (401). This
|
|
16
|
+
// middleware assumes currentUser is populated.
|
|
5
17
|
const requireOwner = (req, res, next) => {
|
|
6
18
|
var _a, _b;
|
|
7
19
|
if (((_a = req.currentUser) === null || _a === void 0 ? void 0 : _a.role) !== "owner" && ((_b = req.currentUser) === null || _b === void 0 ? void 0 : _b.role) !== "admin") {
|
|
8
|
-
throw new
|
|
20
|
+
throw new forbidden_error_1.ForbiddenError("Owner access required");
|
|
9
21
|
}
|
|
10
22
|
next();
|
|
11
23
|
};
|