@helpio/common 1.0.4 → 1.0.6
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/build/index.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export * from "./types/auth";
|
|
|
8
8
|
export * from "./middlewares/current-user";
|
|
9
9
|
export * from "./middlewares/error-handler";
|
|
10
10
|
export * from "./middlewares/require-auth";
|
|
11
|
+
export * from "./middlewares/require-role";
|
|
11
12
|
export * from "./middlewares/validate-request";
|
|
12
13
|
export * from "./events/consumer";
|
|
13
14
|
export * from "./events/producer";
|
package/build/index.js
CHANGED
|
@@ -21,6 +21,7 @@ __exportStar(require("./types/auth"), exports);
|
|
|
21
21
|
__exportStar(require("./middlewares/current-user"), exports);
|
|
22
22
|
__exportStar(require("./middlewares/error-handler"), exports);
|
|
23
23
|
__exportStar(require("./middlewares/require-auth"), exports);
|
|
24
|
+
__exportStar(require("./middlewares/require-role"), exports);
|
|
24
25
|
__exportStar(require("./middlewares/validate-request"), exports);
|
|
25
26
|
__exportStar(require("./events/consumer"), exports);
|
|
26
27
|
__exportStar(require("./events/producer"), exports);
|
|
@@ -5,14 +5,35 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.currentUser = void 0;
|
|
7
7
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
|
+
const getJwtSecret = () => {
|
|
9
|
+
return process.env.JWT_SECRET || process.env.JWT_KEY;
|
|
10
|
+
};
|
|
11
|
+
const extractAccessToken = (req) => {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
const authHeader = req.headers.authorization;
|
|
14
|
+
const bearer = typeof authHeader === "string" && authHeader.startsWith("Bearer ")
|
|
15
|
+
? authHeader.substring(7)
|
|
16
|
+
: undefined;
|
|
17
|
+
const cookieToken = (_a = req.cookies) === null || _a === void 0 ? void 0 : _a.accessToken;
|
|
18
|
+
const legacySessionToken = (_b = req.session) === null || _b === void 0 ? void 0 : _b.jwt;
|
|
19
|
+
const token = bearer || cookieToken || legacySessionToken;
|
|
20
|
+
return typeof token === "string" && token.trim() ? token.trim() : undefined;
|
|
21
|
+
};
|
|
22
|
+
const attachPayload = (req, payload) => {
|
|
23
|
+
req.currentUser = payload;
|
|
24
|
+
req.userId = payload.userId || payload.id;
|
|
25
|
+
req.sessionId = payload.sessionId;
|
|
26
|
+
};
|
|
8
27
|
const currentUser = (req, res, next) => {
|
|
9
|
-
|
|
10
|
-
if (!
|
|
28
|
+
const token = extractAccessToken(req);
|
|
29
|
+
if (!token)
|
|
30
|
+
return next();
|
|
31
|
+
const secret = getJwtSecret();
|
|
32
|
+
if (!secret)
|
|
11
33
|
return next();
|
|
12
|
-
}
|
|
13
34
|
try {
|
|
14
|
-
const payload = jsonwebtoken_1.default.verify(
|
|
15
|
-
req
|
|
35
|
+
const payload = jsonwebtoken_1.default.verify(token, secret);
|
|
36
|
+
attachPayload(req, payload);
|
|
16
37
|
}
|
|
17
38
|
catch (err) { }
|
|
18
39
|
next();
|
|
@@ -6,42 +6,47 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.optionalAuth = exports.requireAuth = void 0;
|
|
7
7
|
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
8
8
|
const not_authorized_error_1 = require("../errors/not-authorized-error");
|
|
9
|
-
const
|
|
9
|
+
const getJwtSecret = () => {
|
|
10
|
+
const secret = process.env.JWT_SECRET || process.env.JWT_KEY;
|
|
11
|
+
if (!secret) {
|
|
12
|
+
throw new Error("JWT_SECRET must be defined");
|
|
13
|
+
}
|
|
14
|
+
return secret;
|
|
15
|
+
};
|
|
16
|
+
const extractAccessToken = (req) => {
|
|
17
|
+
var _a, _b;
|
|
18
|
+
const authHeader = req.headers.authorization;
|
|
19
|
+
const bearer = typeof authHeader === "string" && authHeader.startsWith("Bearer ")
|
|
20
|
+
? authHeader.substring(7)
|
|
21
|
+
: undefined;
|
|
22
|
+
const cookieToken = (_a = req.cookies) === null || _a === void 0 ? void 0 : _a.accessToken;
|
|
23
|
+
const legacySessionToken = (_b = req.session) === null || _b === void 0 ? void 0 : _b.jwt;
|
|
24
|
+
const token = bearer || cookieToken || legacySessionToken;
|
|
25
|
+
return typeof token === "string" && token.trim() ? token.trim() : undefined;
|
|
26
|
+
};
|
|
27
|
+
const attachPayload = (req, payload) => {
|
|
28
|
+
req.currentUser = payload;
|
|
29
|
+
req.userId = payload.userId || payload.id;
|
|
30
|
+
req.sessionId = payload.sessionId;
|
|
31
|
+
};
|
|
10
32
|
/**
|
|
11
33
|
* Middleware: Require authentication
|
|
12
34
|
* Verifies JWT access token and attaches user payload to request
|
|
13
35
|
* Works across all microservices
|
|
14
36
|
*/
|
|
15
37
|
const requireAuth = (req, res, next) => {
|
|
16
|
-
var _a;
|
|
17
38
|
try {
|
|
18
|
-
|
|
19
|
-
const authHeader = req.headers.authorization;
|
|
20
|
-
const token = (authHeader === null || authHeader === void 0 ? void 0 : authHeader.startsWith("Bearer "))
|
|
21
|
-
? authHeader.substring(7)
|
|
22
|
-
: (_a = req.cookies) === null || _a === void 0 ? void 0 : _a.accessToken;
|
|
39
|
+
const token = extractAccessToken(req);
|
|
23
40
|
// Check if token exists
|
|
24
41
|
if (!token) {
|
|
25
|
-
console.log("[requireAuth] No token provided");
|
|
26
42
|
throw new not_authorized_error_1.NotAuthorizedError();
|
|
27
43
|
}
|
|
28
44
|
// Verify token
|
|
29
|
-
const payload = jsonwebtoken_1.default.verify(token,
|
|
30
|
-
|
|
31
|
-
userId: payload.userId,
|
|
32
|
-
id: payload.id,
|
|
33
|
-
email: payload.email,
|
|
34
|
-
hasAccountNumber: !!payload.accountNumber
|
|
35
|
-
});
|
|
36
|
-
// Attach user payload to request
|
|
37
|
-
req.currentUser = payload;
|
|
38
|
-
// Support both legacy 'id' and new 'userId' formats
|
|
39
|
-
req.userId = payload.userId || payload.id;
|
|
40
|
-
req.sessionId = payload.sessionId;
|
|
45
|
+
const payload = jsonwebtoken_1.default.verify(token, getJwtSecret());
|
|
46
|
+
attachPayload(req, payload);
|
|
41
47
|
next();
|
|
42
48
|
}
|
|
43
49
|
catch (err) {
|
|
44
|
-
console.error("[requireAuth] Error:", err.message, err.name);
|
|
45
50
|
if (err.name === "TokenExpiredError") {
|
|
46
51
|
return res.status(401).json({
|
|
47
52
|
error: "TOKEN_EXPIRED",
|
|
@@ -67,20 +72,13 @@ exports.requireAuth = requireAuth;
|
|
|
67
72
|
* Loads user if token is present, but doesn't require it
|
|
68
73
|
*/
|
|
69
74
|
const optionalAuth = (req, res, next) => {
|
|
70
|
-
var _a;
|
|
71
75
|
try {
|
|
72
|
-
const
|
|
73
|
-
const token = (authHeader === null || authHeader === void 0 ? void 0 : authHeader.startsWith("Bearer "))
|
|
74
|
-
? authHeader.substring(7)
|
|
75
|
-
: (_a = req.cookies) === null || _a === void 0 ? void 0 : _a.accessToken;
|
|
76
|
+
const token = extractAccessToken(req);
|
|
76
77
|
if (!token) {
|
|
77
78
|
return next();
|
|
78
79
|
}
|
|
79
|
-
const payload = jsonwebtoken_1.default.verify(token,
|
|
80
|
-
req
|
|
81
|
-
// Support both legacy 'id' and new 'userId' formats
|
|
82
|
-
req.userId = payload.userId || payload.id;
|
|
83
|
-
req.sessionId = payload.sessionId;
|
|
80
|
+
const payload = jsonwebtoken_1.default.verify(token, getJwtSecret());
|
|
81
|
+
attachPayload(req, payload);
|
|
84
82
|
next();
|
|
85
83
|
}
|
|
86
84
|
catch (error) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Request, Response, NextFunction } from "express";
|
|
2
|
+
export declare const requireAnyRole: (allowedRoles: string[]) => (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
|
3
|
+
export declare const requireWorker: (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
|
4
|
+
export declare const requireEmployer: (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
|
5
|
+
export declare const requireOwner: (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
|
6
|
+
export declare const requireEmployerOrOwner: (req: Request, res: Response, next: NextFunction) => void | Response<any, Record<string, any>>;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requireEmployerOrOwner = exports.requireOwner = exports.requireEmployer = exports.requireWorker = exports.requireAnyRole = void 0;
|
|
4
|
+
const normalizeRole = (value) => {
|
|
5
|
+
if (typeof value !== "string")
|
|
6
|
+
return undefined;
|
|
7
|
+
const trimmed = value.trim();
|
|
8
|
+
return trimmed ? trimmed.toLowerCase() : undefined;
|
|
9
|
+
};
|
|
10
|
+
const getRoleCandidates = (req) => {
|
|
11
|
+
const currentUser = req.currentUser;
|
|
12
|
+
if (!currentUser)
|
|
13
|
+
return [];
|
|
14
|
+
const directRole = normalizeRole(currentUser.role);
|
|
15
|
+
const rolesArray = Array.isArray(currentUser.roles)
|
|
16
|
+
? currentUser.roles.map(normalizeRole).filter(Boolean)
|
|
17
|
+
: [];
|
|
18
|
+
const activeMode = normalizeRole(currentUser.activeMode);
|
|
19
|
+
return [directRole, activeMode, ...rolesArray].filter(Boolean);
|
|
20
|
+
};
|
|
21
|
+
const requireAnyRole = (allowedRoles) => {
|
|
22
|
+
const allowed = allowedRoles.map((r) => r.toLowerCase());
|
|
23
|
+
return (req, res, next) => {
|
|
24
|
+
const candidates = getRoleCandidates(req);
|
|
25
|
+
if (candidates.some((r) => allowed.includes(r))) {
|
|
26
|
+
return next();
|
|
27
|
+
}
|
|
28
|
+
return res.status(403).send({
|
|
29
|
+
error: "FORBIDDEN",
|
|
30
|
+
message: `Required role: ${allowedRoles.join(" | ")}`,
|
|
31
|
+
});
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
exports.requireAnyRole = requireAnyRole;
|
|
35
|
+
exports.requireWorker = (0, exports.requireAnyRole)(["worker"]);
|
|
36
|
+
exports.requireEmployer = (0, exports.requireAnyRole)(["employer"]);
|
|
37
|
+
// Owner/admin access varies across deployments, so we accept a few common values.
|
|
38
|
+
exports.requireOwner = (0, exports.requireAnyRole)(["owner", "admin", "super_admin"]);
|
|
39
|
+
exports.requireEmployerOrOwner = (0, exports.requireAnyRole)([
|
|
40
|
+
"employer",
|
|
41
|
+
"owner",
|
|
42
|
+
"admin",
|
|
43
|
+
"super_admin",
|
|
44
|
+
]);
|