@innvoid/getmarket-sdk 0.1.9 → 0.1.11
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 → chunk-WK3P3MDA.js} +97 -38
- package/dist/chunk-WK3P3MDA.js.map +1 -0
- package/dist/index.cjs +97 -36
- 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 +5 -1
- package/dist/middlewares/index.cjs +97 -36
- package/dist/middlewares/index.cjs.map +1 -1
- package/dist/middlewares/index.d.cts +11 -3
- package/dist/middlewares/index.d.ts +11 -3
- package/dist/middlewares/index.js +5 -1
- package/package.json +1 -1
- package/dist/chunk-WKL4L67F.js.map +0 -1
|
@@ -379,6 +379,37 @@ function normalizeUid2(v) {
|
|
|
379
379
|
const s = String(v ?? "").trim();
|
|
380
380
|
return s.length ? s : null;
|
|
381
381
|
}
|
|
382
|
+
function normalizeCodes(list, kind) {
|
|
383
|
+
if (!Array.isArray(list)) return [];
|
|
384
|
+
const out = [];
|
|
385
|
+
for (const item of list) {
|
|
386
|
+
if (!item) continue;
|
|
387
|
+
if (typeof item === "string") {
|
|
388
|
+
const s2 = item.trim();
|
|
389
|
+
if (s2) out.push(s2);
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
const s = String(item.code || item.name || "").trim();
|
|
393
|
+
if (s) out.push(s);
|
|
394
|
+
}
|
|
395
|
+
return Array.from(new Set(out));
|
|
396
|
+
}
|
|
397
|
+
function extractEmployeeUid(decoded) {
|
|
398
|
+
const direct = normalizeUid2(decoded?.employee_uid);
|
|
399
|
+
if (direct) return direct;
|
|
400
|
+
const sub = normalizeUid2(decoded?.sub);
|
|
401
|
+
if (!sub) return null;
|
|
402
|
+
const m = /^emp:(.+)$/i.exec(sub);
|
|
403
|
+
return m?.[1] ? normalizeUid2(m[1]) : null;
|
|
404
|
+
}
|
|
405
|
+
function extractCustomerUid(decoded) {
|
|
406
|
+
const direct = normalizeUid2(decoded?.customer_uid);
|
|
407
|
+
if (direct) return direct;
|
|
408
|
+
const sub = normalizeUid2(decoded?.sub);
|
|
409
|
+
if (!sub) return null;
|
|
410
|
+
const m = /^cus:(.+)$/i.exec(sub);
|
|
411
|
+
return m?.[1] ? normalizeUid2(m[1]) : null;
|
|
412
|
+
}
|
|
382
413
|
function deriveCompanyBranch(decoded, companyUid, branchUid) {
|
|
383
414
|
const companiesFromToken = Array.isArray(decoded?.companies) ? decoded.companies : [];
|
|
384
415
|
const company = decoded?.company ?? (companyUid ? companiesFromToken.find((c) => c?.uid === companyUid) : null) ?? null;
|
|
@@ -410,9 +441,10 @@ function createAuthMiddleware2(opts) {
|
|
|
410
441
|
companies: companiesFromToken,
|
|
411
442
|
company,
|
|
412
443
|
branch,
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
444
|
+
// ✅ canonical string[]
|
|
445
|
+
roles: normalizeCodes(decoded?.roles, "role"),
|
|
446
|
+
permissions: normalizeCodes(decoded?.permissions, "perm"),
|
|
447
|
+
denied_permissions: normalizeCodes(decoded?.denied_permissions, "perm"),
|
|
416
448
|
session: {
|
|
417
449
|
jti: decoded?.jti,
|
|
418
450
|
device_id: decoded?.device_id,
|
|
@@ -420,25 +452,35 @@ function createAuthMiddleware2(opts) {
|
|
|
420
452
|
}
|
|
421
453
|
};
|
|
422
454
|
if (subject === "employee") {
|
|
423
|
-
const
|
|
424
|
-
|
|
455
|
+
const employeeUid = extractEmployeeUid(decoded);
|
|
456
|
+
const employeeEmbedded = decoded?.employee ?? decoded?.user ?? null;
|
|
457
|
+
if (employeeEmbedded) {
|
|
458
|
+
ctx.employee = employeeUid ? { ...employeeEmbedded, uid: employeeEmbedded?.uid ?? employeeUid } : employeeEmbedded;
|
|
459
|
+
} else if (employeeUid) {
|
|
460
|
+
ctx.employee = { uid: employeeUid };
|
|
461
|
+
} else {
|
|
425
462
|
return res.status(401).json({
|
|
426
463
|
ok: false,
|
|
427
464
|
code: "AUTH_EMPLOYEE_NOT_FOUND",
|
|
428
|
-
message: "Employee not found in token"
|
|
465
|
+
message: "Employee not found in token (expected employee_uid or sub=emp:<uid>)"
|
|
429
466
|
});
|
|
430
467
|
}
|
|
431
|
-
ctx.
|
|
468
|
+
ctx.employee_uid = employeeUid ?? void 0;
|
|
432
469
|
} else {
|
|
433
|
-
const
|
|
434
|
-
|
|
470
|
+
const customerUid = extractCustomerUid(decoded);
|
|
471
|
+
const customerEmbedded = decoded?.customer ?? null;
|
|
472
|
+
if (customerEmbedded) {
|
|
473
|
+
ctx.customer = customerUid ? { ...customerEmbedded, uid: customerEmbedded?.uid ?? customerUid } : customerEmbedded;
|
|
474
|
+
} else if (customerUid) {
|
|
475
|
+
ctx.customer = { uid: customerUid };
|
|
476
|
+
} else {
|
|
435
477
|
return res.status(401).json({
|
|
436
478
|
ok: false,
|
|
437
479
|
code: "AUTH_CUSTOMER_NOT_FOUND",
|
|
438
|
-
message: "Customer not found in token"
|
|
480
|
+
message: "Customer not found in token (expected customer_uid or sub=cus:<uid>)"
|
|
439
481
|
});
|
|
440
482
|
}
|
|
441
|
-
ctx.
|
|
483
|
+
ctx.customer_uid = customerUid ?? void 0;
|
|
442
484
|
}
|
|
443
485
|
req.auth = ctx;
|
|
444
486
|
return next();
|
|
@@ -508,14 +550,13 @@ function getAuth2(req) {
|
|
|
508
550
|
return req.auth ?? {};
|
|
509
551
|
}
|
|
510
552
|
function permissionSets(auth) {
|
|
511
|
-
const allow = new Set(
|
|
512
|
-
|
|
513
|
-
);
|
|
514
|
-
const deny = new Set(
|
|
515
|
-
(auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean)
|
|
516
|
-
);
|
|
553
|
+
const allow = new Set((auth.permissions ?? []).map(normalizePerm).filter(Boolean));
|
|
554
|
+
const deny = new Set((auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean));
|
|
517
555
|
return { allow, deny };
|
|
518
556
|
}
|
|
557
|
+
function roleSet(auth) {
|
|
558
|
+
return new Set((auth.roles ?? []).map(normalizeRole).filter(Boolean));
|
|
559
|
+
}
|
|
519
560
|
function allowSysAdminOrAnyPermission(...perms) {
|
|
520
561
|
const required = (perms ?? []).filter(Boolean);
|
|
521
562
|
return [
|
|
@@ -527,16 +568,12 @@ function allowSysAdminOrAnyPermission(...perms) {
|
|
|
527
568
|
const { allow, deny } = permissionSets(auth);
|
|
528
569
|
for (const p of required) {
|
|
529
570
|
if (deny.has(p)) {
|
|
530
|
-
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
|
|
531
|
-
denied: p
|
|
532
|
-
});
|
|
571
|
+
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, { denied: p });
|
|
533
572
|
}
|
|
534
573
|
}
|
|
535
574
|
const ok = required.some((p) => allow.has(p));
|
|
536
575
|
if (!ok) {
|
|
537
|
-
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", {
|
|
538
|
-
required
|
|
539
|
-
});
|
|
576
|
+
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", { required });
|
|
540
577
|
}
|
|
541
578
|
return next();
|
|
542
579
|
}
|
|
@@ -553,17 +590,12 @@ function allowSysAdminOrPermissionsAll(...perms) {
|
|
|
553
590
|
const { allow, deny } = permissionSets(auth);
|
|
554
591
|
for (const p of required) {
|
|
555
592
|
if (deny.has(p)) {
|
|
556
|
-
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
|
|
557
|
-
denied: p
|
|
558
|
-
});
|
|
593
|
+
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, { denied: p });
|
|
559
594
|
}
|
|
560
595
|
}
|
|
561
596
|
const missing = required.filter((p) => !allow.has(p));
|
|
562
597
|
if (missing.length) {
|
|
563
|
-
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", {
|
|
564
|
-
required,
|
|
565
|
-
missing
|
|
566
|
-
});
|
|
598
|
+
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", { required, missing });
|
|
567
599
|
}
|
|
568
600
|
return next();
|
|
569
601
|
}
|
|
@@ -577,19 +609,44 @@ function allowSysAdminOrRoles(...roles) {
|
|
|
577
609
|
(req, res, next) => {
|
|
578
610
|
const auth = getAuth2(req);
|
|
579
611
|
if (isSysAdmin2(auth.roles)) return next();
|
|
580
|
-
const have =
|
|
581
|
-
(auth.roles ?? []).map(normalizeRole).filter(Boolean)
|
|
582
|
-
);
|
|
612
|
+
const have = roleSet(auth);
|
|
583
613
|
const ok = required.some((r) => have.has(r));
|
|
584
614
|
if (!ok) {
|
|
585
|
-
return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", {
|
|
586
|
-
required
|
|
587
|
-
});
|
|
615
|
+
return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", { required });
|
|
588
616
|
}
|
|
589
617
|
return next();
|
|
590
618
|
}
|
|
591
619
|
];
|
|
592
620
|
}
|
|
621
|
+
function allowSysAdminOrRolesOrAnyPermission(roles, permissions) {
|
|
622
|
+
const requiredRoles = (Array.isArray(roles) ? roles : [roles]).filter(Boolean);
|
|
623
|
+
const requiredPerms = (Array.isArray(permissions) ? permissions : [permissions]).filter(Boolean);
|
|
624
|
+
return [
|
|
625
|
+
parseHeaders,
|
|
626
|
+
authEmployeeRequired,
|
|
627
|
+
(req, res, next) => {
|
|
628
|
+
const auth = getAuth2(req);
|
|
629
|
+
if (isSysAdmin2(auth.roles)) return next();
|
|
630
|
+
const { allow, deny } = permissionSets(auth);
|
|
631
|
+
for (const p of requiredPerms) {
|
|
632
|
+
if (deny.has(p)) {
|
|
633
|
+
return sendError(req, res, 403, "FORBIDDEN", `Denied: ${p}`, { permission: p });
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
const haveRoles = roleSet(auth);
|
|
637
|
+
if (requiredRoles.some((r) => haveRoles.has(r))) return next();
|
|
638
|
+
if (requiredPerms.some((p) => allow.has(p))) return next();
|
|
639
|
+
return sendError(req, res, 403, "FORBIDDEN", "Permission denied", {
|
|
640
|
+
roles: requiredRoles,
|
|
641
|
+
permissions: requiredPerms,
|
|
642
|
+
mode: "ROLES_OR_ANY_PERMISSION"
|
|
643
|
+
});
|
|
644
|
+
}
|
|
645
|
+
];
|
|
646
|
+
}
|
|
647
|
+
function allowAuthAdminOrPerm(permission) {
|
|
648
|
+
return allowSysAdminOrRolesOrAnyPermission(["AUTH_ADMIN"], [permission]);
|
|
649
|
+
}
|
|
593
650
|
|
|
594
651
|
export {
|
|
595
652
|
parseHeaders,
|
|
@@ -611,6 +668,8 @@ export {
|
|
|
611
668
|
authCustomerAllowFirebase,
|
|
612
669
|
allowSysAdminOrAnyPermission,
|
|
613
670
|
allowSysAdminOrPermissionsAll,
|
|
614
|
-
allowSysAdminOrRoles
|
|
671
|
+
allowSysAdminOrRoles,
|
|
672
|
+
allowSysAdminOrRolesOrAnyPermission,
|
|
673
|
+
allowAuthAdminOrPerm
|
|
615
674
|
};
|
|
616
|
-
//# sourceMappingURL=chunk-
|
|
675
|
+
//# sourceMappingURL=chunk-WK3P3MDA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/middlewares/parseHeaders.ts","../src/middlewares/internalAuth.ts","../src/middlewares/respond.ts","../src/middlewares/authorization.ts","../src/auth/jwt.ts","../src/auth/middleware.ts","../src/auth/authentication.ts","../src/middlewares/guards.ts"],"sourcesContent":["// sdk/src/middlewares/parseHeaders.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {getRequestContextFromHeaders} from \"../headers\";\n\n/**\n * ✅ NO-LEGACY / ESTÁNDAR:\n * - Lee SOLO x-company y x-branch (UIDs planos)\n * - Setea req.context = { company_uid, branch_uid }\n * - NO toca req.auth (auth lo setea authentication/requireAuth)\n */\nexport default function parseHeaders(req: Request, _res: Response, next: NextFunction) {\n (req as any).context = getRequestContextFromHeaders(req.headers as any);\n next();\n}\n","import type {Request, Response, NextFunction} from \"express\";\nimport fs from \"fs\";\nimport crypto from \"crypto\";\nimport {sendError} from \"./respond\";\nimport {HEADER_INTERNAL_API_KEY} from \"../headers\";\n\nfunction readSecretFile(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\nfunction splitKeys(v?: string | null): string[] {\n if (!v) return [];\n return v.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\nfunction getExpectedKeys(): string[] {\n const fileKey = readSecretFile(process.env.INTERNAL_API_KEY_FILE);\n const envKey = (process.env.INTERNAL_API_KEY || \"\").trim();\n const raw = fileKey || envKey;\n return splitKeys(raw);\n}\n\nfunction extractToken(req: Request): string | null {\n const apiKey = (req.header(HEADER_INTERNAL_API_KEY) || \"\").trim();\n return apiKey || null;\n}\n\nfunction safeEquals(a: string, b: string): boolean {\n const aa = Buffer.from(a);\n const bb = Buffer.from(b);\n if (aa.length !== bb.length) return false;\n return crypto.timingSafeEqual(aa, bb);\n}\n\nexport default function internalAuth(req: Request, res: Response, next: NextFunction) {\n const token = extractToken(req);\n\n if (!token) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", `Missing internal api key (${HEADER_INTERNAL_API_KEY})`);\n }\n\n const expectedKeys = getExpectedKeys();\n if (expectedKeys.length === 0) {\n return sendError(\n req,\n res,\n 500,\n \"MISCONFIGURED_INTERNAL_AUTH\",\n \"Internal api key not configured (INTERNAL_API_KEY or INTERNAL_API_KEY_FILE)\"\n );\n }\n\n const ok = expectedKeys.some((k) => safeEquals(token, k));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Invalid internal api key\");\n }\n\n return next();\n}\n","import type {Request, Response} from \"express\";\n\nexport function sendOk<T>(_req: Request, res: Response, data: T, statusCode = 200) {\n return res.status(statusCode).json({ok: true, data, requestId: res.locals?.requestId ?? null});\n}\n\nexport function sendError(\n _req: Request,\n res: Response,\n statusCode: number,\n code: string,\n message: string,\n details?: any\n) {\n return res.status(statusCode).json({\n ok: false,\n error: {code, message, ...(details !== undefined ? {details} : {})},\n requestId: res.locals?.requestId ?? null,\n });\n}\n","// packages/sdk/src/middlewares/authorization.ts\nimport type {Request, Response, NextFunction} from \"express\";\nimport {sendError} from \"./respond\";\n\ntype AuthRole = string | { code?: string; name?: string };\ntype AuthPermission = string | { code?: string; name?: string };\n\ntype AuthShape = {\n roles?: AuthRole[];\n permissions?: AuthPermission[];\n denied_permissions?: AuthPermission[];\n};\n\nfunction getAuth(req: Request): AuthShape {\n return ((req as any).auth ?? {}) as AuthShape;\n}\n\nfunction normalizeCode(v: any): string | null {\n if (!v) return null;\n if (typeof v === \"string\") return v;\n if (typeof v === \"object\") return v.code || v.name || null;\n return null;\n}\n\nfunction rolesSet(auth: AuthShape): Set<string> {\n const out = new Set<string>();\n for (const r of auth.roles || []) {\n const c = normalizeCode(r);\n if (c) out.add(c);\n }\n return out;\n}\n\nfunction permsSet(list?: AuthPermission[]): Set<string> {\n const out = new Set<string>();\n for (const p of list || []) {\n const c = normalizeCode(p);\n if (c) out.add(c);\n }\n return out;\n}\n\n/**\n * 401 si no existe req.auth (contexto auth).\n * Útil para proteger rutas donde SIEMPRE debe existir auth.\n */\nexport function requireAuthContext() {\n return (req: Request, res: Response, next: NextFunction) => {\n if (!(req as any).auth) {\n return sendError(req, res, 401, \"UNAUTHORIZED\", \"Missing auth context\");\n }\n return next();\n };\n}\n\n/**\n * Helper: SYS_ADMIN bypass (por defecto activo)\n */\nfunction isSysAdmin(auth: AuthShape, sysAdminRole: string) {\n const have = rolesSet(auth);\n return have.has(sysAdminRole);\n}\n\n/**\n * Requiere TODOS los permisos indicados.\n * Regla: denied_permissions siempre gana sobre permissions.\n *\n * options:\n * - sysAdminBypass: default true\n * - sysAdminRole: default \"SYS_ADMIN\"\n */\nexport function requirePermissions(\n perms: string[],\n options?: { sysAdminBypass?: boolean; sysAdminRole?: string }\n) {\n const sysAdminBypass = options?.sysAdminBypass !== false;\n const sysAdminRole = options?.sysAdminRole || \"SYS_ADMIN\";\n\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();\n\n const allow = permsSet(auth.permissions);\n const deny = permsSet(auth.denied_permissions);\n\n // deny gana siempre\n for (const p of perms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {\n denied: p,\n });\n }\n }\n\n const missing = perms.filter((p) => !allow.has(p));\n if (missing.length) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Missing permissions\", {\n missing,\n mode: \"ALL\",\n });\n }\n\n return next();\n };\n}\n\n/**\n * Requiere AL MENOS 1 permiso de la lista (ANY/OR).\n * Regla: denied_permissions siempre gana.\n */\nexport function requireAnyPermission(\n perms: string[],\n options?: { sysAdminBypass?: boolean; sysAdminRole?: string }\n) {\n const sysAdminBypass = options?.sysAdminBypass !== false;\n const sysAdminRole = options?.sysAdminRole || \"SYS_ADMIN\";\n\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();\n\n const allow = permsSet(auth.permissions);\n const deny = permsSet(auth.denied_permissions);\n\n // deny gana siempre (si alguno requerido está denegado explícitamente)\n for (const p of perms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {\n denied: p,\n });\n }\n }\n\n const ok = perms.some((p) => allow.has(p));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Permission denied\", {\n required: perms,\n mode: \"ANY\",\n });\n }\n\n return next();\n };\n}\n\n/**\n * Requiere al menos 1 rol (ANY/OR).\n * options:\n * - sysAdminBypass: default true\n * - sysAdminRole: default \"SYS_ADMIN\"\n */\nexport function requireRoles(\n roles: string[],\n options?: { sysAdminBypass?: boolean; sysAdminRole?: string }\n) {\n const sysAdminBypass = options?.sysAdminBypass !== false;\n const sysAdminRole = options?.sysAdminRole || \"SYS_ADMIN\";\n\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n // SYS_ADMIN bypass aplica también aquí\n if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();\n\n const have = rolesSet(auth);\n if (!roles.some((r) => have.has(r))) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Role not allowed\", {\n required: roles,\n mode: \"ANY\",\n });\n }\n\n return next();\n };\n}\n\n/**\n * Requiere (roles ANY) OR (permissions ANY).\n * deny_permissions siempre gana sobre permissions.\n */\nexport function requireRolesOrAnyPermission(\n roles: string[],\n perms: string[],\n options?: { sysAdminBypass?: boolean; sysAdminRole?: string }\n) {\n const sysAdminBypass = options?.sysAdminBypass !== false;\n const sysAdminRole = options?.sysAdminRole || \"SYS_ADMIN\";\n\n return (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n\n if (sysAdminBypass && isSysAdmin(auth, sysAdminRole)) return next();\n\n const haveRoles = rolesSet(auth);\n const allow = permsSet(auth.permissions);\n const deny = permsSet(auth.denied_permissions);\n\n // deny gana siempre (si cualquiera de los permisos evaluados está denegado explícitamente)\n for (const p of perms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {\n denied: p,\n });\n }\n }\n\n const okRole = roles.some((r) => haveRoles.has(r));\n const okPerm = perms.some((p) => allow.has(p));\n\n if (!okRole && !okPerm) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Access denied\", {\n roles,\n permissions: perms,\n mode: \"ROLES_OR_PERMS_ANY\",\n });\n }\n\n return next();\n };\n}\n","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 // ✅ canonical: string[]\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 // ✅ opcional, pero útil para debug / consumers\n employee_uid?: string;\n customer_uid?: string;\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\n/**\n * roles/perms pueden venir como:\n * - string[]\n * - {code,name}[]\n */\ntype RoleShape = string | { code?: string; name?: string };\ntype PermShape = string | { code?: string; name?: string };\n\nfunction normalizeCodes(list: any, kind: \"role\" | \"perm\"): string[] {\n if (!Array.isArray(list)) return [];\n const out: string[] = [];\n for (const item of list as (RoleShape | PermShape)[]) {\n if (!item) continue;\n if (typeof item === \"string\") {\n const s = item.trim();\n if (s) out.push(s);\n continue;\n }\n const s = String(item.code || item.name || \"\").trim();\n if (s) out.push(s);\n }\n // uniq\n return Array.from(new Set(out));\n}\n\n/**\n * UID-first extraction:\n * - decoded.employee_uid / customer_uid\n * - decoded.sub = \"emp:<uid>\" / \"cus:<uid>\"\n */\nfunction extractEmployeeUid(decoded: any): string | null {\n const direct = normalizeUid(decoded?.employee_uid);\n if (direct) return direct;\n\n const sub = normalizeUid(decoded?.sub);\n if (!sub) return null;\n\n const m = /^emp:(.+)$/i.exec(sub);\n return m?.[1] ? normalizeUid(m[1]) : null;\n}\n\nfunction extractCustomerUid(decoded: any): string | null {\n const direct = normalizeUid(decoded?.customer_uid);\n if (direct) return direct;\n\n const sub = normalizeUid(decoded?.sub);\n if (!sub) return null;\n\n const m = /^cus:(.+)$/i.exec(sub);\n return m?.[1] ? normalizeUid(m[1]) : 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 // ✅ canonical string[]\n roles: normalizeCodes(decoded?.roles, \"role\"),\n permissions: normalizeCodes(decoded?.permissions, \"perm\"),\n denied_permissions: normalizeCodes(decoded?.denied_permissions, \"perm\"),\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 employeeUid = extractEmployeeUid(decoded);\n\n // Preferir embebido, si existe\n const employeeEmbedded = decoded?.employee ?? decoded?.user ?? null;\n\n // ✅ UID-first: si no viene embebido, basta con stub {uid}\n if (employeeEmbedded) {\n ctx.employee = employeeUid\n ? { ...employeeEmbedded, uid: employeeEmbedded?.uid ?? employeeUid }\n : employeeEmbedded;\n } else if (employeeUid) {\n ctx.employee = { uid: employeeUid };\n } else {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_EMPLOYEE_NOT_FOUND\",\n message: \"Employee not found in token (expected employee_uid or sub=emp:<uid>)\",\n });\n }\n\n ctx.employee_uid = employeeUid ?? undefined;\n } else {\n const customerUid = extractCustomerUid(decoded);\n const customerEmbedded = decoded?.customer ?? null;\n\n if (customerEmbedded) {\n ctx.customer = customerUid\n ? { ...customerEmbedded, uid: customerEmbedded?.uid ?? customerUid }\n : customerEmbedded;\n } else if (customerUid) {\n ctx.customer = { uid: customerUid };\n } else {\n return res.status(401).json({\n ok: false,\n code: \"AUTH_CUSTOMER_NOT_FOUND\",\n message: \"Customer not found in token (expected customer_uid or sub=cus:<uid>)\",\n });\n }\n\n ctx.customer_uid = customerUid ?? undefined;\n }\n\n req.auth = ctx;\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","// packages/sdk/src/middlewares/guards.ts\nimport type {Request, Response, NextFunction, RequestHandler} from \"express\";\nimport parseHeaders from \"./parseHeaders\";\nimport {authEmployeeRequired} from \"../auth\";\nimport {sendError} from \"./respond\";\n\ntype RoleShape = string | { code?: string; name?: string };\ntype PermShape = string | { code?: string; name?: string };\n\nfunction normalizeRole(r: RoleShape): string | null {\n if (!r) return null;\n if (typeof r === \"string\") return r;\n return r.code || r.name || null;\n}\n\nfunction normalizePerm(p: PermShape): string | null {\n if (!p) return null;\n if (typeof p === \"string\") return p;\n return p.code || p.name || null;\n}\n\nfunction isSysAdmin(roles: RoleShape[] | undefined): boolean {\n if (!Array.isArray(roles)) return false;\n return roles.some((r) => normalizeRole(r) === \"SYS_ADMIN\");\n}\n\nfunction getAuth(req: Request) {\n return ((req as any).auth ?? {}) as {\n roles?: RoleShape[];\n permissions?: PermShape[];\n denied_permissions?: PermShape[];\n };\n}\n\nfunction permissionSets(auth: ReturnType<typeof getAuth>) {\n const allow = new Set<string>((auth.permissions ?? []).map(normalizePerm).filter(Boolean) as string[]);\n const deny = new Set<string>((auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean) as string[]);\n return {allow, deny};\n}\n\nfunction roleSet(auth: ReturnType<typeof getAuth>) {\n return new Set<string>((auth.roles ?? []).map(normalizeRole).filter(Boolean) as string[]);\n}\n\n/**\n * ✅ SysAdmin bypass OR (ANY) permissions\n * - Si tiene alguno de los permisos => OK\n * - denied_permissions gana siempre\n */\nexport function allowSysAdminOrAnyPermission(...perms: string[]): RequestHandler[] {\n const required = (perms ?? []).filter(Boolean);\n\n return [\n parseHeaders,\n authEmployeeRequired,\n (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n if (isSysAdmin(auth.roles)) return next();\n\n const {allow, deny} = permissionSets(auth);\n\n for (const p of required) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {denied: p});\n }\n }\n\n const ok = required.some((p) => allow.has(p));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Missing permissions (ANY)\", {required});\n }\n\n return next();\n },\n ];\n}\n\n/**\n * ✅ SysAdmin bypass OR (ALL) permissions (AND)\n */\nexport function allowSysAdminOrPermissionsAll(...perms: string[]): RequestHandler[] {\n const required = (perms ?? []).filter(Boolean);\n\n return [\n parseHeaders,\n authEmployeeRequired,\n (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n if (isSysAdmin(auth.roles)) return next();\n\n const {allow, deny} = permissionSets(auth);\n\n for (const p of required) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied permission: ${p}`, {denied: p});\n }\n }\n\n const missing = required.filter((p) => !allow.has(p));\n if (missing.length) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Missing permissions (ALL)\", {required, missing});\n }\n\n return next();\n },\n ];\n}\n\n/**\n * ✅ SysAdmin bypass OR roles (ANY)\n */\nexport function allowSysAdminOrRoles(...roles: string[]): RequestHandler[] {\n const required = (roles ?? []).filter(Boolean);\n\n return [\n parseHeaders,\n authEmployeeRequired,\n (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n if (isSysAdmin(auth.roles)) return next();\n\n const have = roleSet(auth);\n\n const ok = required.some((r) => have.has(r));\n if (!ok) {\n return sendError(req, res, 403, \"FORBIDDEN\", \"Role not allowed\", {required});\n }\n\n return next();\n },\n ];\n}\n\n/**\n * ✅ SYS_ADMIN bypass OR (ANY) roles OR (ANY) permissions\n * - denied_permissions siempre gana\n */\nexport function allowSysAdminOrRolesOrAnyPermission(\n roles: string | string[],\n permissions: string | string[]\n): RequestHandler[] {\n const requiredRoles = (Array.isArray(roles) ? roles : [roles]).filter(Boolean);\n const requiredPerms = (Array.isArray(permissions) ? permissions : [permissions]).filter(Boolean);\n\n return [\n parseHeaders,\n authEmployeeRequired,\n (req: Request, res: Response, next: NextFunction) => {\n const auth = getAuth(req);\n if (isSysAdmin(auth.roles)) return next();\n\n const {allow, deny} = permissionSets(auth);\n for (const p of requiredPerms) {\n if (deny.has(p)) {\n return sendError(req, res, 403, \"FORBIDDEN\", `Denied: ${p}`, {permission: p});\n }\n }\n\n const haveRoles = roleSet(auth);\n if (requiredRoles.some((r) => haveRoles.has(r))) return next();\n\n if (requiredPerms.some((p) => allow.has(p))) return next();\n\n return sendError(req, res, 403, \"FORBIDDEN\", \"Permission denied\", {\n roles: requiredRoles,\n permissions: requiredPerms,\n mode: \"ROLES_OR_ANY_PERMISSION\",\n });\n },\n ];\n}\n\n/**\n * ✅ Helper específico Auth:\n * Rol AUTH_ADMIN o permiso fino (y SYS_ADMIN bypass)\n */\nexport function allowAuthAdminOrPerm(permission: string): RequestHandler[] {\n return allowSysAdminOrRolesOrAnyPermission([\"AUTH_ADMIN\"], [permission]);\n}\n"],"mappings":"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","names":["fs","admin","jwt","fs","getBearerToken","verifyBackendJwtRS256","normalizeUid","s","createAuthMiddleware","isSysAdmin","getAuth"]}
|
package/dist/index.cjs
CHANGED
|
@@ -39,9 +39,11 @@ __export(src_exports, {
|
|
|
39
39
|
InternalHttp: () => InternalHttp,
|
|
40
40
|
TwoLevelCache: () => TwoLevelCache,
|
|
41
41
|
UpstreamError: () => UpstreamError,
|
|
42
|
+
allowAuthAdminOrPerm: () => allowAuthAdminOrPerm,
|
|
42
43
|
allowSysAdminOrAnyPermission: () => allowSysAdminOrAnyPermission,
|
|
43
44
|
allowSysAdminOrPermissionsAll: () => allowSysAdminOrPermissionsAll,
|
|
44
45
|
allowSysAdminOrRoles: () => allowSysAdminOrRoles,
|
|
46
|
+
allowSysAdminOrRolesOrAnyPermission: () => allowSysAdminOrRolesOrAnyPermission,
|
|
45
47
|
authCustomerAllowFirebase: () => authCustomerAllowFirebase,
|
|
46
48
|
authCustomerRequired: () => authCustomerRequired,
|
|
47
49
|
authEmployeeAllowFirebase: () => authEmployeeAllowFirebase,
|
|
@@ -937,6 +939,37 @@ function normalizeUid2(v) {
|
|
|
937
939
|
const s = String(v ?? "").trim();
|
|
938
940
|
return s.length ? s : null;
|
|
939
941
|
}
|
|
942
|
+
function normalizeCodes(list, kind) {
|
|
943
|
+
if (!Array.isArray(list)) return [];
|
|
944
|
+
const out = [];
|
|
945
|
+
for (const item of list) {
|
|
946
|
+
if (!item) continue;
|
|
947
|
+
if (typeof item === "string") {
|
|
948
|
+
const s2 = item.trim();
|
|
949
|
+
if (s2) out.push(s2);
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
const s = String(item.code || item.name || "").trim();
|
|
953
|
+
if (s) out.push(s);
|
|
954
|
+
}
|
|
955
|
+
return Array.from(new Set(out));
|
|
956
|
+
}
|
|
957
|
+
function extractEmployeeUid(decoded) {
|
|
958
|
+
const direct = normalizeUid2(decoded?.employee_uid);
|
|
959
|
+
if (direct) return direct;
|
|
960
|
+
const sub = normalizeUid2(decoded?.sub);
|
|
961
|
+
if (!sub) return null;
|
|
962
|
+
const m = /^emp:(.+)$/i.exec(sub);
|
|
963
|
+
return m?.[1] ? normalizeUid2(m[1]) : null;
|
|
964
|
+
}
|
|
965
|
+
function extractCustomerUid(decoded) {
|
|
966
|
+
const direct = normalizeUid2(decoded?.customer_uid);
|
|
967
|
+
if (direct) return direct;
|
|
968
|
+
const sub = normalizeUid2(decoded?.sub);
|
|
969
|
+
if (!sub) return null;
|
|
970
|
+
const m = /^cus:(.+)$/i.exec(sub);
|
|
971
|
+
return m?.[1] ? normalizeUid2(m[1]) : null;
|
|
972
|
+
}
|
|
940
973
|
function deriveCompanyBranch(decoded, companyUid, branchUid) {
|
|
941
974
|
const companiesFromToken = Array.isArray(decoded?.companies) ? decoded.companies : [];
|
|
942
975
|
const company = decoded?.company ?? (companyUid ? companiesFromToken.find((c) => c?.uid === companyUid) : null) ?? null;
|
|
@@ -968,9 +1001,10 @@ function createAuthMiddleware2(opts) {
|
|
|
968
1001
|
companies: companiesFromToken,
|
|
969
1002
|
company,
|
|
970
1003
|
branch,
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
1004
|
+
// ✅ canonical string[]
|
|
1005
|
+
roles: normalizeCodes(decoded?.roles, "role"),
|
|
1006
|
+
permissions: normalizeCodes(decoded?.permissions, "perm"),
|
|
1007
|
+
denied_permissions: normalizeCodes(decoded?.denied_permissions, "perm"),
|
|
974
1008
|
session: {
|
|
975
1009
|
jti: decoded?.jti,
|
|
976
1010
|
device_id: decoded?.device_id,
|
|
@@ -978,25 +1012,35 @@ function createAuthMiddleware2(opts) {
|
|
|
978
1012
|
}
|
|
979
1013
|
};
|
|
980
1014
|
if (subject === "employee") {
|
|
981
|
-
const
|
|
982
|
-
|
|
1015
|
+
const employeeUid = extractEmployeeUid(decoded);
|
|
1016
|
+
const employeeEmbedded = decoded?.employee ?? decoded?.user ?? null;
|
|
1017
|
+
if (employeeEmbedded) {
|
|
1018
|
+
ctx.employee = employeeUid ? { ...employeeEmbedded, uid: employeeEmbedded?.uid ?? employeeUid } : employeeEmbedded;
|
|
1019
|
+
} else if (employeeUid) {
|
|
1020
|
+
ctx.employee = { uid: employeeUid };
|
|
1021
|
+
} else {
|
|
983
1022
|
return res.status(401).json({
|
|
984
1023
|
ok: false,
|
|
985
1024
|
code: "AUTH_EMPLOYEE_NOT_FOUND",
|
|
986
|
-
message: "Employee not found in token"
|
|
1025
|
+
message: "Employee not found in token (expected employee_uid or sub=emp:<uid>)"
|
|
987
1026
|
});
|
|
988
1027
|
}
|
|
989
|
-
ctx.
|
|
1028
|
+
ctx.employee_uid = employeeUid ?? void 0;
|
|
990
1029
|
} else {
|
|
991
|
-
const
|
|
992
|
-
|
|
1030
|
+
const customerUid = extractCustomerUid(decoded);
|
|
1031
|
+
const customerEmbedded = decoded?.customer ?? null;
|
|
1032
|
+
if (customerEmbedded) {
|
|
1033
|
+
ctx.customer = customerUid ? { ...customerEmbedded, uid: customerEmbedded?.uid ?? customerUid } : customerEmbedded;
|
|
1034
|
+
} else if (customerUid) {
|
|
1035
|
+
ctx.customer = { uid: customerUid };
|
|
1036
|
+
} else {
|
|
993
1037
|
return res.status(401).json({
|
|
994
1038
|
ok: false,
|
|
995
1039
|
code: "AUTH_CUSTOMER_NOT_FOUND",
|
|
996
|
-
message: "Customer not found in token"
|
|
1040
|
+
message: "Customer not found in token (expected customer_uid or sub=cus:<uid>)"
|
|
997
1041
|
});
|
|
998
1042
|
}
|
|
999
|
-
ctx.
|
|
1043
|
+
ctx.customer_uid = customerUid ?? void 0;
|
|
1000
1044
|
}
|
|
1001
1045
|
req.auth = ctx;
|
|
1002
1046
|
return next();
|
|
@@ -1066,14 +1110,13 @@ function getAuth2(req) {
|
|
|
1066
1110
|
return req.auth ?? {};
|
|
1067
1111
|
}
|
|
1068
1112
|
function permissionSets(auth) {
|
|
1069
|
-
const allow = new Set(
|
|
1070
|
-
|
|
1071
|
-
);
|
|
1072
|
-
const deny = new Set(
|
|
1073
|
-
(auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean)
|
|
1074
|
-
);
|
|
1113
|
+
const allow = new Set((auth.permissions ?? []).map(normalizePerm).filter(Boolean));
|
|
1114
|
+
const deny = new Set((auth.denied_permissions ?? []).map(normalizePerm).filter(Boolean));
|
|
1075
1115
|
return { allow, deny };
|
|
1076
1116
|
}
|
|
1117
|
+
function roleSet(auth) {
|
|
1118
|
+
return new Set((auth.roles ?? []).map(normalizeRole).filter(Boolean));
|
|
1119
|
+
}
|
|
1077
1120
|
function allowSysAdminOrAnyPermission(...perms) {
|
|
1078
1121
|
const required = (perms ?? []).filter(Boolean);
|
|
1079
1122
|
return [
|
|
@@ -1085,16 +1128,12 @@ function allowSysAdminOrAnyPermission(...perms) {
|
|
|
1085
1128
|
const { allow, deny } = permissionSets(auth);
|
|
1086
1129
|
for (const p of required) {
|
|
1087
1130
|
if (deny.has(p)) {
|
|
1088
|
-
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
|
|
1089
|
-
denied: p
|
|
1090
|
-
});
|
|
1131
|
+
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, { denied: p });
|
|
1091
1132
|
}
|
|
1092
1133
|
}
|
|
1093
1134
|
const ok = required.some((p) => allow.has(p));
|
|
1094
1135
|
if (!ok) {
|
|
1095
|
-
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", {
|
|
1096
|
-
required
|
|
1097
|
-
});
|
|
1136
|
+
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ANY)", { required });
|
|
1098
1137
|
}
|
|
1099
1138
|
return next();
|
|
1100
1139
|
}
|
|
@@ -1111,17 +1150,12 @@ function allowSysAdminOrPermissionsAll(...perms) {
|
|
|
1111
1150
|
const { allow, deny } = permissionSets(auth);
|
|
1112
1151
|
for (const p of required) {
|
|
1113
1152
|
if (deny.has(p)) {
|
|
1114
|
-
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, {
|
|
1115
|
-
denied: p
|
|
1116
|
-
});
|
|
1153
|
+
return sendError(req, res, 403, "FORBIDDEN", `Denied permission: ${p}`, { denied: p });
|
|
1117
1154
|
}
|
|
1118
1155
|
}
|
|
1119
1156
|
const missing = required.filter((p) => !allow.has(p));
|
|
1120
1157
|
if (missing.length) {
|
|
1121
|
-
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", {
|
|
1122
|
-
required,
|
|
1123
|
-
missing
|
|
1124
|
-
});
|
|
1158
|
+
return sendError(req, res, 403, "FORBIDDEN", "Missing permissions (ALL)", { required, missing });
|
|
1125
1159
|
}
|
|
1126
1160
|
return next();
|
|
1127
1161
|
}
|
|
@@ -1135,19 +1169,44 @@ function allowSysAdminOrRoles(...roles) {
|
|
|
1135
1169
|
(req, res, next) => {
|
|
1136
1170
|
const auth = getAuth2(req);
|
|
1137
1171
|
if (isSysAdmin2(auth.roles)) return next();
|
|
1138
|
-
const have =
|
|
1139
|
-
(auth.roles ?? []).map(normalizeRole).filter(Boolean)
|
|
1140
|
-
);
|
|
1172
|
+
const have = roleSet(auth);
|
|
1141
1173
|
const ok = required.some((r) => have.has(r));
|
|
1142
1174
|
if (!ok) {
|
|
1143
|
-
return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", {
|
|
1144
|
-
required
|
|
1145
|
-
});
|
|
1175
|
+
return sendError(req, res, 403, "FORBIDDEN", "Role not allowed", { required });
|
|
1146
1176
|
}
|
|
1147
1177
|
return next();
|
|
1148
1178
|
}
|
|
1149
1179
|
];
|
|
1150
1180
|
}
|
|
1181
|
+
function allowSysAdminOrRolesOrAnyPermission(roles, permissions) {
|
|
1182
|
+
const requiredRoles = (Array.isArray(roles) ? roles : [roles]).filter(Boolean);
|
|
1183
|
+
const requiredPerms = (Array.isArray(permissions) ? permissions : [permissions]).filter(Boolean);
|
|
1184
|
+
return [
|
|
1185
|
+
parseHeaders,
|
|
1186
|
+
authEmployeeRequired,
|
|
1187
|
+
(req, res, next) => {
|
|
1188
|
+
const auth = getAuth2(req);
|
|
1189
|
+
if (isSysAdmin2(auth.roles)) return next();
|
|
1190
|
+
const { allow, deny } = permissionSets(auth);
|
|
1191
|
+
for (const p of requiredPerms) {
|
|
1192
|
+
if (deny.has(p)) {
|
|
1193
|
+
return sendError(req, res, 403, "FORBIDDEN", `Denied: ${p}`, { permission: p });
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
const haveRoles = roleSet(auth);
|
|
1197
|
+
if (requiredRoles.some((r) => haveRoles.has(r))) return next();
|
|
1198
|
+
if (requiredPerms.some((p) => allow.has(p))) return next();
|
|
1199
|
+
return sendError(req, res, 403, "FORBIDDEN", "Permission denied", {
|
|
1200
|
+
roles: requiredRoles,
|
|
1201
|
+
permissions: requiredPerms,
|
|
1202
|
+
mode: "ROLES_OR_ANY_PERMISSION"
|
|
1203
|
+
});
|
|
1204
|
+
}
|
|
1205
|
+
];
|
|
1206
|
+
}
|
|
1207
|
+
function allowAuthAdminOrPerm(permission) {
|
|
1208
|
+
return allowSysAdminOrRolesOrAnyPermission(["AUTH_ADMIN"], [permission]);
|
|
1209
|
+
}
|
|
1151
1210
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1152
1211
|
0 && (module.exports = {
|
|
1153
1212
|
HEADER_AUTHORIZATION,
|
|
@@ -1159,9 +1218,11 @@ function allowSysAdminOrRoles(...roles) {
|
|
|
1159
1218
|
InternalHttp,
|
|
1160
1219
|
TwoLevelCache,
|
|
1161
1220
|
UpstreamError,
|
|
1221
|
+
allowAuthAdminOrPerm,
|
|
1162
1222
|
allowSysAdminOrAnyPermission,
|
|
1163
1223
|
allowSysAdminOrPermissionsAll,
|
|
1164
1224
|
allowSysAdminOrRoles,
|
|
1225
|
+
allowSysAdminOrRolesOrAnyPermission,
|
|
1165
1226
|
authCustomerAllowFirebase,
|
|
1166
1227
|
authCustomerRequired,
|
|
1167
1228
|
authEmployeeAllowFirebase,
|