@innvoid/getmarket-sdk 0.1.8 → 0.1.9
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/dist/chunk-WKL4L67F.js +616 -0
- package/dist/chunk-WKL4L67F.js.map +1 -0
- package/dist/index.cjs +108 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +16 -281
- package/dist/index.js.map +1 -1
- package/dist/middlewares/index.cjs +258 -0
- package/dist/middlewares/index.cjs.map +1 -1
- package/dist/middlewares/index.d.cts +19 -2
- package/dist/middlewares/index.d.ts +19 -2
- package/dist/middlewares/index.js +7 -1
- package/package.json +1 -1
- package/dist/chunk-JXOLNJ7J.js +0 -224
- package/dist/chunk-JXOLNJ7J.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { CacheProvider, TwoLevelCache, TwoLevelCacheOptions, closeCache, getOrSet, getTwoLevelCache } from './cache/index.cjs';
|
|
2
2
|
export { AnyHeaders, ClientErrorCode, HttpClientOpts, InternalHttp, UpstreamError, createHttpClient, mapAxiosToUpstreamError, withRequestId, withRequestIdConfig } from './core/index.cjs';
|
|
3
3
|
export { HEADER_AUTHORIZATION, HEADER_BRANCH_UID, HEADER_COMPANY_UID, HEADER_EMPLOYEE_UID, HEADER_INTERNAL_API_KEY, HEADER_REQUEST_ID, RequestContext, getRequestContextFromHeaders } from './headers/index.cjs';
|
|
4
|
-
export { internalAuth, parseHeaders, requestId, requireAnyPermission, requireAuthContext, requirePermissions, requireRoles, requireRolesOrAnyPermission, sendError, sendOk } from './middlewares/index.cjs';
|
|
4
|
+
export { allowSysAdminOrAnyPermission, allowSysAdminOrPermissionsAll, allowSysAdminOrRoles, internalAuth, parseHeaders, requestId, requireAnyPermission, requireAuthContext, requirePermissions, requireRoles, requireRolesOrAnyPermission, sendError, sendOk } from './middlewares/index.cjs';
|
|
5
5
|
import { a as AuthMiddlewareOptions } from './types-CRECQuHp.cjs';
|
|
6
6
|
export { A as AuthContext, b as AuthSession, c as AuthSubject, H as HydrateInput, d as HydrateResult, e as Hydrator, T as TokenType } from './types-CRECQuHp.cjs';
|
|
7
7
|
import { Response, NextFunction } from 'express';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { CacheProvider, TwoLevelCache, TwoLevelCacheOptions, closeCache, getOrSet, getTwoLevelCache } from './cache/index.js';
|
|
2
2
|
export { AnyHeaders, ClientErrorCode, HttpClientOpts, InternalHttp, UpstreamError, createHttpClient, mapAxiosToUpstreamError, withRequestId, withRequestIdConfig } from './core/index.js';
|
|
3
3
|
export { HEADER_AUTHORIZATION, HEADER_BRANCH_UID, HEADER_COMPANY_UID, HEADER_EMPLOYEE_UID, HEADER_INTERNAL_API_KEY, HEADER_REQUEST_ID, RequestContext, getRequestContextFromHeaders } from './headers/index.js';
|
|
4
|
-
export { internalAuth, parseHeaders, requestId, requireAnyPermission, requireAuthContext, requirePermissions, requireRoles, requireRolesOrAnyPermission, sendError, sendOk } from './middlewares/index.js';
|
|
4
|
+
export { allowSysAdminOrAnyPermission, allowSysAdminOrPermissionsAll, allowSysAdminOrRoles, internalAuth, parseHeaders, requestId, requireAnyPermission, requireAuthContext, requirePermissions, requireRoles, requireRolesOrAnyPermission, sendError, sendOk } from './middlewares/index.js';
|
|
5
5
|
import { a as AuthMiddlewareOptions } from './types-CRECQuHp.js';
|
|
6
6
|
export { A as AuthContext, b as AuthSession, c as AuthSubject, H as HydrateInput, d as HydrateResult, e as Hydrator, T as TokenType } from './types-CRECQuHp.js';
|
|
7
7
|
import { Response, NextFunction } from 'express';
|
package/dist/index.js
CHANGED
|
@@ -13,16 +13,27 @@ import {
|
|
|
13
13
|
withRequestIdConfig
|
|
14
14
|
} from "./chunk-OSYBK5AN.js";
|
|
15
15
|
import {
|
|
16
|
+
allowSysAdminOrAnyPermission,
|
|
17
|
+
allowSysAdminOrPermissionsAll,
|
|
18
|
+
allowSysAdminOrRoles,
|
|
19
|
+
authCustomerAllowFirebase,
|
|
20
|
+
authCustomerRequired,
|
|
21
|
+
authEmployeeAllowFirebase,
|
|
22
|
+
authEmployeeRequired,
|
|
23
|
+
createAuthMiddleware,
|
|
24
|
+
createAuthMiddleware2,
|
|
16
25
|
internalAuth,
|
|
17
26
|
parseHeaders,
|
|
27
|
+
readRs256PublicKey,
|
|
18
28
|
requireAnyPermission,
|
|
19
29
|
requireAuthContext,
|
|
20
30
|
requirePermissions,
|
|
21
31
|
requireRoles,
|
|
22
32
|
requireRolesOrAnyPermission,
|
|
23
33
|
sendError,
|
|
24
|
-
sendOk
|
|
25
|
-
|
|
34
|
+
sendOk,
|
|
35
|
+
verifyBackendJwtRS256
|
|
36
|
+
} from "./chunk-WKL4L67F.js";
|
|
26
37
|
import {
|
|
27
38
|
requestId
|
|
28
39
|
} from "./chunk-KJ64O2EG.js";
|
|
@@ -35,285 +46,6 @@ import {
|
|
|
35
46
|
HEADER_REQUEST_ID,
|
|
36
47
|
getRequestContextFromHeaders
|
|
37
48
|
} from "./chunk-P2U3MT2E.js";
|
|
38
|
-
|
|
39
|
-
// src/auth/jwt.ts
|
|
40
|
-
import fs from "fs";
|
|
41
|
-
import jwt from "jsonwebtoken";
|
|
42
|
-
function readFileIfExists(path) {
|
|
43
|
-
if (!path) return null;
|
|
44
|
-
try {
|
|
45
|
-
const v = fs.readFileSync(path, "utf8").trim();
|
|
46
|
-
return v.length ? v : null;
|
|
47
|
-
} catch {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
function readRs256PublicKey() {
|
|
52
|
-
const fromFile = readFileIfExists(process.env.JWT_PUBLIC_KEY_PATH);
|
|
53
|
-
if (fromFile) return fromFile;
|
|
54
|
-
const fromEnv = String(process.env.AUTH_JWT_PUBLIC_KEY || process.env.AUTH_RSA_PUBLIC_KEY || "").replace(/\\n/g, "\n").trim();
|
|
55
|
-
if (fromEnv) return fromEnv;
|
|
56
|
-
throw new Error("Missing RS256 public key (JWT_PUBLIC_KEY_PATH / AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY)");
|
|
57
|
-
}
|
|
58
|
-
function verifyBackendJwtRS256(raw) {
|
|
59
|
-
const publicKey = readRs256PublicKey();
|
|
60
|
-
const audience = process.env.JWT_AUDIENCE || process.env.AUTH_JWT_AUDIENCE || "getmarket.api";
|
|
61
|
-
const issuer = process.env.JWT_ISSUER || process.env.AUTH_JWT_ISSUER || "getmarket-auth";
|
|
62
|
-
return jwt.verify(raw, publicKey, {
|
|
63
|
-
algorithms: ["RS256"],
|
|
64
|
-
audience,
|
|
65
|
-
issuer
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// src/auth/middleware.ts
|
|
70
|
-
function getBearerToken(req) {
|
|
71
|
-
const auth = String(req.headers?.authorization || "");
|
|
72
|
-
if (!auth.startsWith("Bearer ")) return null;
|
|
73
|
-
const token = auth.slice(7).trim();
|
|
74
|
-
return token.length ? token : null;
|
|
75
|
-
}
|
|
76
|
-
function normalizeUid(v) {
|
|
77
|
-
const s = String(v ?? "").trim();
|
|
78
|
-
return s.length ? s : null;
|
|
79
|
-
}
|
|
80
|
-
function createAuthMiddleware(opts) {
|
|
81
|
-
const { subject, allowFirebaseIdToken = false, requireSubject = true, hydrate } = opts;
|
|
82
|
-
return async (req, res, next) => {
|
|
83
|
-
const token = getBearerToken(req);
|
|
84
|
-
if (!token) {
|
|
85
|
-
return res.status(401).json({
|
|
86
|
-
ok: false,
|
|
87
|
-
code: "AUTH_MISSING_TOKEN",
|
|
88
|
-
message: "Missing Authorization Bearer token"
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
const headerCtx = req.context || {};
|
|
92
|
-
const company_uid = normalizeUid(headerCtx.company_uid);
|
|
93
|
-
const branch_uid = normalizeUid(headerCtx.branch_uid);
|
|
94
|
-
try {
|
|
95
|
-
const decoded = verifyBackendJwtRS256(token);
|
|
96
|
-
const baseCtx = {
|
|
97
|
-
tokenType: "backend",
|
|
98
|
-
subject,
|
|
99
|
-
company_uid: company_uid ?? void 0,
|
|
100
|
-
branch_uid: branch_uid ?? void 0,
|
|
101
|
-
roles: Array.isArray(decoded?.roles) ? decoded.roles : [],
|
|
102
|
-
permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],
|
|
103
|
-
denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],
|
|
104
|
-
session: {
|
|
105
|
-
jti: decoded?.jti,
|
|
106
|
-
device_id: decoded?.device_id,
|
|
107
|
-
expires_at: decoded?.exp
|
|
108
|
-
}
|
|
109
|
-
};
|
|
110
|
-
const hydrated = await hydrate({ decoded, req, subject, company_uid, branch_uid });
|
|
111
|
-
Object.assign(baseCtx, hydrated);
|
|
112
|
-
if (requireSubject) {
|
|
113
|
-
if (subject === "employee" && !baseCtx.employee) {
|
|
114
|
-
return res.status(401).json({
|
|
115
|
-
ok: false,
|
|
116
|
-
code: "AUTH_EMPLOYEE_NOT_FOUND",
|
|
117
|
-
message: "Employee not resolved by hydrator"
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
if (subject === "customer" && !baseCtx.customer) {
|
|
121
|
-
return res.status(401).json({
|
|
122
|
-
ok: false,
|
|
123
|
-
code: "AUTH_CUSTOMER_NOT_FOUND",
|
|
124
|
-
message: "Customer not resolved by hydrator"
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
req.auth = baseCtx;
|
|
129
|
-
return next();
|
|
130
|
-
} catch {
|
|
131
|
-
if (!allowFirebaseIdToken) {
|
|
132
|
-
return res.status(401).json({
|
|
133
|
-
ok: false,
|
|
134
|
-
code: "AUTH_INVALID_TOKEN",
|
|
135
|
-
message: "Invalid or expired token"
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
try {
|
|
139
|
-
const { default: admin2 } = await import("firebase-admin");
|
|
140
|
-
const firebaseDecoded = await admin2.auth().verifyIdToken(token);
|
|
141
|
-
if (firebaseDecoded.email && firebaseDecoded.email_verified === false) {
|
|
142
|
-
return res.status(401).json({
|
|
143
|
-
ok: false,
|
|
144
|
-
code: "AUTH_EMAIL_NOT_VERIFIED",
|
|
145
|
-
message: "Email not verified"
|
|
146
|
-
});
|
|
147
|
-
}
|
|
148
|
-
req.auth = {
|
|
149
|
-
tokenType: "backend",
|
|
150
|
-
subject,
|
|
151
|
-
firebase: firebaseDecoded,
|
|
152
|
-
company_uid: company_uid ?? void 0,
|
|
153
|
-
branch_uid: branch_uid ?? void 0,
|
|
154
|
-
companies: [],
|
|
155
|
-
roles: [],
|
|
156
|
-
permissions: [],
|
|
157
|
-
denied_permissions: []
|
|
158
|
-
};
|
|
159
|
-
return next();
|
|
160
|
-
} catch {
|
|
161
|
-
return res.status(401).json({
|
|
162
|
-
ok: false,
|
|
163
|
-
code: "AUTH_INVALID_TOKEN",
|
|
164
|
-
message: "Invalid or expired token"
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
// src/auth/authentication.ts
|
|
172
|
-
import admin from "firebase-admin";
|
|
173
|
-
import jwt2 from "jsonwebtoken";
|
|
174
|
-
import fs2 from "fs";
|
|
175
|
-
function getBearerToken2(req) {
|
|
176
|
-
const auth = String(req.headers?.authorization || "");
|
|
177
|
-
if (!auth.startsWith("Bearer ")) return null;
|
|
178
|
-
const token = auth.slice(7).trim();
|
|
179
|
-
return token.length ? token : null;
|
|
180
|
-
}
|
|
181
|
-
function readPublicKey() {
|
|
182
|
-
const publicKeyPath = process.env.JWT_PUBLIC_KEY_PATH;
|
|
183
|
-
const publicKeyEnv = process.env.AUTH_JWT_PUBLIC_KEY || process.env.AUTH_RSA_PUBLIC_KEY || "";
|
|
184
|
-
if (publicKeyPath) {
|
|
185
|
-
const v = fs2.readFileSync(publicKeyPath, "utf8").trim();
|
|
186
|
-
if (v) return v;
|
|
187
|
-
}
|
|
188
|
-
const envKey = publicKeyEnv.replace(/\\n/g, "\n").trim();
|
|
189
|
-
if (envKey) return envKey;
|
|
190
|
-
throw new Error(
|
|
191
|
-
"Missing RS256 public key (JWT_PUBLIC_KEY_PATH / AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY)"
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
function verifyBackendJwtRS2562(raw) {
|
|
195
|
-
const publicKey = readPublicKey();
|
|
196
|
-
const audience = process.env.JWT_AUDIENCE || process.env.AUTH_JWT_AUDIENCE || "getmarket.api";
|
|
197
|
-
const issuer = process.env.JWT_ISSUER || process.env.AUTH_JWT_ISSUER || "getmarket-auth";
|
|
198
|
-
return jwt2.verify(raw, publicKey, {
|
|
199
|
-
algorithms: ["RS256"],
|
|
200
|
-
audience,
|
|
201
|
-
issuer
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
function normalizeUid2(v) {
|
|
205
|
-
const s = String(v ?? "").trim();
|
|
206
|
-
return s.length ? s : null;
|
|
207
|
-
}
|
|
208
|
-
function deriveCompanyBranch(decoded, companyUid, branchUid) {
|
|
209
|
-
const companiesFromToken = Array.isArray(decoded?.companies) ? decoded.companies : [];
|
|
210
|
-
const company = decoded?.company ?? (companyUid ? companiesFromToken.find((c) => c?.uid === companyUid) : null) ?? null;
|
|
211
|
-
const branch = decoded?.branch ?? (branchUid && company?.branches ? (company.branches || []).find((b) => b?.uid === branchUid) : null) ?? null;
|
|
212
|
-
return { companiesFromToken, company, branch };
|
|
213
|
-
}
|
|
214
|
-
function createAuthMiddleware2(opts) {
|
|
215
|
-
const { subject, allowFirebaseIdToken = false } = opts;
|
|
216
|
-
return async (req, res, next) => {
|
|
217
|
-
const token = getBearerToken2(req);
|
|
218
|
-
if (!token) {
|
|
219
|
-
return res.status(401).json({
|
|
220
|
-
ok: false,
|
|
221
|
-
code: "AUTH_MISSING_TOKEN",
|
|
222
|
-
message: "Missing Authorization Bearer token"
|
|
223
|
-
});
|
|
224
|
-
}
|
|
225
|
-
try {
|
|
226
|
-
const decoded = verifyBackendJwtRS2562(token);
|
|
227
|
-
const headerCtx = req.context || {};
|
|
228
|
-
const companyUid = normalizeUid2(headerCtx.company_uid);
|
|
229
|
-
const branchUid = normalizeUid2(headerCtx.branch_uid);
|
|
230
|
-
const { companiesFromToken, company, branch } = deriveCompanyBranch(decoded, companyUid, branchUid);
|
|
231
|
-
const ctx = {
|
|
232
|
-
tokenType: "backend",
|
|
233
|
-
subject,
|
|
234
|
-
company_uid: companyUid ?? void 0,
|
|
235
|
-
branch_uid: branchUid ?? void 0,
|
|
236
|
-
companies: companiesFromToken,
|
|
237
|
-
company,
|
|
238
|
-
branch,
|
|
239
|
-
roles: Array.isArray(decoded?.roles) ? decoded.roles : [],
|
|
240
|
-
permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],
|
|
241
|
-
denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],
|
|
242
|
-
session: {
|
|
243
|
-
jti: decoded?.jti,
|
|
244
|
-
device_id: decoded?.device_id,
|
|
245
|
-
expires_at: decoded?.exp
|
|
246
|
-
}
|
|
247
|
-
};
|
|
248
|
-
if (subject === "employee") {
|
|
249
|
-
const employee = decoded?.employee ?? decoded?.user ?? null;
|
|
250
|
-
if (!employee) {
|
|
251
|
-
return res.status(401).json({
|
|
252
|
-
ok: false,
|
|
253
|
-
code: "AUTH_EMPLOYEE_NOT_FOUND",
|
|
254
|
-
message: "Employee not found in token"
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
ctx.employee = employee;
|
|
258
|
-
} else {
|
|
259
|
-
const customer = decoded?.customer ?? null;
|
|
260
|
-
if (!customer) {
|
|
261
|
-
return res.status(401).json({
|
|
262
|
-
ok: false,
|
|
263
|
-
code: "AUTH_CUSTOMER_NOT_FOUND",
|
|
264
|
-
message: "Customer not found in token"
|
|
265
|
-
});
|
|
266
|
-
}
|
|
267
|
-
ctx.customer = customer;
|
|
268
|
-
}
|
|
269
|
-
req.auth = ctx;
|
|
270
|
-
return next();
|
|
271
|
-
} catch {
|
|
272
|
-
if (!allowFirebaseIdToken) {
|
|
273
|
-
return res.status(401).json({
|
|
274
|
-
ok: false,
|
|
275
|
-
code: "AUTH_INVALID_TOKEN",
|
|
276
|
-
message: "Invalid or expired token"
|
|
277
|
-
});
|
|
278
|
-
}
|
|
279
|
-
try {
|
|
280
|
-
const firebaseDecoded = await admin.auth().verifyIdToken(token);
|
|
281
|
-
if (firebaseDecoded.email && firebaseDecoded.email_verified === false) {
|
|
282
|
-
return res.status(401).json({
|
|
283
|
-
ok: false,
|
|
284
|
-
code: "AUTH_EMAIL_NOT_VERIFIED",
|
|
285
|
-
message: "Email not verified"
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
const headerCtx = req.context || {};
|
|
289
|
-
const companyUid = normalizeUid2(headerCtx.company_uid);
|
|
290
|
-
const branchUid = normalizeUid2(headerCtx.branch_uid);
|
|
291
|
-
req.auth = {
|
|
292
|
-
tokenType: "backend",
|
|
293
|
-
subject,
|
|
294
|
-
firebase: firebaseDecoded,
|
|
295
|
-
company_uid: companyUid ?? void 0,
|
|
296
|
-
branch_uid: branchUid ?? void 0,
|
|
297
|
-
companies: [],
|
|
298
|
-
roles: [],
|
|
299
|
-
permissions: [],
|
|
300
|
-
denied_permissions: []
|
|
301
|
-
};
|
|
302
|
-
return next();
|
|
303
|
-
} catch {
|
|
304
|
-
return res.status(401).json({
|
|
305
|
-
ok: false,
|
|
306
|
-
code: "AUTH_INVALID_TOKEN",
|
|
307
|
-
message: "Invalid or expired token"
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
var authEmployeeRequired = createAuthMiddleware2({ subject: "employee", allowFirebaseIdToken: false });
|
|
314
|
-
var authCustomerRequired = createAuthMiddleware2({ subject: "customer", allowFirebaseIdToken: false });
|
|
315
|
-
var authEmployeeAllowFirebase = createAuthMiddleware2({ subject: "employee", allowFirebaseIdToken: true });
|
|
316
|
-
var authCustomerAllowFirebase = createAuthMiddleware2({ subject: "customer", allowFirebaseIdToken: true });
|
|
317
49
|
export {
|
|
318
50
|
HEADER_AUTHORIZATION,
|
|
319
51
|
HEADER_BRANCH_UID,
|
|
@@ -324,6 +56,9 @@ export {
|
|
|
324
56
|
InternalHttp,
|
|
325
57
|
TwoLevelCache,
|
|
326
58
|
UpstreamError,
|
|
59
|
+
allowSysAdminOrAnyPermission,
|
|
60
|
+
allowSysAdminOrPermissionsAll,
|
|
61
|
+
allowSysAdminOrRoles,
|
|
327
62
|
authCustomerAllowFirebase,
|
|
328
63
|
authCustomerRequired,
|
|
329
64
|
authEmployeeAllowFirebase,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth/jwt.ts","../src/auth/middleware.ts","../src/auth/authentication.ts"],"sourcesContent":["import fs from \"fs\";\nimport jwt, {JwtPayload} from \"jsonwebtoken\";\n\nfunction readFileIfExists(path?: string): string | null {\n if (!path) return null;\n try {\n const v = fs.readFileSync(path, \"utf8\").trim();\n return v.length ? v : null;\n } catch {\n return null;\n }\n}\n\n/**\n * ✅ Keys viven en getmarket-stack:\n * - JWT_PUBLIC_KEY_PATH=/run/secrets/jwtRS256.key.pub (recomendado)\n * - fallback env AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY\n */\nexport function readRs256PublicKey(): string {\n const fromFile = readFileIfExists(process.env.JWT_PUBLIC_KEY_PATH);\n if (fromFile) return fromFile;\n\n const fromEnv = String(process.env.AUTH_JWT_PUBLIC_KEY || process.env.AUTH_RSA_PUBLIC_KEY || \"\")\n .replace(/\\\\n/g, \"\\n\")\n .trim();\n\n if (fromEnv) return fromEnv;\n\n throw new Error(\"Missing RS256 public key (JWT_PUBLIC_KEY_PATH / AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY)\");\n}\n\nexport function verifyBackendJwtRS256(raw: string): JwtPayload {\n const publicKey = readRs256PublicKey();\n\n const audience = process.env.JWT_AUDIENCE || process.env.AUTH_JWT_AUDIENCE || \"getmarket.api\";\n const issuer = process.env.JWT_ISSUER || process.env.AUTH_JWT_ISSUER || \"getmarket-auth\";\n\n // ✅ SOLO RS256\n return jwt.verify(raw, publicKey, {\n algorithms: [\"RS256\"],\n audience,\n issuer,\n }) as JwtPayload;\n}\n","import type {NextFunction, Response} from \"express\";\nimport {verifyBackendJwtRS256} from \"./jwt\";\nimport type {AuthContext, AuthMiddlewareOptions} from \"./types\";\n\nfunction getBearerToken(req: any): string | null {\n const auth = String(req.headers?.authorization || \"\");\n if (!auth.startsWith(\"Bearer \")) return null;\n const token = auth.slice(7).trim();\n return token.length ? token : null;\n}\n\nfunction normalizeUid(v: any): string | null {\n const s = String(v ?? \"\").trim();\n return s.length ? s : null;\n}\n\n/**\n * ✅ Middleware estándar:\n * - Solo Authorization: Bearer\n * - Solo RS256\n * - Cero legacy\n * - Hidrata vía hook (OBLIGATORIO)\n */\nexport function createAuthMiddleware(opts: AuthMiddlewareOptions) {\n const {subject, allowFirebaseIdToken = false, requireSubject = true, hydrate} = opts;\n\n return async (req: any, res: Response, next: NextFunction) => {\n const token = getBearerToken(req);\n if (!token) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_MISSING_TOKEN\",\n message: \"Missing Authorization Bearer token\",\n });\n }\n\n // Contexto desde parseHeaders (SDK) -> req.context\n const headerCtx = (req as any).context || {};\n const company_uid = normalizeUid(headerCtx.company_uid);\n const branch_uid = normalizeUid(headerCtx.branch_uid);\n\n // 1) RS256 backend JWT\n try {\n const decoded: any = verifyBackendJwtRS256(token);\n\n const baseCtx: AuthContext = {\n tokenType: \"backend\",\n subject,\n company_uid: company_uid ?? undefined,\n branch_uid: branch_uid ?? undefined,\n roles: Array.isArray(decoded?.roles) ? decoded.roles : [],\n permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],\n denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],\n session: {\n jti: decoded?.jti,\n device_id: decoded?.device_id,\n expires_at: decoded?.exp,\n },\n };\n\n // ✅ hydrate obligatorio\n const hydrated = await hydrate({decoded, req, subject, company_uid, branch_uid});\n Object.assign(baseCtx, hydrated);\n\n if (requireSubject) {\n if (subject === \"employee\" && !baseCtx.employee) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMPLOYEE_NOT_FOUND\",\n message: \"Employee not resolved by hydrator\",\n });\n }\n if (subject === \"customer\" && !baseCtx.customer) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_CUSTOMER_NOT_FOUND\",\n message: \"Customer not resolved by hydrator\",\n });\n }\n }\n\n (req as any).auth = baseCtx;\n return next();\n } catch {\n // 2) Firebase opcional\n if (!allowFirebaseIdToken) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n\n try {\n const {default: admin} = await import(\"firebase-admin\");\n const firebaseDecoded = await admin.auth().verifyIdToken(token);\n\n if (firebaseDecoded.email && firebaseDecoded.email_verified === false) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMAIL_NOT_VERIFIED\",\n message: \"Email not verified\",\n });\n }\n\n (req as any).auth = {\n tokenType: \"backend\",\n subject,\n firebase: firebaseDecoded,\n company_uid: company_uid ?? undefined,\n branch_uid: branch_uid ?? undefined,\n companies: [],\n roles: [],\n permissions: [],\n denied_permissions: [],\n } satisfies AuthContext;\n\n return next();\n } catch {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n }\n };\n}\n","// packages/sdk/src/auth/authentication.ts\nimport type {NextFunction, Response} from \"express\";\nimport admin from \"firebase-admin\";\nimport jwt, {JwtPayload} from \"jsonwebtoken\";\nimport fs from \"fs\";\n\ntype Subject = \"employee\" | \"customer\";\ntype TokenType = \"backend\";\n\nexport interface AuthContext {\n tokenType: TokenType;\n subject: Subject;\n\n employee?: any;\n customer?: any;\n\n company_uid?: string;\n branch_uid?: string;\n\n company?: any;\n branch?: any;\n companies?: any[];\n\n roles?: string[];\n permissions?: string[];\n denied_permissions?: string[];\n\n session?: { jti?: string; device_id?: string; expires_at?: number };\n firebase?: admin.auth.DecodedIdToken;\n}\n\n/**\n * ✅ ÚNICO estándar:\n * - Authorization: Bearer <token>\n */\nfunction getBearerToken(req: any): string | null {\n const auth = String(req.headers?.authorization || \"\");\n if (!auth.startsWith(\"Bearer \")) return null;\n const token = auth.slice(7).trim();\n return token.length ? token : null;\n}\n\nfunction readPublicKey(): string {\n const publicKeyPath = process.env.JWT_PUBLIC_KEY_PATH;\n const publicKeyEnv = process.env.AUTH_JWT_PUBLIC_KEY || process.env.AUTH_RSA_PUBLIC_KEY || \"\";\n\n if (publicKeyPath) {\n const v = fs.readFileSync(publicKeyPath, \"utf8\").trim();\n if (v) return v;\n }\n\n const envKey = publicKeyEnv.replace(/\\\\n/g, \"\\n\").trim();\n if (envKey) return envKey;\n\n throw new Error(\n \"Missing RS256 public key (JWT_PUBLIC_KEY_PATH / AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY)\"\n );\n}\n\nfunction verifyBackendJwtRS256(raw: string): JwtPayload {\n const publicKey = readPublicKey();\n const audience = process.env.JWT_AUDIENCE || process.env.AUTH_JWT_AUDIENCE || \"getmarket.api\";\n const issuer = process.env.JWT_ISSUER || process.env.AUTH_JWT_ISSUER || \"getmarket-auth\";\n\n return jwt.verify(raw, publicKey, {\n algorithms: [\"RS256\"],\n audience,\n issuer,\n }) as JwtPayload;\n}\n\nfunction normalizeUid(v: any): string | null {\n const s = String(v ?? \"\").trim();\n return s.length ? s : null;\n}\n\nfunction deriveCompanyBranch(decoded: any, companyUid: string | null, branchUid: string | null) {\n const companiesFromToken = Array.isArray(decoded?.companies) ? decoded.companies : [];\n\n const company =\n decoded?.company ??\n (companyUid ? companiesFromToken.find((c: any) => c?.uid === companyUid) : null) ??\n null;\n\n const branch =\n decoded?.branch ??\n (branchUid && company?.branches ? (company.branches || []).find((b: any) => b?.uid === branchUid) : null) ??\n null;\n\n return {companiesFromToken, company, branch};\n}\n\nexport function createAuthMiddleware(opts: { subject: Subject; allowFirebaseIdToken?: boolean }) {\n const {subject, allowFirebaseIdToken = false} = opts;\n\n return async (req: any, res: Response, next: NextFunction) => {\n const token = getBearerToken(req);\n if (!token) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_MISSING_TOKEN\",\n message: \"Missing Authorization Bearer token\",\n });\n }\n\n try {\n const decoded: any = verifyBackendJwtRS256(token);\n\n const headerCtx = (req as any).context || {};\n const companyUid = normalizeUid(headerCtx.company_uid);\n const branchUid = normalizeUid(headerCtx.branch_uid);\n\n const {companiesFromToken, company, branch} = deriveCompanyBranch(decoded, companyUid, branchUid);\n\n const ctx: AuthContext = {\n tokenType: \"backend\",\n subject,\n\n company_uid: companyUid ?? undefined,\n branch_uid: branchUid ?? undefined,\n\n companies: companiesFromToken,\n company,\n branch,\n\n roles: Array.isArray(decoded?.roles) ? decoded.roles : [],\n permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],\n denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],\n\n session: {\n jti: decoded?.jti,\n device_id: decoded?.device_id,\n expires_at: decoded?.exp,\n },\n };\n\n if (subject === \"employee\") {\n const employee = decoded?.employee ?? decoded?.user ?? null;\n if (!employee) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMPLOYEE_NOT_FOUND\",\n message: \"Employee not found in token\",\n });\n }\n ctx.employee = employee;\n } else {\n const customer = decoded?.customer ?? null;\n if (!customer) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_CUSTOMER_NOT_FOUND\",\n message: \"Customer not found in token\",\n });\n }\n ctx.customer = customer;\n }\n\n req.auth = ctx; // runtime OK\n return next();\n } catch {\n if (!allowFirebaseIdToken) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n\n try {\n const firebaseDecoded = await admin.auth().verifyIdToken(token);\n\n if (firebaseDecoded.email && firebaseDecoded.email_verified === false) {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMAIL_NOT_VERIFIED\",\n message: \"Email not verified\",\n });\n }\n\n const headerCtx = (req as any).context || {};\n const companyUid = normalizeUid(headerCtx.company_uid);\n const branchUid = normalizeUid(headerCtx.branch_uid);\n\n req.auth = {\n tokenType: \"backend\",\n subject,\n firebase: firebaseDecoded,\n company_uid: companyUid ?? undefined,\n branch_uid: branchUid ?? undefined,\n companies: [],\n roles: [],\n permissions: [],\n denied_permissions: [],\n };\n\n return next();\n } catch {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_INVALID_TOKEN\",\n message: \"Invalid or expired token\",\n });\n }\n }\n };\n}\n\nexport const authEmployeeRequired = createAuthMiddleware({subject: \"employee\", allowFirebaseIdToken: false});\nexport const authCustomerRequired = createAuthMiddleware({subject: \"customer\", allowFirebaseIdToken: false});\nexport const authEmployeeAllowFirebase = createAuthMiddleware({subject: \"employee\", allowFirebaseIdToken: true});\nexport const authCustomerAllowFirebase = createAuthMiddleware({subject: \"customer\", allowFirebaseIdToken: true});\n"],"mappings":"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","names":["admin","jwt","fs","getBearerToken","verifyBackendJwtRS256","normalizeUid","createAuthMiddleware"]}
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -30,6 +30,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/middlewares/index.ts
|
|
31
31
|
var middlewares_exports = {};
|
|
32
32
|
__export(middlewares_exports, {
|
|
33
|
+
allowSysAdminOrAnyPermission: () => allowSysAdminOrAnyPermission,
|
|
34
|
+
allowSysAdminOrPermissionsAll: () => allowSysAdminOrPermissionsAll,
|
|
35
|
+
allowSysAdminOrRoles: () => allowSysAdminOrRoles,
|
|
33
36
|
internalAuth: () => internalAuth,
|
|
34
37
|
parseHeaders: () => parseHeaders,
|
|
35
38
|
requestId: () => requestId,
|
|
@@ -291,8 +294,263 @@ function requireRolesOrAnyPermission(roles, perms, options) {
|
|
|
291
294
|
return next();
|
|
292
295
|
};
|
|
293
296
|
}
|
|
297
|
+
|
|
298
|
+
// src/auth/jwt.ts
|
|
299
|
+
var import_jsonwebtoken = __toESM(require("jsonwebtoken"), 1);
|
|
300
|
+
|
|
301
|
+
// src/auth/authentication.ts
|
|
302
|
+
var import_firebase_admin = __toESM(require("firebase-admin"), 1);
|
|
303
|
+
var import_jsonwebtoken2 = __toESM(require("jsonwebtoken"), 1);
|
|
304
|
+
var import_fs2 = __toESM(require("fs"), 1);
|
|
305
|
+
function getBearerToken(req) {
|
|
306
|
+
const auth = String(req.headers?.authorization || "");
|
|
307
|
+
if (!auth.startsWith("Bearer ")) return null;
|
|
308
|
+
const token = auth.slice(7).trim();
|
|
309
|
+
return token.length ? token : null;
|
|
310
|
+
}
|
|
311
|
+
function readPublicKey() {
|
|
312
|
+
const publicKeyPath = process.env.JWT_PUBLIC_KEY_PATH;
|
|
313
|
+
const publicKeyEnv = process.env.AUTH_JWT_PUBLIC_KEY || process.env.AUTH_RSA_PUBLIC_KEY || "";
|
|
314
|
+
if (publicKeyPath) {
|
|
315
|
+
const v = import_fs2.default.readFileSync(publicKeyPath, "utf8").trim();
|
|
316
|
+
if (v) return v;
|
|
317
|
+
}
|
|
318
|
+
const envKey = publicKeyEnv.replace(/\\n/g, "\n").trim();
|
|
319
|
+
if (envKey) return envKey;
|
|
320
|
+
throw new Error(
|
|
321
|
+
"Missing RS256 public key (JWT_PUBLIC_KEY_PATH / AUTH_JWT_PUBLIC_KEY / AUTH_RSA_PUBLIC_KEY)"
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
function verifyBackendJwtRS2562(raw) {
|
|
325
|
+
const publicKey = readPublicKey();
|
|
326
|
+
const audience = process.env.JWT_AUDIENCE || process.env.AUTH_JWT_AUDIENCE || "getmarket.api";
|
|
327
|
+
const issuer = process.env.JWT_ISSUER || process.env.AUTH_JWT_ISSUER || "getmarket-auth";
|
|
328
|
+
return import_jsonwebtoken2.default.verify(raw, publicKey, {
|
|
329
|
+
algorithms: ["RS256"],
|
|
330
|
+
audience,
|
|
331
|
+
issuer
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
function normalizeUid(v) {
|
|
335
|
+
const s = String(v ?? "").trim();
|
|
336
|
+
return s.length ? s : null;
|
|
337
|
+
}
|
|
338
|
+
function deriveCompanyBranch(decoded, companyUid, branchUid) {
|
|
339
|
+
const companiesFromToken = Array.isArray(decoded?.companies) ? decoded.companies : [];
|
|
340
|
+
const company = decoded?.company ?? (companyUid ? companiesFromToken.find((c) => c?.uid === companyUid) : null) ?? null;
|
|
341
|
+
const branch = decoded?.branch ?? (branchUid && company?.branches ? (company.branches || []).find((b) => b?.uid === branchUid) : null) ?? null;
|
|
342
|
+
return { companiesFromToken, company, branch };
|
|
343
|
+
}
|
|
344
|
+
function createAuthMiddleware(opts) {
|
|
345
|
+
const { subject, allowFirebaseIdToken = false } = opts;
|
|
346
|
+
return async (req, res, next) => {
|
|
347
|
+
const token = getBearerToken(req);
|
|
348
|
+
if (!token) {
|
|
349
|
+
return res.status(401).json({
|
|
350
|
+
ok: false,
|
|
351
|
+
code: "AUTH_MISSING_TOKEN",
|
|
352
|
+
message: "Missing Authorization Bearer token"
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
try {
|
|
356
|
+
const decoded = verifyBackendJwtRS2562(token);
|
|
357
|
+
const headerCtx = req.context || {};
|
|
358
|
+
const companyUid = normalizeUid(headerCtx.company_uid);
|
|
359
|
+
const branchUid = normalizeUid(headerCtx.branch_uid);
|
|
360
|
+
const { companiesFromToken, company, branch } = deriveCompanyBranch(decoded, companyUid, branchUid);
|
|
361
|
+
const ctx = {
|
|
362
|
+
tokenType: "backend",
|
|
363
|
+
subject,
|
|
364
|
+
company_uid: companyUid ?? void 0,
|
|
365
|
+
branch_uid: branchUid ?? void 0,
|
|
366
|
+
companies: companiesFromToken,
|
|
367
|
+
company,
|
|
368
|
+
branch,
|
|
369
|
+
roles: Array.isArray(decoded?.roles) ? decoded.roles : [],
|
|
370
|
+
permissions: Array.isArray(decoded?.permissions) ? decoded.permissions : [],
|
|
371
|
+
denied_permissions: Array.isArray(decoded?.denied_permissions) ? decoded.denied_permissions : [],
|
|
372
|
+
session: {
|
|
373
|
+
jti: decoded?.jti,
|
|
374
|
+
device_id: decoded?.device_id,
|
|
375
|
+
expires_at: decoded?.exp
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
if (subject === "employee") {
|
|
379
|
+
const employee = decoded?.employee ?? decoded?.user ?? null;
|
|
380
|
+
if (!employee) {
|
|
381
|
+
return res.status(401).json({
|
|
382
|
+
ok: false,
|
|
383
|
+
code: "AUTH_EMPLOYEE_NOT_FOUND",
|
|
384
|
+
message: "Employee not found in token"
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
ctx.employee = employee;
|
|
388
|
+
} else {
|
|
389
|
+
const customer = decoded?.customer ?? null;
|
|
390
|
+
if (!customer) {
|
|
391
|
+
return res.status(401).json({
|
|
392
|
+
ok: false,
|
|
393
|
+
code: "AUTH_CUSTOMER_NOT_FOUND",
|
|
394
|
+
message: "Customer not found in token"
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
ctx.customer = customer;
|
|
398
|
+
}
|
|
399
|
+
req.auth = ctx;
|
|
400
|
+
return next();
|
|
401
|
+
} catch {
|
|
402
|
+
if (!allowFirebaseIdToken) {
|
|
403
|
+
return res.status(401).json({
|
|
404
|
+
ok: false,
|
|
405
|
+
code: "AUTH_INVALID_TOKEN",
|
|
406
|
+
message: "Invalid or expired token"
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
try {
|
|
410
|
+
const firebaseDecoded = await import_firebase_admin.default.auth().verifyIdToken(token);
|
|
411
|
+
if (firebaseDecoded.email && firebaseDecoded.email_verified === false) {
|
|
412
|
+
return res.status(401).json({
|
|
413
|
+
ok: false,
|
|
414
|
+
code: "AUTH_EMAIL_NOT_VERIFIED",
|
|
415
|
+
message: "Email not verified"
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
const headerCtx = req.context || {};
|
|
419
|
+
const companyUid = normalizeUid(headerCtx.company_uid);
|
|
420
|
+
const branchUid = normalizeUid(headerCtx.branch_uid);
|
|
421
|
+
req.auth = {
|
|
422
|
+
tokenType: "backend",
|
|
423
|
+
subject,
|
|
424
|
+
firebase: firebaseDecoded,
|
|
425
|
+
company_uid: companyUid ?? void 0,
|
|
426
|
+
branch_uid: branchUid ?? void 0,
|
|
427
|
+
companies: [],
|
|
428
|
+
roles: [],
|
|
429
|
+
permissions: [],
|
|
430
|
+
denied_permissions: []
|
|
431
|
+
};
|
|
432
|
+
return next();
|
|
433
|
+
} catch {
|
|
434
|
+
return res.status(401).json({
|
|
435
|
+
ok: false,
|
|
436
|
+
code: "AUTH_INVALID_TOKEN",
|
|
437
|
+
message: "Invalid or expired token"
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
var authEmployeeRequired = createAuthMiddleware({ subject: "employee", allowFirebaseIdToken: false });
|
|
444
|
+
var authCustomerRequired = createAuthMiddleware({ subject: "customer", allowFirebaseIdToken: false });
|
|
445
|
+
var authEmployeeAllowFirebase = createAuthMiddleware({ subject: "employee", allowFirebaseIdToken: true });
|
|
446
|
+
var authCustomerAllowFirebase = createAuthMiddleware({ subject: "customer", allowFirebaseIdToken: true });
|
|
447
|
+
|
|
448
|
+
// src/middlewares/guards.ts
|
|
449
|
+
function normalizeRole(r) {
|
|
450
|
+
if (!r) return null;
|
|
451
|
+
if (typeof r === "string") return r;
|
|
452
|
+
return r.code || r.name || null;
|
|
453
|
+
}
|
|
454
|
+
function normalizePerm(p) {
|
|
455
|
+
if (!p) return null;
|
|
456
|
+
if (typeof p === "string") return p;
|
|
457
|
+
return p.code || p.name || null;
|
|
458
|
+
}
|
|
459
|
+
function isSysAdmin2(roles) {
|
|
460
|
+
if (!Array.isArray(roles)) return false;
|
|
461
|
+
return roles.some((r) => normalizeRole(r) === "SYS_ADMIN");
|
|
462
|
+
}
|
|
463
|
+
function getAuth2(req) {
|
|
464
|
+
return req.auth ?? {};
|
|
465
|
+
}
|
|
466
|
+
function permissionSets(auth) {
|
|
467
|
+
const allow = new Set(
|
|
468
|
+
(auth.permissions ?? []).map(normalizePerm).filter(Boolean)
|
|
469
|
+
);
|
|
470
|
+
const deny = new Set(
|
|
471
|
+
(auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean)
|
|
472
|
+
);
|
|
473
|
+
return { allow, deny };
|
|
474
|
+
}
|
|
475
|
+
function allowSysAdminOrAnyPermission(...perms) {
|
|
476
|
+
const required = (perms ?? []).filter(Boolean);
|
|
477
|
+
return [
|
|
478
|
+
parseHeaders,
|
|
479
|
+
authEmployeeRequired,
|
|
480
|
+
(req, res, next) => {
|
|
481
|
+
const auth = getAuth2(req);
|
|
482
|
+
if (isSysAdmin2(auth.roles)) return next();
|
|
483
|
+
const { allow, deny } = permissionSets(auth);
|
|
484
|
+
for (const p of required) {
|
|
485
|
+
if (deny.has(p)) {
|
|
486
|
+
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
|
|
487
|
+
denied: p
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
const ok = required.some((p) => allow.has(p));
|
|
492
|
+
if (!ok) {
|
|
493
|
+
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", {
|
|
494
|
+
required
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
return next();
|
|
498
|
+
}
|
|
499
|
+
];
|
|
500
|
+
}
|
|
501
|
+
function allowSysAdminOrPermissionsAll(...perms) {
|
|
502
|
+
const required = (perms ?? []).filter(Boolean);
|
|
503
|
+
return [
|
|
504
|
+
parseHeaders,
|
|
505
|
+
authEmployeeRequired,
|
|
506
|
+
(req, res, next) => {
|
|
507
|
+
const auth = getAuth2(req);
|
|
508
|
+
if (isSysAdmin2(auth.roles)) return next();
|
|
509
|
+
const { allow, deny } = permissionSets(auth);
|
|
510
|
+
for (const p of required) {
|
|
511
|
+
if (deny.has(p)) {
|
|
512
|
+
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
|
|
513
|
+
denied: p
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
const missing = required.filter((p) => !allow.has(p));
|
|
518
|
+
if (missing.length) {
|
|
519
|
+
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", {
|
|
520
|
+
required,
|
|
521
|
+
missing
|
|
522
|
+
});
|
|
523
|
+
}
|
|
524
|
+
return next();
|
|
525
|
+
}
|
|
526
|
+
];
|
|
527
|
+
}
|
|
528
|
+
function allowSysAdminOrRoles(...roles) {
|
|
529
|
+
const required = (roles ?? []).filter(Boolean);
|
|
530
|
+
return [
|
|
531
|
+
parseHeaders,
|
|
532
|
+
authEmployeeRequired,
|
|
533
|
+
(req, res, next) => {
|
|
534
|
+
const auth = getAuth2(req);
|
|
535
|
+
if (isSysAdmin2(auth.roles)) return next();
|
|
536
|
+
const have = new Set(
|
|
537
|
+
(auth.roles ?? []).map(normalizeRole).filter(Boolean)
|
|
538
|
+
);
|
|
539
|
+
const ok = required.some((r) => have.has(r));
|
|
540
|
+
if (!ok) {
|
|
541
|
+
return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", {
|
|
542
|
+
required
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
return next();
|
|
546
|
+
}
|
|
547
|
+
];
|
|
548
|
+
}
|
|
294
549
|
// Annotate the CommonJS export names for ESM import in node:
|
|
295
550
|
0 && (module.exports = {
|
|
551
|
+
allowSysAdminOrAnyPermission,
|
|
552
|
+
allowSysAdminOrPermissionsAll,
|
|
553
|
+
allowSysAdminOrRoles,
|
|
296
554
|
internalAuth,
|
|
297
555
|
parseHeaders,
|
|
298
556
|
requestId,
|