@infuro/cms-core 1.0.31 → 1.0.33
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/README.md +3 -2
- package/dist/admin.cjs +929 -345
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.js +947 -362
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +839 -59
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/api.js +833 -53
- package/dist/api.js.map +1 -1
- package/dist/auth.cjs +159 -14
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +37 -22
- package/dist/auth.d.ts +37 -22
- package/dist/auth.js +153 -14
- package/dist/auth.js.map +1 -1
- package/dist/cli.cjs +3 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +3 -2
- package/dist/cli.js.map +1 -1
- package/dist/{index-Bda8D1Rm.d.ts → index-DWd5Gjc4.d.ts} +2 -2
- package/dist/{index-BcMRGNjS.d.cts → index-rZTnpK7y.d.cts} +2 -2
- package/dist/index.cjs +1141 -254
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -30
- package/dist/index.d.ts +41 -30
- package/dist/index.js +1135 -254
- package/dist/index.js.map +1 -1
- package/dist/migrations/1778660000003-AddQrTokenToOrders.ts +32 -0
- package/dist/migrations/1779100000000-ChatConversationLeadEmailSent.ts +16 -0
- package/dist/migrations/1779200000000-LlmAgentScope.ts +72 -0
- package/package.json +2 -1
package/dist/auth.cjs
CHANGED
|
@@ -386,6 +386,8 @@ __export(auth_exports, {
|
|
|
386
386
|
getPermissionableEntityKeys: () => getPermissionableEntityKeys,
|
|
387
387
|
getRequiredPermission: () => getRequiredPermission,
|
|
388
388
|
hasEntityPermission: () => hasEntityPermission,
|
|
389
|
+
isAuthDebugClientEnabled: () => isAuthDebugClientEnabled,
|
|
390
|
+
isAuthDebugEnabled: () => isAuthDebugEnabled,
|
|
389
391
|
isOpenEndpoint: () => isOpenEndpoint,
|
|
390
392
|
isPlatformAdministrator: () => isPlatformAdministrator,
|
|
391
393
|
isPublicMethod: () => isPublicMethod,
|
|
@@ -395,13 +397,17 @@ __export(auth_exports, {
|
|
|
395
397
|
isVendorOwner: () => isVendorOwner,
|
|
396
398
|
isVendorPortalUser: () => isVendorPortalUser,
|
|
397
399
|
isVendorStaff: () => isVendorStaff,
|
|
400
|
+
logAuth: () => logAuth,
|
|
401
|
+
logAuthClient: () => logAuthClient,
|
|
398
402
|
logEntityAccessDecision: () => logEntityAccessDecision,
|
|
399
403
|
logRbac: () => logRbac,
|
|
404
|
+
nextAuthCookieDebugInfo: () => nextAuthCookieDebugInfo,
|
|
400
405
|
permissionRowsToRecord: () => permissionRowsToRecord,
|
|
401
406
|
resolveVendorScopeFromSessionUser: () => resolveVendorScopeFromSessionUser,
|
|
402
407
|
seedAdministratorPermissions: () => seedAdministratorPermissions,
|
|
403
408
|
sessionHasEntityAccess: () => sessionHasEntityAccess,
|
|
404
409
|
summarizeEntityPerms: () => summarizeEntityPerms,
|
|
410
|
+
summarizeSessionUserForLog: () => summarizeSessionUserForLog,
|
|
405
411
|
vendorPortalFlagsFromUser: () => vendorPortalFlagsFromUser
|
|
406
412
|
});
|
|
407
413
|
module.exports = __toCommonJS(auth_exports);
|
|
@@ -556,6 +562,59 @@ async function seedAdministratorPermissions(dataSource, entityMap) {
|
|
|
556
562
|
}
|
|
557
563
|
}
|
|
558
564
|
|
|
565
|
+
// src/auth/middleware.ts
|
|
566
|
+
var import_jwt = require("next-auth/jwt");
|
|
567
|
+
|
|
568
|
+
// src/auth/auth-debug.ts
|
|
569
|
+
var LOG_PREFIX2 = "[cms-auth]";
|
|
570
|
+
function isAuthDebugEnabled() {
|
|
571
|
+
const v = process.env.CMS_AUTH_DEBUG?.trim().toLowerCase();
|
|
572
|
+
if (v === "1" || v === "true" || v === "yes") return true;
|
|
573
|
+
if (v === "0" || v === "false" || v === "no") return false;
|
|
574
|
+
return process.env.NODE_ENV === "development";
|
|
575
|
+
}
|
|
576
|
+
function isAuthDebugClientEnabled() {
|
|
577
|
+
if (typeof window === "undefined") return false;
|
|
578
|
+
const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();
|
|
579
|
+
if (v === "1" || v === "true" || v === "yes") return true;
|
|
580
|
+
if (v === "0" || v === "false" || v === "no") return false;
|
|
581
|
+
return process.env.NODE_ENV === "development";
|
|
582
|
+
}
|
|
583
|
+
function logAuth(message, data) {
|
|
584
|
+
if (!isAuthDebugEnabled()) return;
|
|
585
|
+
if (data) console.info(LOG_PREFIX2, message, data);
|
|
586
|
+
else console.info(LOG_PREFIX2, message);
|
|
587
|
+
}
|
|
588
|
+
function logAuthClient(message, data) {
|
|
589
|
+
if (!isAuthDebugClientEnabled()) return;
|
|
590
|
+
if (data) console.info(LOG_PREFIX2, message, data);
|
|
591
|
+
else console.info(LOG_PREFIX2, message);
|
|
592
|
+
}
|
|
593
|
+
function summarizeSessionUserForLog(user) {
|
|
594
|
+
if (!user || typeof user !== "object") return { present: false };
|
|
595
|
+
const u = user;
|
|
596
|
+
return {
|
|
597
|
+
present: true,
|
|
598
|
+
email: u.email ?? null,
|
|
599
|
+
id: u.id ?? null,
|
|
600
|
+
adminAccess: u.adminAccess ?? null,
|
|
601
|
+
isRBACAdmin: u.isRBACAdmin ?? null,
|
|
602
|
+
isVendorPortal: u.isVendorPortal ?? null,
|
|
603
|
+
groupName: u.groupName ?? null
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
function nextAuthCookieDebugInfo() {
|
|
607
|
+
const nextAuthUrl = process.env.NEXTAUTH_URL ?? "(unset)";
|
|
608
|
+
const isHttps = nextAuthUrl.startsWith("https");
|
|
609
|
+
return {
|
|
610
|
+
nextAuthUrl,
|
|
611
|
+
hasSecret: Boolean(process.env.NEXTAUTH_SECRET),
|
|
612
|
+
cookieName: isHttps ? "__Secure-next-auth.session-token" : "next-auth.session-token",
|
|
613
|
+
cookieSecure: isHttps,
|
|
614
|
+
nodeEnv: process.env.NODE_ENV ?? "(unset)"
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
|
|
559
618
|
// src/auth/middleware.ts
|
|
560
619
|
var defaultPublicApiMethods = {
|
|
561
620
|
"/api/contacts": ["POST"],
|
|
@@ -568,8 +627,21 @@ var defaultPublicApiMethods = {
|
|
|
568
627
|
"/api/users/set-password": ["POST"],
|
|
569
628
|
"/api/users/invite": ["POST"]
|
|
570
629
|
};
|
|
571
|
-
function
|
|
572
|
-
|
|
630
|
+
function legacyGetSessionToken(request) {
|
|
631
|
+
const secure = request.cookies.get("__Secure-next-auth.session-token")?.value;
|
|
632
|
+
const regular = request.cookies.get("next-auth.session-token")?.value;
|
|
633
|
+
return secure ?? regular;
|
|
634
|
+
}
|
|
635
|
+
function sessionCookiePresence(request) {
|
|
636
|
+
const secure = request.cookies.get("__Secure-next-auth.session-token")?.value;
|
|
637
|
+
const regular = request.cookies.get("next-auth.session-token")?.value;
|
|
638
|
+
const hasChunked = Boolean(request.cookies.get("next-auth.session-token.0")?.value) || Boolean(request.cookies.get("__Secure-next-auth.session-token.0")?.value);
|
|
639
|
+
return {
|
|
640
|
+
hasSecureToken: Boolean(secure),
|
|
641
|
+
hasRegularToken: Boolean(regular),
|
|
642
|
+
hasChunkedToken: hasChunked,
|
|
643
|
+
resolved: Boolean(secure ?? regular)
|
|
644
|
+
};
|
|
573
645
|
}
|
|
574
646
|
function isPublicMethod2(pathname, method, publicApiMethods) {
|
|
575
647
|
for (const [endpoint, methods] of Object.entries(publicApiMethods)) {
|
|
@@ -577,31 +649,59 @@ function isPublicMethod2(pathname, method, publicApiMethods) {
|
|
|
577
649
|
}
|
|
578
650
|
return false;
|
|
579
651
|
}
|
|
652
|
+
async function hasValidSession(request, secret, legacyGetToken) {
|
|
653
|
+
if (request.req) {
|
|
654
|
+
const token = await (0, import_jwt.getToken)({ req: request.req, secret });
|
|
655
|
+
return token != null;
|
|
656
|
+
}
|
|
657
|
+
return Boolean(legacyGetToken(request));
|
|
658
|
+
}
|
|
580
659
|
function createCmsMiddleware(config = {}) {
|
|
581
660
|
const {
|
|
582
661
|
publicAdminPaths = ["/admin/signin", "/admin/forgot-password", "/admin/reset-password", "/admin/invite"],
|
|
583
662
|
publicApiMethods = defaultPublicApiMethods,
|
|
584
663
|
signInPath = "/admin/signin",
|
|
585
|
-
getSessionToken =
|
|
664
|
+
getSessionToken = legacyGetSessionToken,
|
|
665
|
+
secret = process.env.NEXTAUTH_SECRET
|
|
586
666
|
} = config;
|
|
587
|
-
return function cmsMiddleware(request) {
|
|
667
|
+
return async function cmsMiddleware(request) {
|
|
588
668
|
const pathname = request.nextUrl.pathname;
|
|
589
669
|
const method = request.method;
|
|
590
670
|
if (publicAdminPaths.some((p) => pathname === p || pathname.startsWith(p + "/"))) {
|
|
591
671
|
return { type: "next" };
|
|
592
672
|
}
|
|
593
673
|
if (pathname.startsWith("/admin")) {
|
|
594
|
-
const
|
|
595
|
-
|
|
674
|
+
const authenticated = await hasValidSession(request, secret, getSessionToken);
|
|
675
|
+
const cookies = sessionCookiePresence(request);
|
|
676
|
+
if (!authenticated) {
|
|
677
|
+
logAuth("middleware: admin redirect to signin (no session)", {
|
|
678
|
+
pathname,
|
|
679
|
+
method,
|
|
680
|
+
usesGetToken: Boolean(request.req),
|
|
681
|
+
...cookies,
|
|
682
|
+
expectedCookieName: process.env.NEXTAUTH_URL?.startsWith("https") ? "__Secure-next-auth.session-token" : "next-auth.session-token"
|
|
683
|
+
});
|
|
596
684
|
return { type: "redirect", url: new URL(signInPath, request.url).toString() };
|
|
597
685
|
}
|
|
686
|
+
logAuth("middleware: admin allowed", {
|
|
687
|
+
pathname,
|
|
688
|
+
method,
|
|
689
|
+
usesGetToken: Boolean(request.req),
|
|
690
|
+
...cookies
|
|
691
|
+
});
|
|
598
692
|
}
|
|
599
693
|
if (pathname.startsWith("/api")) {
|
|
600
694
|
if (isPublicMethod2(pathname, method, publicApiMethods)) {
|
|
601
695
|
return { type: "next" };
|
|
602
696
|
}
|
|
603
|
-
const
|
|
604
|
-
if (!
|
|
697
|
+
const authenticated = await hasValidSession(request, secret, getSessionToken);
|
|
698
|
+
if (!authenticated) {
|
|
699
|
+
logAuth("middleware: api 401 (no session)", {
|
|
700
|
+
pathname,
|
|
701
|
+
method,
|
|
702
|
+
usesGetToken: Boolean(request.req),
|
|
703
|
+
...sessionCookiePresence(request)
|
|
704
|
+
});
|
|
605
705
|
return { type: "json", status: 401, body: { error: "Unauthorized" } };
|
|
606
706
|
}
|
|
607
707
|
}
|
|
@@ -656,6 +756,7 @@ function getNextAuthOptions(config) {
|
|
|
656
756
|
enableOtpLogin = false,
|
|
657
757
|
authorizeOtp
|
|
658
758
|
} = config;
|
|
759
|
+
logAuth("getNextAuthOptions init", nextAuthCookieDebugInfo());
|
|
659
760
|
const providers = [];
|
|
660
761
|
if (enablePasswordLogin) {
|
|
661
762
|
providers.push(
|
|
@@ -666,15 +767,43 @@ function getNextAuthOptions(config) {
|
|
|
666
767
|
password: { label: "Password", type: "password" }
|
|
667
768
|
},
|
|
668
769
|
async authorize(credentials) {
|
|
669
|
-
|
|
770
|
+
const email = credentials?.email?.trim() ?? "";
|
|
771
|
+
if (!email || !credentials?.password) {
|
|
772
|
+
logAuth("authorize(credentials) rejected", { reason: "missing_email_or_password" });
|
|
773
|
+
return null;
|
|
774
|
+
}
|
|
670
775
|
try {
|
|
671
|
-
const user = await getUserByEmail(
|
|
672
|
-
if (!user
|
|
776
|
+
const user = await getUserByEmail(email);
|
|
777
|
+
if (!user) {
|
|
778
|
+
logAuth("authorize(credentials) rejected", { reason: "user_not_found", email });
|
|
779
|
+
return null;
|
|
780
|
+
}
|
|
781
|
+
if (user.blocked) {
|
|
782
|
+
logAuth("authorize(credentials) rejected", { reason: "blocked", email, userId: user.id });
|
|
783
|
+
return null;
|
|
784
|
+
}
|
|
785
|
+
if (user.deleted) {
|
|
786
|
+
logAuth("authorize(credentials) rejected", { reason: "deleted", email, userId: user.id });
|
|
787
|
+
return null;
|
|
788
|
+
}
|
|
789
|
+
if (!user.password) {
|
|
790
|
+
logAuth("authorize(credentials) rejected", { reason: "no_password", email, userId: user.id });
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
673
793
|
const valid = await comparePassword(credentials.password, user.password);
|
|
674
|
-
if (!valid)
|
|
675
|
-
|
|
794
|
+
if (!valid) {
|
|
795
|
+
logAuth("authorize(credentials) rejected", { reason: "invalid_password", email, userId: user.id });
|
|
796
|
+
return null;
|
|
797
|
+
}
|
|
798
|
+
const sessionUser = sessionUserFromNextAuthUser(user);
|
|
799
|
+
logAuth("authorize(credentials) ok", summarizeSessionUserForLog(sessionUser));
|
|
800
|
+
return sessionUser;
|
|
676
801
|
} catch (err) {
|
|
677
802
|
console.error("[cms-auth] authorize error (credentials):", err instanceof Error ? err.message : err);
|
|
803
|
+
logAuth("authorize(credentials) error", {
|
|
804
|
+
email,
|
|
805
|
+
message: err instanceof Error ? err.message : String(err)
|
|
806
|
+
});
|
|
678
807
|
return null;
|
|
679
808
|
}
|
|
680
809
|
}
|
|
@@ -727,6 +856,10 @@ function getNextAuthOptions(config) {
|
|
|
727
856
|
callbacks: {
|
|
728
857
|
async jwt({ token, user, trigger, session }) {
|
|
729
858
|
if (user) {
|
|
859
|
+
logAuth("jwt callback: new sign-in", {
|
|
860
|
+
trigger,
|
|
861
|
+
user: summarizeSessionUserForLog(user)
|
|
862
|
+
});
|
|
730
863
|
const u = user;
|
|
731
864
|
token.id = u.id;
|
|
732
865
|
token.groupId = u.groupId;
|
|
@@ -741,6 +874,7 @@ function getNextAuthOptions(config) {
|
|
|
741
874
|
token.isVendorOwner = u.isVendorOwner;
|
|
742
875
|
}
|
|
743
876
|
if (trigger === "update" && session && typeof session === "object") {
|
|
877
|
+
logAuth("jwt callback: session update", { trigger });
|
|
744
878
|
const s = session;
|
|
745
879
|
const t = token;
|
|
746
880
|
if (typeof s.name === "string") t.name = s.name;
|
|
@@ -750,8 +884,13 @@ function getNextAuthOptions(config) {
|
|
|
750
884
|
return token;
|
|
751
885
|
},
|
|
752
886
|
async session({ session, token }) {
|
|
887
|
+
const t = token;
|
|
888
|
+
logAuth("session callback", {
|
|
889
|
+
tokenHasId: t.id != null,
|
|
890
|
+
tokenEmail: typeof t.email === "string" ? t.email : null,
|
|
891
|
+
sessionUser: summarizeSessionUserForLog(session.user)
|
|
892
|
+
});
|
|
753
893
|
if (session.user) {
|
|
754
|
-
const t = token;
|
|
755
894
|
if (typeof t.name === "string") session.user.name = t.name;
|
|
756
895
|
if (typeof t.email === "string") session.user.email = t.email;
|
|
757
896
|
session.user.id = t.id;
|
|
@@ -794,6 +933,8 @@ function getNextAuthOptions(config) {
|
|
|
794
933
|
getPermissionableEntityKeys,
|
|
795
934
|
getRequiredPermission,
|
|
796
935
|
hasEntityPermission,
|
|
936
|
+
isAuthDebugClientEnabled,
|
|
937
|
+
isAuthDebugEnabled,
|
|
797
938
|
isOpenEndpoint,
|
|
798
939
|
isPlatformAdministrator,
|
|
799
940
|
isPublicMethod,
|
|
@@ -803,13 +944,17 @@ function getNextAuthOptions(config) {
|
|
|
803
944
|
isVendorOwner,
|
|
804
945
|
isVendorPortalUser,
|
|
805
946
|
isVendorStaff,
|
|
947
|
+
logAuth,
|
|
948
|
+
logAuthClient,
|
|
806
949
|
logEntityAccessDecision,
|
|
807
950
|
logRbac,
|
|
951
|
+
nextAuthCookieDebugInfo,
|
|
808
952
|
permissionRowsToRecord,
|
|
809
953
|
resolveVendorScopeFromSessionUser,
|
|
810
954
|
seedAdministratorPermissions,
|
|
811
955
|
sessionHasEntityAccess,
|
|
812
956
|
summarizeEntityPerms,
|
|
957
|
+
summarizeSessionUserForLog,
|
|
813
958
|
vendorPortalFlagsFromUser
|
|
814
959
|
});
|
|
815
960
|
//# sourceMappingURL=auth.cjs.map
|
package/dist/auth.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/auth/permission-entities.ts","../src/auth/vendor-scope.ts","../src/auth/rbac-debug-db.ts","../src/auth/rbac-debug.ts","../src/auth/index.ts","../src/auth/helpers.ts","../src/auth/seed-permissions.ts","../src/auth/middleware.ts","../src/auth/nextauth-options.ts"],"sourcesContent":["/** API resource keys excluded from the permission matrix (internal / not admin-CRUD). */\r\nexport const PERMISSION_ENTITY_INTERNAL_EXCLUDE = new Set([\r\n 'users',\r\n 'password_reset_tokens',\r\n 'user_groups',\r\n 'permissions',\r\n 'comments',\r\n 'form_fields',\r\n 'configs',\r\n 'knowledge_base_chunks',\r\n 'carts',\r\n 'cart_items',\r\n 'wishlists',\r\n 'wishlist_items',\r\n 'message_templates',\r\n 'vendor_users',\r\n]);\r\n\r\n/** Non-CRUD admin surfaces mapped to entity keys for RBAC. */\r\nexport const PERMISSION_LOGICAL_ENTITIES = [\r\n 'users',\r\n 'forms',\r\n 'form_submissions',\r\n 'dashboard',\r\n 'upload',\r\n 'settings',\r\n 'analytics',\r\n 'chat',\r\n] as const;\r\n\r\n/** Canonical name for new installs / migrations */\r\nexport const ADMIN_GROUP_NAME = 'Administrator';\r\n\r\n/** System administrator group (roles UI + users / user_groups / permissions bypass). */\r\nexport function isSuperAdminGroupName(name: string | null | undefined): boolean {\r\n return name === ADMIN_GROUP_NAME;\r\n}\r\n\r\nexport type EntityCrudAction = 'create' | 'read' | 'update' | 'delete';\r\n\r\nexport type EntityPermissionFlags = { c: boolean; r: boolean; u: boolean; d: boolean };\r\n\r\nexport function getPermissionableEntityKeys(entityMap: Record<string, unknown>): string[] {\r\n const fromMap = Object.keys(entityMap).filter((k) => !PERMISSION_ENTITY_INTERNAL_EXCLUDE.has(k));\r\n const logical = PERMISSION_LOGICAL_ENTITIES.filter((k) => !fromMap.includes(k));\r\n return [...fromMap.sort(), ...logical].filter((k, i, a) => a.indexOf(k) === i);\r\n}\r\n\r\nexport function permissionRowsToRecord(\r\n rows: Array<{ entity: string; canCreate: boolean; canRead: boolean; canUpdate: boolean; canDelete: boolean }> | undefined\r\n): Record<string, EntityPermissionFlags> {\r\n const out: Record<string, EntityPermissionFlags> = {};\r\n if (!rows?.length) return out;\r\n for (const p of rows) {\r\n out[p.entity] = {\r\n c: !!p.canCreate,\r\n r: !!p.canRead,\r\n u: !!p.canUpdate,\r\n d: !!p.canDelete,\r\n };\r\n }\r\n return out;\r\n}\r\n\r\nexport function hasEntityPermission(\r\n record: Record<string, EntityPermissionFlags> | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n const p = record?.[entity];\r\n if (!p) return false;\r\n if (action === 'create') return p.c;\r\n if (action === 'read') return p.r;\r\n if (action === 'update') return p.u;\r\n return p.d;\r\n}\r\n","import type { SessionUser } from './helpers';\r\nimport { isSuperAdminGroupName } from './permission-entities';\r\n\r\n/** Entities with a `vendorId` column (store data). */\r\nexport const VENDOR_SCOPED_STORE_ENTITIES = new Set([\r\n 'products',\r\n 'collections',\r\n 'brands',\r\n 'product_categories',\r\n 'orders',\r\n 'payments',\r\n 'taxes',\r\n 'attributes',\r\n 'vendor_customers',\r\n 'discounts',\r\n]);\r\n\r\n/**\r\n * Store admin RBAC for vendor portal users (read/create/update/delete fallbacks in rbac-debug).\r\n * Includes entities without `vendorId` that are still part of the store admin UI.\r\n */\r\nexport const VENDOR_STORE_RBAC_ENTITIES = new Set<string>([\r\n ...VENDOR_SCOPED_STORE_ENTITIES,\r\n 'order_discounts',\r\n 'order_addresses',\r\n]);\r\n\r\nexport type VendorScope =\r\n | { type: 'all' }\r\n | { type: 'vendor'; vendorId: number; vendorIds: number[] }\r\n | { type: 'deny' };\r\n\r\nexport const VENDOR_OWNER_GROUP_NAME = 'Vendor Owner';\r\n\r\n/** User groups treated as vendor store staff (sidebar + scoped admin). */\r\nexport function isVendorGroupName(name: string | null | undefined): boolean {\r\n if (!name?.trim()) return false;\r\n const n = name.trim().toLowerCase();\r\n return n === VENDOR_OWNER_GROUP_NAME.toLowerCase() || n.includes('vendor');\r\n}\r\n\r\nexport function isPlatformAdministrator(user: SessionUser | null | undefined): boolean {\r\n if (!user?.email) return false;\r\n return !!(user.isRBACAdmin || isSuperAdminGroupName(user.groupName));\r\n}\r\n\r\n/** Vendor portal UI (store + store admin), not platform admin. */\r\nexport function isVendorPortalUser(user: SessionUser | null | undefined): boolean {\r\n if (user?.isVendorPortal === true) return true;\r\n if (!user?.email || isPlatformAdministrator(user)) return false;\r\n if ((user.vendorIds?.length ?? 0) > 0) return true;\r\n return isVendorGroupName(user.groupName);\r\n}\r\n\r\nexport function isVendorStaff(user: SessionUser | null | undefined): boolean {\r\n return isVendorPortalUser(user);\r\n}\r\n\r\n/** Vendor store owner (manages team + role permissions for their group). */\r\nexport function isVendorOwner(user: SessionUser | null | undefined): boolean {\r\n if (user?.isVendorOwner === true) return true;\r\n if (!user?.email || isPlatformAdministrator(user)) return false;\r\n if (user.vendorRole === 'staff') return false;\r\n if (user.vendorRole === 'owner') return true;\r\n if (!isVendorPortalUser(user)) return false;\r\n return user.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase();\r\n}\r\n\r\nexport function canManageVendorTeam(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user) || isVendorOwner(user);\r\n}\r\n\r\nexport function canManageVendorRoles(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user) || isVendorOwner(user);\r\n}\r\n\r\n/** Platform admins (Administrator group) can onboard vendors. */\r\nexport function canOnboardVendors(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user);\r\n}\r\n\r\nexport function resolveVendorScopeFromSessionUser(user: SessionUser | null | undefined): VendorScope {\r\n if (!user?.email) return { type: 'deny' };\r\n if (isPlatformAdministrator(user)) return { type: 'all' };\r\n const vendorIds = user.vendorIds ?? [];\r\n if (vendorIds.length === 0) return { type: 'deny' };\r\n const preferred = user.activeVendorId ?? vendorIds[0]!;\r\n const vendorId = vendorIds.includes(preferred) ? preferred : vendorIds[0]!;\r\n return { type: 'vendor', vendorId, vendorIds };\r\n}\r\n\r\n/** Compute portal flags at login (persist on JWT). */\r\nexport function vendorPortalFlagsFromUser(input: {\r\n email: string;\r\n isRBACAdmin: boolean;\r\n groupName?: string | null;\r\n vendorIds?: number[];\r\n vendorRole?: 'owner' | 'staff' | null;\r\n}): { isVendorPortal: boolean; isVendorOwner: boolean } {\r\n const vendorIds = input.vendorIds ?? [];\r\n const isVendorPortal =\r\n !input.isRBACAdmin &&\r\n (vendorIds.length > 0 || isVendorGroupName(input.groupName));\r\n const isVendorOwner =\r\n isVendorPortal &&\r\n input.vendorRole !== 'staff' &&\r\n (input.vendorRole === 'owner' ||\r\n input.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase());\r\n return { isVendorPortal, isVendorOwner };\r\n}\r\n","import { permissionRowsToRecord } from './permission-entities';\r\nimport type { RbacDebugDataSource } from './rbac-debug';\r\nimport { summarizeEntityPerms } from './rbac-debug';\r\n\r\n/** Load permission rows from DB for debug (server/API only — do not import from `@infuro/cms-core/auth`). */\r\nexport async function loadDbPermissionsForUser(\r\n dataSource: RbacDebugDataSource,\r\n userId: number\r\n): Promise<{\r\n groupId: number | null;\r\n groupName: string | null;\r\n dbEntityPerms: Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }>;\r\n}> {\r\n const rows = (await dataSource.query(\r\n `\r\n SELECT u.\"groupId\" AS \"groupId\", g.name AS \"groupName\",\r\n p.entity, p.\"canCreate\", p.\"canRead\", p.\"canUpdate\", p.\"canDelete\"\r\n FROM users u\r\n LEFT JOIN user_groups g ON g.id = u.\"groupId\" AND g.deleted = false\r\n LEFT JOIN permissions p ON p.\"groupId\" = g.id\r\n WHERE u.id = $1\r\n `,\r\n [userId]\r\n )) as Array<{\r\n groupId: number | null;\r\n groupName: string | null;\r\n entity: string | null;\r\n canCreate: boolean | null;\r\n canRead: boolean | null;\r\n canUpdate: boolean | null;\r\n canDelete: boolean | null;\r\n }>;\r\n\r\n const groupId = rows[0]?.groupId ?? null;\r\n const groupName = rows[0]?.groupName ?? null;\r\n const permRows = rows\r\n .filter((r) => r.entity)\r\n .map((r) => ({\r\n entity: r.entity!,\r\n canCreate: !!r.canCreate,\r\n canRead: !!r.canRead,\r\n canUpdate: !!r.canUpdate,\r\n canDelete: !!r.canDelete,\r\n }));\r\n\r\n return {\r\n groupId,\r\n groupName,\r\n dbEntityPerms: summarizeEntityPerms(permissionRowsToRecord(permRows)),\r\n };\r\n}\r\n","import type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nimport { hasEntityPermission } from './permission-entities';\r\nimport type { SessionUser } from './helpers';\r\nimport { isVendorOwner, isVendorPortalUser, VENDOR_STORE_RBAC_ENTITIES } from './vendor-scope';\r\n\r\nconst LOG_PREFIX = '[cms-rbac]';\r\n\r\n/** Minimal DB handle for RBAC debug (avoids importing `typeorm` in the auth bundle). */\r\nexport type RbacDebugDataSource = {\r\n query: (sql: string, parameters?: unknown[]) => Promise<unknown>;\r\n};\r\n\r\n/** Set `CMS_RBAC_DEBUG=true` in `.env` to log permission decisions (server console). */\r\nexport function isRbacDebugEnabled(): boolean {\r\n const v = process.env.CMS_RBAC_DEBUG?.trim().toLowerCase();\r\n if (v === '1' || v === 'true' || v === 'yes') return true;\r\n if (v === '0' || v === 'false' || v === 'no') return false;\r\n return process.env.NODE_ENV === 'development';\r\n}\r\n\r\nexport function logRbac(message: string, data?: Record<string, unknown>): void {\r\n if (!isRbacDebugEnabled()) return;\r\n if (data) console.info(LOG_PREFIX, message, data);\r\n else console.info(LOG_PREFIX, message);\r\n}\r\n\r\nexport function summarizeEntityPerms(\r\n entityPerms: Record<string, EntityPermissionFlags> | undefined\r\n): Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }> {\r\n const out: Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }> = {};\r\n if (!entityPerms) return out;\r\n for (const [entity, p] of Object.entries(entityPerms)) {\r\n out[entity] = { c: p.c, r: p.r, u: p.u, d: p.d };\r\n }\r\n return out;\r\n}\r\n\r\nexport interface EntityAccessExplanation {\r\n allowed: boolean;\r\n reason: string;\r\n userSnapshot: Record<string, unknown>;\r\n}\r\n\r\nfunction vendorPortalFallbackReason(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): string | null {\r\n if (!isVendorPortalUser(user)) return null;\r\n if (entity === 'dashboard' && action === 'read') return 'vendor_portal_dashboard_fallback';\r\n if (entity === 'analytics' && action === 'read') return 'vendor_portal_analytics_fallback';\r\n if (entity === 'settings' && action === 'read') return 'vendor_portal_settings_read_fallback';\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity) && action === 'read') return 'vendor_portal_store_read_fallback';\r\n return null;\r\n}\r\n\r\n/** Same rules as `sessionHasEntityAccess`, but returns why access was granted or denied. */\r\nexport function explainSessionEntityAccess(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): EntityAccessExplanation {\r\n const userSnapshot: Record<string, unknown> = {\r\n email: user?.email ?? null,\r\n id: user?.id ?? null,\r\n groupId: user?.groupId ?? null,\r\n groupName: user?.groupName ?? null,\r\n isRBACAdmin: user?.isRBACAdmin ?? false,\r\n adminAccess: user?.adminAccess ?? null,\r\n vendorIds: user?.vendorIds ?? [],\r\n activeVendorId: user?.activeVendorId ?? null,\r\n vendorRole: user?.vendorRole ?? null,\r\n isVendorPortal: user?.isVendorPortal ?? false,\r\n isVendorOwner: user?.isVendorOwner ?? false,\r\n isVendorPortalComputed: isVendorPortalUser(user),\r\n isVendorOwnerComputed: isVendorOwner(user),\r\n jwtEntityPerms: summarizeEntityPerms(user?.entityPerms),\r\n jwtEntityPermForTarget: user?.entityPerms?.[entity] ?? null,\r\n };\r\n\r\n if (!user?.email) {\r\n return { allowed: false, reason: 'no_session_email', userSnapshot };\r\n }\r\n if (user.isRBACAdmin) {\r\n return { allowed: true, reason: 'platform_administrator', userSnapshot };\r\n }\r\n\r\n const vendorIds = user.vendorIds ?? [];\r\n const isStaff = user.vendorRole === 'staff';\r\n\r\n if (vendorIds.length > 0) {\r\n if (entity === 'dashboard' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_dashboard_read', userSnapshot };\r\n }\r\n if (entity === 'analytics' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_analytics_read', userSnapshot };\r\n }\r\n if (entity === 'settings') {\r\n if (action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_settings_read', userSnapshot };\r\n }\r\n if (action === 'update' && !isStaff) {\r\n return { allowed: true, reason: 'vendor_link_settings_update', userSnapshot };\r\n }\r\n }\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity)) {\r\n if (isStaff && action === 'read') {\r\n return { allowed: true, reason: 'vendor_staff_store_read', userSnapshot };\r\n }\r\n if (!isStaff) {\r\n return { allowed: true, reason: 'vendor_link_store_full', userSnapshot };\r\n }\r\n return {\r\n allowed: false,\r\n reason: 'vendor_staff_store_write_denied',\r\n userSnapshot,\r\n };\r\n }\r\n }\r\n\r\n if (isVendorPortalUser(user) && isVendorOwner(user)) {\r\n if (entity === 'dashboard' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_owner_group_dashboard', userSnapshot };\r\n }\r\n if (entity === 'analytics' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_owner_group_analytics', userSnapshot };\r\n }\r\n if (entity === 'settings' && (action === 'read' || action === 'update')) {\r\n return { allowed: true, reason: 'vendor_owner_group_settings', userSnapshot };\r\n }\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity)) {\r\n return { allowed: true, reason: 'vendor_owner_group_store', userSnapshot };\r\n }\r\n }\r\n\r\n const vendorPortalReason = vendorPortalFallbackReason(user, entity, action);\r\n if (vendorPortalReason) {\r\n return { allowed: true, reason: vendorPortalReason, userSnapshot };\r\n }\r\n\r\n const explicit = user.entityPerms?.[entity];\r\n if (explicit !== undefined) {\r\n const allowed = hasEntityPermission(user.entityPerms, entity, action);\r\n return {\r\n allowed,\r\n reason: allowed ? 'jwt_entity_perms_allow' : 'jwt_entity_perms_deny',\r\n userSnapshot,\r\n };\r\n }\r\n\r\n const allowed = hasEntityPermission(user.entityPerms, entity, action);\r\n return {\r\n allowed,\r\n reason: allowed ? 'entity_perms_fallback_allow' : 'no_matching_rule',\r\n userSnapshot,\r\n };\r\n}\r\n\r\nexport function sessionHasEntityAccessFromExplanation(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n return explainSessionEntityAccess(user, entity, action).allowed;\r\n}\r\n\r\nexport async function logEntityAccessDecision(\r\n dataSource: RbacDebugDataSource | undefined,\r\n context: string,\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction,\r\n extra?: Record<string, unknown>\r\n): Promise<void> {\r\n if (!isRbacDebugEnabled()) return;\r\n\r\n const explanation = explainSessionEntityAccess(user, entity, action);\r\n let dbPermissions: Record<string, unknown> | undefined;\r\n if (dataSource && user?.id) {\r\n const id = Number(user.id);\r\n if (Number.isFinite(id)) {\r\n try {\r\n const { loadDbPermissionsForUser } = await import('./rbac-debug-db');\r\n dbPermissions = await loadDbPermissionsForUser(dataSource, id);\r\n } catch (e) {\r\n dbPermissions = { error: e instanceof Error ? e.message : String(e) };\r\n }\r\n }\r\n }\r\n\r\n logRbac(context, {\r\n entity,\r\n action,\r\n allowed: explanation.allowed,\r\n reason: explanation.reason,\r\n ...explanation.userSnapshot,\r\n dbPermissions,\r\n ...extra,\r\n });\r\n}\r\n","export {\r\n createAuthHelpers,\r\n createCmsAuthBundle,\r\n OPEN_ENDPOINTS,\r\n PERMISSION_REQUIRED_ENDPOINTS,\r\n isOpenEndpoint,\r\n isPublicMethod,\r\n getRequiredPermission,\r\n} from './helpers';\r\nexport type { SessionUser, GetSession, AuthHelpers } from './helpers';\r\nexport { sessionHasEntityAccess, canManageRoles, RBAC_ADMIN_ONLY_ENTITIES } from './helpers';\r\nexport {\r\n isRbacDebugEnabled,\r\n logRbac,\r\n explainSessionEntityAccess,\r\n logEntityAccessDecision,\r\n summarizeEntityPerms,\r\n} from './rbac-debug';\r\nexport {\r\n resolveVendorScopeFromSessionUser,\r\n VENDOR_SCOPED_STORE_ENTITIES,\r\n VENDOR_STORE_RBAC_ENTITIES,\r\n VENDOR_OWNER_GROUP_NAME,\r\n isVendorStaff,\r\n isVendorPortalUser,\r\n isVendorOwner,\r\n isVendorGroupName,\r\n isPlatformAdministrator,\r\n vendorPortalFlagsFromUser,\r\n canOnboardVendors,\r\n canManageVendorTeam,\r\n canManageVendorRoles,\r\n} from './vendor-scope';\r\nexport {\r\n getPermissionableEntityKeys,\r\n ADMIN_GROUP_NAME,\r\n isSuperAdminGroupName,\r\n permissionRowsToRecord,\r\n hasEntityPermission,\r\n} from './permission-entities';\r\nexport { seedAdministratorPermissions } from './seed-permissions';\r\nexport type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nexport { createCmsMiddleware, defaultPublicApiMethods } from './middleware';\r\nexport type { CmsMiddlewareConfig } from './middleware';\r\nexport { getNextAuthOptions } from './nextauth-options';\r\nexport type { NextAuthOptionsConfig, NextAuthUser, AuthorizeOtpInput } from './nextauth-options';\r\n","import type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nimport { explainSessionEntityAccess, logRbac } from './rbac-debug';\r\nimport { isVendorPortalUser } from './vendor-scope';\r\n\r\n/**\r\n * @deprecated Administrator bypass is now full entity access via `isRBACAdmin` in `sessionHasEntityAccess`.\r\n * Kept for backwards-compatible imports.\r\n */\r\nexport const RBAC_ADMIN_ONLY_ENTITIES = new Set(['users', 'user_groups', 'permissions']);\r\n\r\nexport interface SessionUser {\r\n id?: string;\r\n email?: string | null;\r\n name?: string | null;\r\n groupId?: number;\r\n /** User group display name (from login). */\r\n groupName?: string | null;\r\n /** @deprecated use entityPerms / isRBACAdmin */\r\n permissions?: string[];\r\n /** Administrator group: bypasses entity-level RBAC on all resources */\r\n isRBACAdmin?: boolean;\r\n entityPerms?: Record<string, EntityPermissionFlags>;\r\n /** When false and not isRBACAdmin, admin API/UI is denied. */\r\n adminAccess?: boolean;\r\n /** Vendor stores this user can access (from vendor_users). */\r\n vendorIds?: number[];\r\n /** Active vendor for scoped CRUD (vendor staff). */\r\n activeVendorId?: number | null;\r\n /** Role for the active vendor link (`vendor_users.role`). */\r\n vendorRole?: 'owner' | 'staff' | null;\r\n /** Set at login: vendor store portal (not platform admin). */\r\n isVendorPortal?: boolean;\r\n /** Set at login: vendor store owner (team + permissions). */\r\n isVendorOwner?: boolean;\r\n}\r\n\r\nexport function sessionHasEntityAccess(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n return explainSessionEntityAccess(user, entity, action).allowed;\r\n}\r\n\r\nexport function canManageRoles(user: SessionUser | null | undefined): boolean {\r\n return !!(user?.email && user.isRBACAdmin);\r\n}\r\n\r\nexport type GetSession = () => Promise<{ user?: SessionUser } | null>;\r\n\r\nexport const OPEN_ENDPOINTS: Array<Record<string, string[]>> = [\r\n { '/api/contacts': ['POST'] },\r\n { '/api/form-submissions': ['POST'] },\r\n { '/api/blogs': ['GET'] },\r\n];\r\n\r\nexport const PERMISSION_REQUIRED_ENDPOINTS: Record<string, string[]> = {};\r\n\r\nexport function isOpenEndpoint(pathname: string): boolean {\r\n return OPEN_ENDPOINTS.some((endpoint) => pathname.startsWith(Object.keys(endpoint)[0]));\r\n}\r\n\r\nexport function getRequiredPermission(pathname: string): string[] | null {\r\n return null;\r\n}\r\n\r\nexport function isPublicMethod(pathname: string, method: string): boolean {\r\n for (const endpoint of OPEN_ENDPOINTS) {\r\n const key = Object.keys(endpoint)[0];\r\n if (pathname.startsWith(key) && endpoint[key].includes(method)) return true;\r\n }\r\n return false;\r\n}\r\n\r\nexport interface AuthHelpers {\r\n requireAuth(req: Request): Promise<Response | null>;\r\n requirePermission(req: Request, permission: string): Promise<Response | null>;\r\n requireEntityPermission(req: Request, entity: string, action: EntityCrudAction): Promise<Response | null>;\r\n requireAdminAccess(req: Request): Promise<Response | null>;\r\n getAuthenticatedUser(): Promise<SessionUser | null>;\r\n}\r\n\r\nexport function createAuthHelpers(getSession: GetSession, NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }): AuthHelpers {\r\n return createAuthHelpersFromGetSession(getSession, NextResponse);\r\n}\r\n\r\n/** Pass return value into `createCmsApiHandler` (includes `getSessionUser` for vendor store APIs). */\r\nexport function createCmsAuthBundle(\r\n getSession: GetSession,\r\n NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }\r\n) {\r\n const auth = createAuthHelpers(getSession, NextResponse);\r\n return {\r\n requireAuth: auth.requireAuth,\r\n requireAdminAccess: auth.requireAdminAccess,\r\n requireEntityPermission: auth.requireEntityPermission,\r\n getSessionUser: auth.getAuthenticatedUser,\r\n getAuthenticatedUser: auth.getAuthenticatedUser,\r\n };\r\n}\r\n\r\nfunction createAuthHelpersFromGetSession(\r\n getSession: GetSession,\r\n NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }\r\n): AuthHelpers {\r\n return {\r\n async requireAuth() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n return null;\r\n },\r\n async requirePermission() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n return null;\r\n },\r\n async requireEntityPermission(_req: Request, entity: string, action: EntityCrudAction) {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n const u = session.user as SessionUser;\r\n const allowed = sessionHasEntityAccess(u, entity, action);\r\n const { reason } = explainSessionEntityAccess(u, entity, action);\r\n logRbac('authHelpers.requireEntityPermission', {\r\n entity,\r\n action,\r\n allowed,\r\n reason,\r\n email: u.email,\r\n groupName: u.groupName,\r\n vendorIds: u.vendorIds,\r\n isVendorPortal: u.isVendorPortal,\r\n isVendorOwner: u.isVendorOwner,\r\n });\r\n if (allowed) return null;\r\n return NextResponse.json({ error: 'Forbidden', entity, action, reason }, { status: 403 });\r\n },\r\n async requireAdminAccess() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n const u = session.user as SessionUser;\r\n if (u.isRBACAdmin) return null;\r\n // Vendor portal users always have admin UI access for their store — check\r\n // before adminAccess so that vendor users (who have adminAccess:false from\r\n // the DB default) are not incorrectly denied.\r\n if (isVendorPortalUser(u)) return null;\r\n if (u.adminAccess === true) return null;\r\n if (u.adminAccess === false) {\r\n logRbac('requireAdminAccess denied (adminAccess:false)', {\r\n email: u.email,\r\n groupName: u.groupName,\r\n isVendorPortal: u.isVendorPortal,\r\n });\r\n return NextResponse.json({ error: 'Forbidden', reason: 'admin_access' }, { status: 403 });\r\n }\r\n logRbac('requireAdminAccess denied (no matching rule)', {\r\n email: u.email,\r\n adminAccess: u.adminAccess,\r\n groupName: u.groupName,\r\n isVendorPortal: u.isVendorPortal,\r\n });\r\n return NextResponse.json({ error: 'Forbidden', reason: 'admin_access' }, { status: 403 });\r\n },\r\n async getAuthenticatedUser() {\r\n const session = await getSession();\r\n return (session?.user as SessionUser) ?? null;\r\n },\r\n };\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { EntityTarget } from 'typeorm';\r\nimport type { ObjectLiteral } from 'typeorm';\r\nimport { getPermissionableEntityKeys, ADMIN_GROUP_NAME } from './permission-entities';\r\n\r\n/**\r\n * Ensures the Administrator group has full CRUD on every permissionable entity\r\n * for the given entity map. Idempotent: upserts per entity.\r\n */\r\nexport async function seedAdministratorPermissions(\r\n dataSource: DataSource,\r\n entityMap: Record<string, unknown>\r\n): Promise<void> {\r\n const entities = getPermissionableEntityKeys(entityMap);\r\n const groupRepo = dataSource.getRepository(entityMap.user_groups as EntityTarget<ObjectLiteral>);\r\n const permRepo = dataSource.getRepository(entityMap.permissions as EntityTarget<ObjectLiteral>);\r\n\r\n const adminGroup = await groupRepo.findOne({ where: { name: ADMIN_GROUP_NAME, deleted: false } });\r\n console.log(\"ADMIN GROUP\", adminGroup);\r\n if (!adminGroup) return;\r\n\r\n const fullCrud = { canCreate: true, canRead: true, canUpdate: true, canDelete: true };\r\n\r\n for (const entity of entities) {\r\n const existing = await permRepo.findOne({\r\n where: { groupId: adminGroup.id, entity },\r\n });\r\n console.log(\"EXISTING\", existing);\r\n if (existing) {\r\n existing.canCreate = true;\r\n existing.canRead = true;\r\n existing.canUpdate = true;\r\n existing.canDelete = true;\r\n await permRepo.save(existing);\r\n } else {\r\n await permRepo.save(\r\n permRepo.create({\r\n groupId: adminGroup.id,\r\n entity,\r\n ...fullCrud,\r\n })\r\n );\r\n }\r\n }\r\n}\r\n","export interface CmsMiddlewareConfig {\r\n publicAdminPaths?: string[];\r\n publicApiPaths?: string[];\r\n /** path -> allowed methods */\r\n publicApiMethods?: Record<string, string[]>;\r\n signInPath?: string;\r\n getSessionToken?: (request: { cookies: { get: (name: string) => { value?: string } | undefined } }) => string | undefined;\r\n}\r\n\r\n/** Default public API paths (no auth). Sites should extend this with their own routes. */\r\nexport const defaultPublicApiMethods: Record<string, string[]> = {\r\n '/api/contacts': ['POST'],\r\n '/api/form-submissions': ['POST'],\r\n '/api/blogs': ['GET'],\r\n '/api/forms': ['GET'],\r\n '/api/auth': ['GET', 'POST'],\r\n '/api/health': ['GET'],\r\n '/api/users/forgot-password': ['POST'],\r\n '/api/users/set-password': ['POST'],\r\n '/api/users/invite': ['POST'],\r\n};\r\n\r\nfunction defaultGetSessionToken(request: { cookies: { get: (name: string) => { value?: string } | undefined } }): string | undefined {\r\n return (\r\n request.cookies.get('__Secure-next-auth.session-token')?.value ??\r\n request.cookies.get('next-auth.session-token')?.value\r\n );\r\n}\r\n\r\nfunction isPublicMethod(pathname: string, method: string, publicApiMethods: Record<string, string[]>): boolean {\r\n for (const [endpoint, methods] of Object.entries(publicApiMethods)) {\r\n if (pathname.startsWith(endpoint) && methods.includes(method)) return true;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Returns middleware logic. Use from Next.js middleware:\r\n * import { createCmsMiddleware } from '@infuro/cms-core';\r\n * export const middleware = createCmsMiddleware({ ... });\r\n * export const config = { matcher: ['/admin/:path*', '/api/:path*'] };\r\n */\r\nexport function createCmsMiddleware(config: CmsMiddlewareConfig = {}) {\r\n const {\r\n publicAdminPaths = ['/admin/signin', '/admin/forgot-password', '/admin/reset-password', '/admin/invite'],\r\n publicApiMethods = defaultPublicApiMethods,\r\n signInPath = '/admin/signin',\r\n getSessionToken = defaultGetSessionToken,\r\n } = config;\r\n\r\n return function cmsMiddleware(request: {\r\n nextUrl: { pathname: string };\r\n url: string;\r\n method: string;\r\n cookies: { get: (name: string) => { value?: string } | undefined };\r\n }): { type: 'next' } | { type: 'redirect'; url: string } | { type: 'json'; status: number; body: unknown } {\r\n const pathname = request.nextUrl.pathname;\r\n const method = request.method;\r\n\r\n if (publicAdminPaths.some((p) => pathname === p || pathname.startsWith(p + '/'))) {\r\n return { type: 'next' };\r\n }\r\n\r\n if (pathname.startsWith('/admin')) {\r\n const token = getSessionToken(request);\r\n if (!token) {\r\n return { type: 'redirect', url: new URL(signInPath, request.url).toString() };\r\n }\r\n }\r\n\r\n if (pathname.startsWith('/api')) {\r\n if (isPublicMethod(pathname, method, publicApiMethods)) {\r\n return { type: 'next' };\r\n }\r\n const token = getSessionToken(request);\r\n if (!token) {\r\n return { type: 'json', status: 401, body: { error: 'Unauthorized' } };\r\n }\r\n }\r\n\r\n return { type: 'next' };\r\n };\r\n}\r\n","/**\r\n * Build NextAuth options for credentials auth. App can extend/override via extend().\r\n */\r\nimport type { NextAuthOptions } from 'next-auth';\r\nimport _CredentialsProvider from 'next-auth/providers/credentials';\r\nconst CredentialsProvider = (_CredentialsProvider as unknown as { default: typeof _CredentialsProvider }).default ?? _CredentialsProvider;\r\nimport { isSuperAdminGroupName, permissionRowsToRecord } from './permission-entities';\r\nimport { vendorPortalFlagsFromUser } from './vendor-scope';\r\n\r\nexport interface NextAuthUser {\r\n id: number;\r\n email: string;\r\n name: string | null;\r\n password: string | null;\r\n blocked?: boolean;\r\n deleted?: boolean;\r\n groupId?: number | null;\r\n adminAccess?: boolean;\r\n group?: {\r\n name?: string;\r\n permissions?: Array<{\r\n entity: string;\r\n canCreate: boolean;\r\n canRead: boolean;\r\n canUpdate: boolean;\r\n canDelete: boolean;\r\n }>;\r\n };\r\n vendorIds?: number[];\r\n activeVendorId?: number | null;\r\n vendorRole?: 'owner' | 'staff' | null;\r\n}\r\n\r\nexport interface AuthorizeOtpInput {\r\n identifier: string;\r\n channel: 'email' | 'sms';\r\n code: string;\r\n}\r\n\r\nexport interface NextAuthOptionsConfig {\r\n /** Resolve user by email (e.g. from TypeORM). Return null if not found. */\r\n getUserByEmail: (email: string) => Promise<NextAuthUser | null>;\r\n comparePassword: (plain: string, hash: string) => Promise<boolean>;\r\n signInPage?: string;\r\n secret?: string;\r\n extend?: (options: NextAuthOptions) => NextAuthOptions;\r\n /** When false, password CredentialsProvider is omitted. Default true. */\r\n enablePasswordLogin?: boolean;\r\n /** When true, registers CredentialsProvider id `otp`. Requires authorizeOtp. Default false. */\r\n enableOtpLogin?: boolean;\r\n /** Validate OTP and return user (same shape as password flow) or null. */\r\n authorizeOtp?: (input: AuthorizeOtpInput) => Promise<NextAuthUser | null>;\r\n}\r\n\r\nfunction sessionUserFromNextAuthUser(user: NextAuthUser) {\r\n const g = user.group;\r\n const isRBACAdmin = isSuperAdminGroupName(g?.name);\r\n const entityPerms = permissionRowsToRecord(g?.permissions);\r\n // Preserve the DB value as-is: true → true, false → false, null/undefined → undefined.\r\n // Coercing null to false would make requireAdminAccess deny vendor/unset users before\r\n // the vendor-portal check can allow them.\r\n const rawAdminAccess = (user as NextAuthUser & { adminAccess?: boolean }).adminAccess;\r\n const adminAccess: boolean | undefined =\r\n rawAdminAccess === true ? true : rawAdminAccess === false ? false : undefined;\r\n const vendorIds = user.vendorIds ?? [];\r\n const vendorRole = user.vendorRole ?? null;\r\n const { isVendorPortal, isVendorOwner } = vendorPortalFlagsFromUser({\r\n email: user.email,\r\n isRBACAdmin,\r\n groupName: g?.name,\r\n vendorIds,\r\n vendorRole,\r\n });\r\n return {\r\n id: user.id.toString(),\r\n email: user.email,\r\n name: user.name,\r\n groupId: user.groupId ?? undefined,\r\n groupName: g?.name ?? undefined,\r\n isRBACAdmin,\r\n entityPerms,\r\n adminAccess,\r\n vendorIds,\r\n activeVendorId: user.activeVendorId ?? vendorIds[0] ?? null,\r\n vendorRole,\r\n isVendorPortal,\r\n isVendorOwner,\r\n };\r\n}\r\n\r\nexport function getNextAuthOptions(config: NextAuthOptionsConfig): NextAuthOptions {\r\n const {\r\n getUserByEmail,\r\n comparePassword,\r\n signInPage = '/admin/signin',\r\n secret,\r\n extend,\r\n enablePasswordLogin = true,\r\n enableOtpLogin = false,\r\n authorizeOtp,\r\n } = config;\r\n\r\n const providers: NextAuthOptions['providers'] = [];\r\n\r\n if (enablePasswordLogin) {\r\n providers.push(\r\n CredentialsProvider({\r\n name: 'credentials',\r\n credentials: {\r\n email: { label: 'Email', type: 'email' },\r\n password: { label: 'Password', type: 'password' },\r\n },\r\n async authorize(credentials) {\r\n if (!credentials?.email || !credentials?.password) return null;\r\n try {\r\n const user = await getUserByEmail(credentials.email);\r\n if (!user || user.blocked || (user as { deleted?: boolean }).deleted || !user.password) return null;\r\n const valid = await comparePassword(credentials.password, user.password);\r\n if (!valid) return null;\r\n return sessionUserFromNextAuthUser(user);\r\n } catch (err) {\r\n // Log so infrastructure errors (DB down, missing entity, etc.) are\r\n // visible in server logs rather than silently failing as \"wrong password\".\r\n console.error('[cms-auth] authorize error (credentials):', err instanceof Error ? err.message : err);\r\n return null;\r\n }\r\n },\r\n })\r\n );\r\n }\r\n\r\n if (enableOtpLogin && authorizeOtp) {\r\n providers.push(\r\n CredentialsProvider({\r\n id: 'otp',\r\n name: 'otp',\r\n credentials: {\r\n identifier: { label: 'Email or phone', type: 'text' },\r\n code: { label: 'Code', type: 'text' },\r\n channel: { label: 'Channel', type: 'text' },\r\n },\r\n async authorize(credentials) {\r\n const identifier = typeof credentials?.identifier === 'string' ? credentials.identifier.trim() : '';\r\n const code = typeof credentials?.code === 'string' ? credentials.code.trim() : '';\r\n const ch = credentials?.channel === 'sms' ? 'sms' : 'email';\r\n if (!identifier || !code) return null;\r\n try {\r\n const user = await authorizeOtp({ identifier, channel: ch, code });\r\n if (!user || user.blocked || (user as { deleted?: boolean }).deleted) return null;\r\n return sessionUserFromNextAuthUser(user);\r\n } catch (err) {\r\n console.error('[cms-auth] authorize error (otp):', err instanceof Error ? err.message : err);\r\n return null;\r\n }\r\n },\r\n })\r\n );\r\n }\r\n\r\n const options: NextAuthOptions = {\r\n secret: secret ?? process.env.NEXTAUTH_SECRET,\r\n providers,\r\n session: { strategy: 'jwt' },\r\n pages: { signIn: signInPage },\r\n cookies: {\r\n sessionToken: {\r\n name: process.env.NEXTAUTH_URL?.startsWith('https')\r\n ? '__Secure-next-auth.session-token'\r\n : 'next-auth.session-token',\r\n options: {\r\n httpOnly: true,\r\n sameSite: 'lax',\r\n path: '/',\r\n secure: process.env.NEXTAUTH_URL?.startsWith('https') ?? false,\r\n },\r\n },\r\n },\r\n callbacks: {\r\n async jwt({ token, user, trigger, session }) {\r\n if (user) {\r\n const u = user as unknown as Record<string, unknown>;\r\n (token as Record<string, unknown>).id = u.id;\r\n (token as Record<string, unknown>).groupId = u.groupId;\r\n (token as Record<string, unknown>).groupName = u.groupName;\r\n (token as Record<string, unknown>).isRBACAdmin = u.isRBACAdmin;\r\n (token as Record<string, unknown>).entityPerms = u.entityPerms;\r\n (token as Record<string, unknown>).adminAccess = u.adminAccess;\r\n (token as Record<string, unknown>).vendorIds = u.vendorIds;\r\n (token as Record<string, unknown>).activeVendorId = u.activeVendorId;\r\n (token as Record<string, unknown>).vendorRole = u.vendorRole;\r\n (token as Record<string, unknown>).isVendorPortal = u.isVendorPortal;\r\n (token as Record<string, unknown>).isVendorOwner = u.isVendorOwner;\r\n }\r\n if (trigger === 'update' && session && typeof session === 'object') {\r\n const s = session as Record<string, unknown>;\r\n const t = token as Record<string, unknown>;\r\n if (typeof s.name === 'string') t.name = s.name;\r\n if (typeof s.email === 'string') t.email = s.email;\r\n if (typeof s.activeVendorId === 'number') t.activeVendorId = s.activeVendorId;\r\n }\r\n return token;\r\n },\r\n async session({ session, token }) {\r\n if (session.user) {\r\n const t = token as Record<string, unknown>;\r\n if (typeof t.name === 'string') session.user.name = t.name;\r\n if (typeof t.email === 'string') session.user.email = t.email;\r\n (session.user as Record<string, unknown>).id = t.id;\r\n (session.user as Record<string, unknown>).groupId = t.groupId;\r\n (session.user as Record<string, unknown>).groupName = t.groupName;\r\n (session.user as Record<string, unknown>).isRBACAdmin = t.isRBACAdmin;\r\n (session.user as Record<string, unknown>).entityPerms = t.entityPerms;\r\n (session.user as Record<string, unknown>).adminAccess = t.adminAccess;\r\n (session.user as Record<string, unknown>).vendorIds = t.vendorIds;\r\n (session.user as Record<string, unknown>).activeVendorId = t.activeVendorId;\r\n (session.user as Record<string, unknown>).vendorRole = t.vendorRole;\r\n (session.user as Record<string, unknown>).isVendorPortal = t.isVendorPortal;\r\n (session.user as Record<string, unknown>).isVendorOwner = t.isVendorOwner;\r\n }\r\n return session;\r\n },\r\n },\r\n };\r\n\r\n return extend ? extend(options) : options;\r\n}\r\n"],"mappings":"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","names":["isVendorOwner","allowed","loadDbPermissionsForUser","isPublicMethod","_CredentialsProvider","isVendorOwner"]}
|
|
1
|
+
{"version":3,"sources":["../src/auth/permission-entities.ts","../src/auth/vendor-scope.ts","../src/auth/rbac-debug-db.ts","../src/auth/rbac-debug.ts","../src/auth/index.ts","../src/auth/helpers.ts","../src/auth/seed-permissions.ts","../src/auth/middleware.ts","../src/auth/auth-debug.ts","../src/auth/nextauth-options.ts"],"sourcesContent":["/** API resource keys excluded from the permission matrix (internal / not admin-CRUD). */\r\nexport const PERMISSION_ENTITY_INTERNAL_EXCLUDE = new Set([\r\n 'users',\r\n 'password_reset_tokens',\r\n 'user_groups',\r\n 'permissions',\r\n 'comments',\r\n 'form_fields',\r\n 'configs',\r\n 'knowledge_base_chunks',\r\n 'carts',\r\n 'cart_items',\r\n 'wishlists',\r\n 'wishlist_items',\r\n 'message_templates',\r\n 'vendor_users',\r\n]);\r\n\r\n/** Non-CRUD admin surfaces mapped to entity keys for RBAC. */\r\nexport const PERMISSION_LOGICAL_ENTITIES = [\r\n 'users',\r\n 'forms',\r\n 'form_submissions',\r\n 'dashboard',\r\n 'upload',\r\n 'settings',\r\n 'analytics',\r\n 'chat',\r\n] as const;\r\n\r\n/** Canonical name for new installs / migrations */\r\nexport const ADMIN_GROUP_NAME = 'Administrator';\r\n\r\n/** System administrator group (roles UI + users / user_groups / permissions bypass). */\r\nexport function isSuperAdminGroupName(name: string | null | undefined): boolean {\r\n return name === ADMIN_GROUP_NAME;\r\n}\r\n\r\nexport type EntityCrudAction = 'create' | 'read' | 'update' | 'delete';\r\n\r\nexport type EntityPermissionFlags = { c: boolean; r: boolean; u: boolean; d: boolean };\r\n\r\nexport function getPermissionableEntityKeys(entityMap: Record<string, unknown>): string[] {\r\n const fromMap = Object.keys(entityMap).filter((k) => !PERMISSION_ENTITY_INTERNAL_EXCLUDE.has(k));\r\n const logical = PERMISSION_LOGICAL_ENTITIES.filter((k) => !fromMap.includes(k));\r\n return [...fromMap.sort(), ...logical].filter((k, i, a) => a.indexOf(k) === i);\r\n}\r\n\r\nexport function permissionRowsToRecord(\r\n rows: Array<{ entity: string; canCreate: boolean; canRead: boolean; canUpdate: boolean; canDelete: boolean }> | undefined\r\n): Record<string, EntityPermissionFlags> {\r\n const out: Record<string, EntityPermissionFlags> = {};\r\n if (!rows?.length) return out;\r\n for (const p of rows) {\r\n out[p.entity] = {\r\n c: !!p.canCreate,\r\n r: !!p.canRead,\r\n u: !!p.canUpdate,\r\n d: !!p.canDelete,\r\n };\r\n }\r\n return out;\r\n}\r\n\r\nexport function hasEntityPermission(\r\n record: Record<string, EntityPermissionFlags> | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n const p = record?.[entity];\r\n if (!p) return false;\r\n if (action === 'create') return p.c;\r\n if (action === 'read') return p.r;\r\n if (action === 'update') return p.u;\r\n return p.d;\r\n}\r\n","import type { SessionUser } from './helpers';\r\nimport { isSuperAdminGroupName } from './permission-entities';\r\n\r\n/** Entities with a `vendorId` column (store data). */\r\nexport const VENDOR_SCOPED_STORE_ENTITIES = new Set([\r\n 'products',\r\n 'collections',\r\n 'brands',\r\n 'product_categories',\r\n 'orders',\r\n 'payments',\r\n 'taxes',\r\n 'attributes',\r\n 'vendor_customers',\r\n 'discounts',\r\n]);\r\n\r\n/**\r\n * Store admin RBAC for vendor portal users (read/create/update/delete fallbacks in rbac-debug).\r\n * Includes entities without `vendorId` that are still part of the store admin UI.\r\n */\r\nexport const VENDOR_STORE_RBAC_ENTITIES = new Set<string>([\r\n ...VENDOR_SCOPED_STORE_ENTITIES,\r\n 'order_discounts',\r\n 'order_addresses',\r\n]);\r\n\r\nexport type VendorScope =\r\n | { type: 'all' }\r\n | { type: 'vendor'; vendorId: number; vendorIds: number[] }\r\n | { type: 'deny' };\r\n\r\nexport const VENDOR_OWNER_GROUP_NAME = 'Vendor Owner';\r\n\r\n/** User groups treated as vendor store staff (sidebar + scoped admin). */\r\nexport function isVendorGroupName(name: string | null | undefined): boolean {\r\n if (!name?.trim()) return false;\r\n const n = name.trim().toLowerCase();\r\n return n === VENDOR_OWNER_GROUP_NAME.toLowerCase() || n.includes('vendor');\r\n}\r\n\r\nexport function isPlatformAdministrator(user: SessionUser | null | undefined): boolean {\r\n if (!user?.email) return false;\r\n return !!(user.isRBACAdmin || isSuperAdminGroupName(user.groupName));\r\n}\r\n\r\n/** Vendor portal UI (store + store admin), not platform admin. */\r\nexport function isVendorPortalUser(user: SessionUser | null | undefined): boolean {\r\n if (user?.isVendorPortal === true) return true;\r\n if (!user?.email || isPlatformAdministrator(user)) return false;\r\n if ((user.vendorIds?.length ?? 0) > 0) return true;\r\n return isVendorGroupName(user.groupName);\r\n}\r\n\r\nexport function isVendorStaff(user: SessionUser | null | undefined): boolean {\r\n return isVendorPortalUser(user);\r\n}\r\n\r\n/** Vendor store owner (manages team + role permissions for their group). */\r\nexport function isVendorOwner(user: SessionUser | null | undefined): boolean {\r\n if (user?.isVendorOwner === true) return true;\r\n if (!user?.email || isPlatformAdministrator(user)) return false;\r\n if (user.vendorRole === 'staff') return false;\r\n if (user.vendorRole === 'owner') return true;\r\n if (!isVendorPortalUser(user)) return false;\r\n return user.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase();\r\n}\r\n\r\nexport function canManageVendorTeam(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user) || isVendorOwner(user);\r\n}\r\n\r\nexport function canManageVendorRoles(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user) || isVendorOwner(user);\r\n}\r\n\r\n/** Platform admins (Administrator group) can onboard vendors. */\r\nexport function canOnboardVendors(user: SessionUser | null | undefined): boolean {\r\n return isPlatformAdministrator(user);\r\n}\r\n\r\nexport function resolveVendorScopeFromSessionUser(user: SessionUser | null | undefined): VendorScope {\r\n if (!user?.email) return { type: 'deny' };\r\n if (isPlatformAdministrator(user)) return { type: 'all' };\r\n const vendorIds = user.vendorIds ?? [];\r\n if (vendorIds.length === 0) return { type: 'deny' };\r\n const preferred = user.activeVendorId ?? vendorIds[0]!;\r\n const vendorId = vendorIds.includes(preferred) ? preferred : vendorIds[0]!;\r\n return { type: 'vendor', vendorId, vendorIds };\r\n}\r\n\r\n/** Compute portal flags at login (persist on JWT). */\r\nexport function vendorPortalFlagsFromUser(input: {\r\n email: string;\r\n isRBACAdmin: boolean;\r\n groupName?: string | null;\r\n vendorIds?: number[];\r\n vendorRole?: 'owner' | 'staff' | null;\r\n}): { isVendorPortal: boolean; isVendorOwner: boolean } {\r\n const vendorIds = input.vendorIds ?? [];\r\n const isVendorPortal =\r\n !input.isRBACAdmin &&\r\n (vendorIds.length > 0 || isVendorGroupName(input.groupName));\r\n const isVendorOwner =\r\n isVendorPortal &&\r\n input.vendorRole !== 'staff' &&\r\n (input.vendorRole === 'owner' ||\r\n input.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase());\r\n return { isVendorPortal, isVendorOwner };\r\n}\r\n","import { permissionRowsToRecord } from './permission-entities';\r\nimport type { RbacDebugDataSource } from './rbac-debug';\r\nimport { summarizeEntityPerms } from './rbac-debug';\r\n\r\n/** Load permission rows from DB for debug (server/API only — do not import from `@infuro/cms-core/auth`). */\r\nexport async function loadDbPermissionsForUser(\r\n dataSource: RbacDebugDataSource,\r\n userId: number\r\n): Promise<{\r\n groupId: number | null;\r\n groupName: string | null;\r\n dbEntityPerms: Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }>;\r\n}> {\r\n const rows = (await dataSource.query(\r\n `\r\n SELECT u.\"groupId\" AS \"groupId\", g.name AS \"groupName\",\r\n p.entity, p.\"canCreate\", p.\"canRead\", p.\"canUpdate\", p.\"canDelete\"\r\n FROM users u\r\n LEFT JOIN user_groups g ON g.id = u.\"groupId\" AND g.deleted = false\r\n LEFT JOIN permissions p ON p.\"groupId\" = g.id\r\n WHERE u.id = $1\r\n `,\r\n [userId]\r\n )) as Array<{\r\n groupId: number | null;\r\n groupName: string | null;\r\n entity: string | null;\r\n canCreate: boolean | null;\r\n canRead: boolean | null;\r\n canUpdate: boolean | null;\r\n canDelete: boolean | null;\r\n }>;\r\n\r\n const groupId = rows[0]?.groupId ?? null;\r\n const groupName = rows[0]?.groupName ?? null;\r\n const permRows = rows\r\n .filter((r) => r.entity)\r\n .map((r) => ({\r\n entity: r.entity!,\r\n canCreate: !!r.canCreate,\r\n canRead: !!r.canRead,\r\n canUpdate: !!r.canUpdate,\r\n canDelete: !!r.canDelete,\r\n }));\r\n\r\n return {\r\n groupId,\r\n groupName,\r\n dbEntityPerms: summarizeEntityPerms(permissionRowsToRecord(permRows)),\r\n };\r\n}\r\n","import type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nimport { hasEntityPermission } from './permission-entities';\r\nimport type { SessionUser } from './helpers';\r\nimport { isVendorOwner, isVendorPortalUser, VENDOR_STORE_RBAC_ENTITIES } from './vendor-scope';\r\n\r\nconst LOG_PREFIX = '[cms-rbac]';\r\n\r\n/** Minimal DB handle for RBAC debug (avoids importing `typeorm` in the auth bundle). */\r\nexport type RbacDebugDataSource = {\r\n query: (sql: string, parameters?: unknown[]) => Promise<unknown>;\r\n};\r\n\r\n/** Set `CMS_RBAC_DEBUG=true` in `.env` to log permission decisions (server console). */\r\nexport function isRbacDebugEnabled(): boolean {\r\n const v = process.env.CMS_RBAC_DEBUG?.trim().toLowerCase();\r\n if (v === '1' || v === 'true' || v === 'yes') return true;\r\n if (v === '0' || v === 'false' || v === 'no') return false;\r\n return process.env.NODE_ENV === 'development';\r\n}\r\n\r\nexport function logRbac(message: string, data?: Record<string, unknown>): void {\r\n if (!isRbacDebugEnabled()) return;\r\n if (data) console.info(LOG_PREFIX, message, data);\r\n else console.info(LOG_PREFIX, message);\r\n}\r\n\r\nexport function summarizeEntityPerms(\r\n entityPerms: Record<string, EntityPermissionFlags> | undefined\r\n): Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }> {\r\n const out: Record<string, { c: boolean; r: boolean; u: boolean; d: boolean }> = {};\r\n if (!entityPerms) return out;\r\n for (const [entity, p] of Object.entries(entityPerms)) {\r\n out[entity] = { c: p.c, r: p.r, u: p.u, d: p.d };\r\n }\r\n return out;\r\n}\r\n\r\nexport interface EntityAccessExplanation {\r\n allowed: boolean;\r\n reason: string;\r\n userSnapshot: Record<string, unknown>;\r\n}\r\n\r\nfunction vendorPortalFallbackReason(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): string | null {\r\n if (!isVendorPortalUser(user)) return null;\r\n if (entity === 'dashboard' && action === 'read') return 'vendor_portal_dashboard_fallback';\r\n if (entity === 'analytics' && action === 'read') return 'vendor_portal_analytics_fallback';\r\n if (entity === 'settings' && action === 'read') return 'vendor_portal_settings_read_fallback';\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity) && action === 'read') return 'vendor_portal_store_read_fallback';\r\n return null;\r\n}\r\n\r\n/** Same rules as `sessionHasEntityAccess`, but returns why access was granted or denied. */\r\nexport function explainSessionEntityAccess(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): EntityAccessExplanation {\r\n const userSnapshot: Record<string, unknown> = {\r\n email: user?.email ?? null,\r\n id: user?.id ?? null,\r\n groupId: user?.groupId ?? null,\r\n groupName: user?.groupName ?? null,\r\n isRBACAdmin: user?.isRBACAdmin ?? false,\r\n adminAccess: user?.adminAccess ?? null,\r\n vendorIds: user?.vendorIds ?? [],\r\n activeVendorId: user?.activeVendorId ?? null,\r\n vendorRole: user?.vendorRole ?? null,\r\n isVendorPortal: user?.isVendorPortal ?? false,\r\n isVendorOwner: user?.isVendorOwner ?? false,\r\n isVendorPortalComputed: isVendorPortalUser(user),\r\n isVendorOwnerComputed: isVendorOwner(user),\r\n jwtEntityPerms: summarizeEntityPerms(user?.entityPerms),\r\n jwtEntityPermForTarget: user?.entityPerms?.[entity] ?? null,\r\n };\r\n\r\n if (!user?.email) {\r\n return { allowed: false, reason: 'no_session_email', userSnapshot };\r\n }\r\n if (user.isRBACAdmin) {\r\n return { allowed: true, reason: 'platform_administrator', userSnapshot };\r\n }\r\n\r\n const vendorIds = user.vendorIds ?? [];\r\n const isStaff = user.vendorRole === 'staff';\r\n\r\n if (vendorIds.length > 0) {\r\n if (entity === 'dashboard' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_dashboard_read', userSnapshot };\r\n }\r\n if (entity === 'analytics' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_analytics_read', userSnapshot };\r\n }\r\n if (entity === 'settings') {\r\n if (action === 'read') {\r\n return { allowed: true, reason: 'vendor_link_settings_read', userSnapshot };\r\n }\r\n if (action === 'update' && !isStaff) {\r\n return { allowed: true, reason: 'vendor_link_settings_update', userSnapshot };\r\n }\r\n }\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity)) {\r\n if (isStaff && action === 'read') {\r\n return { allowed: true, reason: 'vendor_staff_store_read', userSnapshot };\r\n }\r\n if (!isStaff) {\r\n return { allowed: true, reason: 'vendor_link_store_full', userSnapshot };\r\n }\r\n return {\r\n allowed: false,\r\n reason: 'vendor_staff_store_write_denied',\r\n userSnapshot,\r\n };\r\n }\r\n }\r\n\r\n if (isVendorPortalUser(user) && isVendorOwner(user)) {\r\n if (entity === 'dashboard' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_owner_group_dashboard', userSnapshot };\r\n }\r\n if (entity === 'analytics' && action === 'read') {\r\n return { allowed: true, reason: 'vendor_owner_group_analytics', userSnapshot };\r\n }\r\n if (entity === 'settings' && (action === 'read' || action === 'update')) {\r\n return { allowed: true, reason: 'vendor_owner_group_settings', userSnapshot };\r\n }\r\n if (VENDOR_STORE_RBAC_ENTITIES.has(entity)) {\r\n return { allowed: true, reason: 'vendor_owner_group_store', userSnapshot };\r\n }\r\n }\r\n\r\n const vendorPortalReason = vendorPortalFallbackReason(user, entity, action);\r\n if (vendorPortalReason) {\r\n return { allowed: true, reason: vendorPortalReason, userSnapshot };\r\n }\r\n\r\n const explicit = user.entityPerms?.[entity];\r\n if (explicit !== undefined) {\r\n const allowed = hasEntityPermission(user.entityPerms, entity, action);\r\n return {\r\n allowed,\r\n reason: allowed ? 'jwt_entity_perms_allow' : 'jwt_entity_perms_deny',\r\n userSnapshot,\r\n };\r\n }\r\n\r\n const allowed = hasEntityPermission(user.entityPerms, entity, action);\r\n return {\r\n allowed,\r\n reason: allowed ? 'entity_perms_fallback_allow' : 'no_matching_rule',\r\n userSnapshot,\r\n };\r\n}\r\n\r\nexport function sessionHasEntityAccessFromExplanation(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n return explainSessionEntityAccess(user, entity, action).allowed;\r\n}\r\n\r\nexport async function logEntityAccessDecision(\r\n dataSource: RbacDebugDataSource | undefined,\r\n context: string,\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction,\r\n extra?: Record<string, unknown>\r\n): Promise<void> {\r\n if (!isRbacDebugEnabled()) return;\r\n\r\n const explanation = explainSessionEntityAccess(user, entity, action);\r\n let dbPermissions: Record<string, unknown> | undefined;\r\n if (dataSource && user?.id) {\r\n const id = Number(user.id);\r\n if (Number.isFinite(id)) {\r\n try {\r\n const { loadDbPermissionsForUser } = await import('./rbac-debug-db');\r\n dbPermissions = await loadDbPermissionsForUser(dataSource, id);\r\n } catch (e) {\r\n dbPermissions = { error: e instanceof Error ? e.message : String(e) };\r\n }\r\n }\r\n }\r\n\r\n logRbac(context, {\r\n entity,\r\n action,\r\n allowed: explanation.allowed,\r\n reason: explanation.reason,\r\n ...explanation.userSnapshot,\r\n dbPermissions,\r\n ...extra,\r\n });\r\n}\r\n","export {\r\n createAuthHelpers,\r\n createCmsAuthBundle,\r\n OPEN_ENDPOINTS,\r\n PERMISSION_REQUIRED_ENDPOINTS,\r\n isOpenEndpoint,\r\n isPublicMethod,\r\n getRequiredPermission,\r\n} from './helpers';\r\nexport type { SessionUser, GetSession, AuthHelpers } from './helpers';\r\nexport { sessionHasEntityAccess, canManageRoles, RBAC_ADMIN_ONLY_ENTITIES } from './helpers';\r\nexport {\r\n isRbacDebugEnabled,\r\n logRbac,\r\n explainSessionEntityAccess,\r\n logEntityAccessDecision,\r\n summarizeEntityPerms,\r\n} from './rbac-debug';\r\nexport {\r\n resolveVendorScopeFromSessionUser,\r\n VENDOR_SCOPED_STORE_ENTITIES,\r\n VENDOR_STORE_RBAC_ENTITIES,\r\n VENDOR_OWNER_GROUP_NAME,\r\n isVendorStaff,\r\n isVendorPortalUser,\r\n isVendorOwner,\r\n isVendorGroupName,\r\n isPlatformAdministrator,\r\n vendorPortalFlagsFromUser,\r\n canOnboardVendors,\r\n canManageVendorTeam,\r\n canManageVendorRoles,\r\n} from './vendor-scope';\r\nexport {\r\n getPermissionableEntityKeys,\r\n ADMIN_GROUP_NAME,\r\n isSuperAdminGroupName,\r\n permissionRowsToRecord,\r\n hasEntityPermission,\r\n} from './permission-entities';\r\nexport { seedAdministratorPermissions } from './seed-permissions';\r\nexport type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nexport { createCmsMiddleware, defaultPublicApiMethods } from './middleware';\r\nexport type { CmsMiddlewareConfig, CmsMiddlewareRequest } from './middleware';\r\nexport {\r\n isAuthDebugEnabled,\r\n isAuthDebugClientEnabled,\r\n logAuth,\r\n logAuthClient,\r\n summarizeSessionUserForLog,\r\n nextAuthCookieDebugInfo,\r\n} from './auth-debug';\r\nexport { getNextAuthOptions } from './nextauth-options';\r\nexport type { NextAuthOptionsConfig, NextAuthUser, AuthorizeOtpInput } from './nextauth-options';\r\n","import type { EntityCrudAction, EntityPermissionFlags } from './permission-entities';\r\nimport { explainSessionEntityAccess, logRbac } from './rbac-debug';\r\nimport { isVendorPortalUser } from './vendor-scope';\r\n\r\n/**\r\n * @deprecated Administrator bypass is now full entity access via `isRBACAdmin` in `sessionHasEntityAccess`.\r\n * Kept for backwards-compatible imports.\r\n */\r\nexport const RBAC_ADMIN_ONLY_ENTITIES = new Set(['users', 'user_groups', 'permissions']);\r\n\r\nexport interface SessionUser {\r\n id?: string;\r\n email?: string | null;\r\n name?: string | null;\r\n groupId?: number;\r\n /** User group display name (from login). */\r\n groupName?: string | null;\r\n /** @deprecated use entityPerms / isRBACAdmin */\r\n permissions?: string[];\r\n /** Administrator group: bypasses entity-level RBAC on all resources */\r\n isRBACAdmin?: boolean;\r\n entityPerms?: Record<string, EntityPermissionFlags>;\r\n /** When false and not isRBACAdmin, admin API/UI is denied. */\r\n adminAccess?: boolean;\r\n /** Vendor stores this user can access (from vendor_users). */\r\n vendorIds?: number[];\r\n /** Active vendor for scoped CRUD (vendor staff). */\r\n activeVendorId?: number | null;\r\n /** Role for the active vendor link (`vendor_users.role`). */\r\n vendorRole?: 'owner' | 'staff' | null;\r\n /** Set at login: vendor store portal (not platform admin). */\r\n isVendorPortal?: boolean;\r\n /** Set at login: vendor store owner (team + permissions). */\r\n isVendorOwner?: boolean;\r\n}\r\n\r\nexport function sessionHasEntityAccess(\r\n user: SessionUser | null | undefined,\r\n entity: string,\r\n action: EntityCrudAction\r\n): boolean {\r\n return explainSessionEntityAccess(user, entity, action).allowed;\r\n}\r\n\r\nexport function canManageRoles(user: SessionUser | null | undefined): boolean {\r\n return !!(user?.email && user.isRBACAdmin);\r\n}\r\n\r\nexport type GetSession = () => Promise<{ user?: SessionUser } | null>;\r\n\r\nexport const OPEN_ENDPOINTS: Array<Record<string, string[]>> = [\r\n { '/api/contacts': ['POST'] },\r\n { '/api/form-submissions': ['POST'] },\r\n { '/api/blogs': ['GET'] },\r\n];\r\n\r\nexport const PERMISSION_REQUIRED_ENDPOINTS: Record<string, string[]> = {};\r\n\r\nexport function isOpenEndpoint(pathname: string): boolean {\r\n return OPEN_ENDPOINTS.some((endpoint) => pathname.startsWith(Object.keys(endpoint)[0]));\r\n}\r\n\r\nexport function getRequiredPermission(pathname: string): string[] | null {\r\n return null;\r\n}\r\n\r\nexport function isPublicMethod(pathname: string, method: string): boolean {\r\n for (const endpoint of OPEN_ENDPOINTS) {\r\n const key = Object.keys(endpoint)[0];\r\n if (pathname.startsWith(key) && endpoint[key].includes(method)) return true;\r\n }\r\n return false;\r\n}\r\n\r\nexport interface AuthHelpers {\r\n requireAuth(req: Request): Promise<Response | null>;\r\n requirePermission(req: Request, permission: string): Promise<Response | null>;\r\n requireEntityPermission(req: Request, entity: string, action: EntityCrudAction): Promise<Response | null>;\r\n requireAdminAccess(req: Request): Promise<Response | null>;\r\n getAuthenticatedUser(): Promise<SessionUser | null>;\r\n}\r\n\r\nexport function createAuthHelpers(getSession: GetSession, NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }): AuthHelpers {\r\n return createAuthHelpersFromGetSession(getSession, NextResponse);\r\n}\r\n\r\n/** Pass return value into `createCmsApiHandler` (includes `getSessionUser` for vendor store APIs). */\r\nexport function createCmsAuthBundle(\r\n getSession: GetSession,\r\n NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }\r\n) {\r\n const auth = createAuthHelpers(getSession, NextResponse);\r\n return {\r\n requireAuth: auth.requireAuth,\r\n requireAdminAccess: auth.requireAdminAccess,\r\n requireEntityPermission: auth.requireEntityPermission,\r\n getSessionUser: auth.getAuthenticatedUser,\r\n getAuthenticatedUser: auth.getAuthenticatedUser,\r\n };\r\n}\r\n\r\nfunction createAuthHelpersFromGetSession(\r\n getSession: GetSession,\r\n NextResponse: { json: (body: unknown, init?: { status?: number }) => Response }\r\n): AuthHelpers {\r\n return {\r\n async requireAuth() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n return null;\r\n },\r\n async requirePermission() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n return null;\r\n },\r\n async requireEntityPermission(_req: Request, entity: string, action: EntityCrudAction) {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n const u = session.user as SessionUser;\r\n const allowed = sessionHasEntityAccess(u, entity, action);\r\n const { reason } = explainSessionEntityAccess(u, entity, action);\r\n logRbac('authHelpers.requireEntityPermission', {\r\n entity,\r\n action,\r\n allowed,\r\n reason,\r\n email: u.email,\r\n groupName: u.groupName,\r\n vendorIds: u.vendorIds,\r\n isVendorPortal: u.isVendorPortal,\r\n isVendorOwner: u.isVendorOwner,\r\n });\r\n if (allowed) return null;\r\n return NextResponse.json({ error: 'Forbidden', entity, action, reason }, { status: 403 });\r\n },\r\n async requireAdminAccess() {\r\n const session = await getSession();\r\n if (!session?.user?.email) {\r\n return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });\r\n }\r\n const u = session.user as SessionUser;\r\n if (u.isRBACAdmin) return null;\r\n // Vendor portal users always have admin UI access for their store — check\r\n // before adminAccess so that vendor users (who have adminAccess:false from\r\n // the DB default) are not incorrectly denied.\r\n if (isVendorPortalUser(u)) return null;\r\n if (u.adminAccess === true) return null;\r\n if (u.adminAccess === false) {\r\n logRbac('requireAdminAccess denied (adminAccess:false)', {\r\n email: u.email,\r\n groupName: u.groupName,\r\n isVendorPortal: u.isVendorPortal,\r\n });\r\n return NextResponse.json({ error: 'Forbidden', reason: 'admin_access' }, { status: 403 });\r\n }\r\n logRbac('requireAdminAccess denied (no matching rule)', {\r\n email: u.email,\r\n adminAccess: u.adminAccess,\r\n groupName: u.groupName,\r\n isVendorPortal: u.isVendorPortal,\r\n });\r\n return NextResponse.json({ error: 'Forbidden', reason: 'admin_access' }, { status: 403 });\r\n },\r\n async getAuthenticatedUser() {\r\n const session = await getSession();\r\n return (session?.user as SessionUser) ?? null;\r\n },\r\n };\r\n}\r\n","import type { DataSource } from 'typeorm';\r\nimport type { EntityTarget } from 'typeorm';\r\nimport type { ObjectLiteral } from 'typeorm';\r\nimport { getPermissionableEntityKeys, ADMIN_GROUP_NAME } from './permission-entities';\r\n\r\n/**\r\n * Ensures the Administrator group has full CRUD on every permissionable entity\r\n * for the given entity map. Idempotent: upserts per entity.\r\n */\r\nexport async function seedAdministratorPermissions(\r\n dataSource: DataSource,\r\n entityMap: Record<string, unknown>\r\n): Promise<void> {\r\n const entities = getPermissionableEntityKeys(entityMap);\r\n const groupRepo = dataSource.getRepository(entityMap.user_groups as EntityTarget<ObjectLiteral>);\r\n const permRepo = dataSource.getRepository(entityMap.permissions as EntityTarget<ObjectLiteral>);\r\n\r\n const adminGroup = await groupRepo.findOne({ where: { name: ADMIN_GROUP_NAME, deleted: false } });\r\n console.log(\"ADMIN GROUP\", adminGroup);\r\n if (!adminGroup) return;\r\n\r\n const fullCrud = { canCreate: true, canRead: true, canUpdate: true, canDelete: true };\r\n\r\n for (const entity of entities) {\r\n const existing = await permRepo.findOne({\r\n where: { groupId: adminGroup.id, entity },\r\n });\r\n console.log(\"EXISTING\", existing);\r\n if (existing) {\r\n existing.canCreate = true;\r\n existing.canRead = true;\r\n existing.canUpdate = true;\r\n existing.canDelete = true;\r\n await permRepo.save(existing);\r\n } else {\r\n await permRepo.save(\r\n permRepo.create({\r\n groupId: adminGroup.id,\r\n entity,\r\n ...fullCrud,\r\n })\r\n );\r\n }\r\n }\r\n}\r\n","import { getToken } from 'next-auth/jwt';\r\nimport { logAuth } from './auth-debug';\r\n\r\nexport interface CmsMiddlewareRequest {\r\n nextUrl: { pathname: string };\r\n url: string;\r\n method: string;\r\n cookies: { get: (name: string) => { value?: string } | undefined };\r\n /**\r\n * Full Next.js request (e.g. `NextRequest`). When provided, session is resolved via\r\n * `getToken()` so chunked `next-auth.session-token.N` cookies work.\r\n */\r\n req?: Parameters<typeof getToken>[0]['req'];\r\n}\r\n\r\nexport interface CmsMiddlewareConfig {\r\n publicAdminPaths?: string[];\r\n publicApiPaths?: string[];\r\n /** path -> allowed methods */\r\n publicApiMethods?: Record<string, string[]>;\r\n signInPath?: string;\r\n /** @deprecated Prefer passing `req` on the request; used only when `req` is omitted. */\r\n getSessionToken?: (request: CmsMiddlewareRequest) => string | undefined;\r\n secret?: string;\r\n}\r\n\r\n/** Default public API paths (no auth). Sites should extend this with their own routes. */\r\nexport const defaultPublicApiMethods: Record<string, string[]> = {\r\n '/api/contacts': ['POST'],\r\n '/api/form-submissions': ['POST'],\r\n '/api/blogs': ['GET'],\r\n '/api/forms': ['GET'],\r\n '/api/auth': ['GET', 'POST'],\r\n '/api/health': ['GET'],\r\n '/api/users/forgot-password': ['POST'],\r\n '/api/users/set-password': ['POST'],\r\n '/api/users/invite': ['POST'],\r\n};\r\n\r\nfunction legacyGetSessionToken(request: CmsMiddlewareRequest): string | undefined {\r\n const secure = request.cookies.get('__Secure-next-auth.session-token')?.value;\r\n const regular = request.cookies.get('next-auth.session-token')?.value;\r\n return secure ?? regular;\r\n}\r\n\r\nfunction sessionCookiePresence(request: CmsMiddlewareRequest) {\r\n const secure = request.cookies.get('__Secure-next-auth.session-token')?.value;\r\n const regular = request.cookies.get('next-auth.session-token')?.value;\r\n const hasChunked =\r\n Boolean(request.cookies.get('next-auth.session-token.0')?.value) ||\r\n Boolean(request.cookies.get('__Secure-next-auth.session-token.0')?.value);\r\n return {\r\n hasSecureToken: Boolean(secure),\r\n hasRegularToken: Boolean(regular),\r\n hasChunkedToken: hasChunked,\r\n resolved: Boolean(secure ?? regular),\r\n };\r\n}\r\n\r\nfunction isPublicMethod(pathname: string, method: string, publicApiMethods: Record<string, string[]>): boolean {\r\n for (const [endpoint, methods] of Object.entries(publicApiMethods)) {\r\n if (pathname.startsWith(endpoint) && methods.includes(method)) return true;\r\n }\r\n return false;\r\n}\r\n\r\nasync function hasValidSession(\r\n request: CmsMiddlewareRequest,\r\n secret: string | undefined,\r\n legacyGetToken: (request: CmsMiddlewareRequest) => string | undefined\r\n): Promise<boolean> {\r\n if (request.req) {\r\n const token = await getToken({ req: request.req, secret });\r\n return token != null;\r\n }\r\n return Boolean(legacyGetToken(request));\r\n}\r\n\r\n/**\r\n * Returns middleware logic. Use from Next.js middleware:\r\n * import { createCmsMiddleware } from '@infuro/cms-core';\r\n * export async function middleware(request: NextRequest) {\r\n * const result = await cmsMiddleware({ ...request fields, req: request });\r\n * ...\r\n * }\r\n * export const config = { matcher: ['/admin/:path*', '/api/:path*'] };\r\n */\r\nexport function createCmsMiddleware(config: CmsMiddlewareConfig = {}) {\r\n const {\r\n publicAdminPaths = ['/admin/signin', '/admin/forgot-password', '/admin/reset-password', '/admin/invite'],\r\n publicApiMethods = defaultPublicApiMethods,\r\n signInPath = '/admin/signin',\r\n getSessionToken = legacyGetSessionToken,\r\n secret = process.env.NEXTAUTH_SECRET,\r\n } = config;\r\n\r\n return async function cmsMiddleware(\r\n request: CmsMiddlewareRequest\r\n ): Promise<{ type: 'next' } | { type: 'redirect'; url: string } | { type: 'json'; status: number; body: unknown }> {\r\n const pathname = request.nextUrl.pathname;\r\n const method = request.method;\r\n\r\n if (publicAdminPaths.some((p) => pathname === p || pathname.startsWith(p + '/'))) {\r\n return { type: 'next' };\r\n }\r\n\r\n if (pathname.startsWith('/admin')) {\r\n const authenticated = await hasValidSession(request, secret, getSessionToken);\r\n const cookies = sessionCookiePresence(request);\r\n if (!authenticated) {\r\n logAuth('middleware: admin redirect to signin (no session)', {\r\n pathname,\r\n method,\r\n usesGetToken: Boolean(request.req),\r\n ...cookies,\r\n expectedCookieName: process.env.NEXTAUTH_URL?.startsWith('https')\r\n ? '__Secure-next-auth.session-token'\r\n : 'next-auth.session-token',\r\n });\r\n return { type: 'redirect', url: new URL(signInPath, request.url).toString() };\r\n }\r\n logAuth('middleware: admin allowed', {\r\n pathname,\r\n method,\r\n usesGetToken: Boolean(request.req),\r\n ...cookies,\r\n });\r\n }\r\n\r\n if (pathname.startsWith('/api')) {\r\n if (isPublicMethod(pathname, method, publicApiMethods)) {\r\n return { type: 'next' };\r\n }\r\n const authenticated = await hasValidSession(request, secret, getSessionToken);\r\n if (!authenticated) {\r\n logAuth('middleware: api 401 (no session)', {\r\n pathname,\r\n method,\r\n usesGetToken: Boolean(request.req),\r\n ...sessionCookiePresence(request),\r\n });\r\n return { type: 'json', status: 401, body: { error: 'Unauthorized' } };\r\n }\r\n }\r\n\r\n return { type: 'next' };\r\n };\r\n}\r\n","const LOG_PREFIX = '[cms-auth]';\r\n\r\n/** Set `CMS_AUTH_DEBUG=false` to silence server auth logs in development. */\r\nexport function isAuthDebugEnabled(): boolean {\r\n const v = process.env.CMS_AUTH_DEBUG?.trim().toLowerCase();\r\n if (v === '1' || v === 'true' || v === 'yes') return true;\r\n if (v === '0' || v === 'false' || v === 'no') return false;\r\n return process.env.NODE_ENV === 'development';\r\n}\r\n\r\n/** Browser console logs; set `NEXT_PUBLIC_CMS_AUTH_DEBUG=false` to silence. */\r\nexport function isAuthDebugClientEnabled(): boolean {\r\n if (typeof window === 'undefined') return false;\r\n const v = process.env.NEXT_PUBLIC_CMS_AUTH_DEBUG?.trim().toLowerCase();\r\n if (v === '1' || v === 'true' || v === 'yes') return true;\r\n if (v === '0' || v === 'false' || v === 'no') return false;\r\n return process.env.NODE_ENV === 'development';\r\n}\r\n\r\nexport function logAuth(message: string, data?: Record<string, unknown>): void {\r\n if (!isAuthDebugEnabled()) return;\r\n if (data) console.info(LOG_PREFIX, message, data);\r\n else console.info(LOG_PREFIX, message);\r\n}\r\n\r\nexport function logAuthClient(message: string, data?: Record<string, unknown>): void {\r\n if (!isAuthDebugClientEnabled()) return;\r\n if (data) console.info(LOG_PREFIX, message, data);\r\n else console.info(LOG_PREFIX, message);\r\n}\r\n\r\nexport function summarizeSessionUserForLog(user: unknown): Record<string, unknown> {\r\n if (!user || typeof user !== 'object') return { present: false };\r\n const u = user as Record<string, unknown>;\r\n return {\r\n present: true,\r\n email: u.email ?? null,\r\n id: u.id ?? null,\r\n adminAccess: u.adminAccess ?? null,\r\n isRBACAdmin: u.isRBACAdmin ?? null,\r\n isVendorPortal: u.isVendorPortal ?? null,\r\n groupName: u.groupName ?? null,\r\n };\r\n}\r\n\r\nexport function nextAuthCookieDebugInfo(): Record<string, unknown> {\r\n const nextAuthUrl = process.env.NEXTAUTH_URL ?? '(unset)';\r\n const isHttps = nextAuthUrl.startsWith('https');\r\n return {\r\n nextAuthUrl,\r\n hasSecret: Boolean(process.env.NEXTAUTH_SECRET),\r\n cookieName: isHttps ? '__Secure-next-auth.session-token' : 'next-auth.session-token',\r\n cookieSecure: isHttps,\r\n nodeEnv: process.env.NODE_ENV ?? '(unset)',\r\n };\r\n}\r\n","/**\r\n * Build NextAuth options for credentials auth. App can extend/override via extend().\r\n */\r\nimport type { NextAuthOptions } from 'next-auth';\r\nimport _CredentialsProvider from 'next-auth/providers/credentials';\r\nconst CredentialsProvider = (_CredentialsProvider as unknown as { default: typeof _CredentialsProvider }).default ?? _CredentialsProvider;\r\nimport { isSuperAdminGroupName, permissionRowsToRecord } from './permission-entities';\r\nimport { vendorPortalFlagsFromUser } from './vendor-scope';\r\nimport { logAuth, nextAuthCookieDebugInfo, summarizeSessionUserForLog } from './auth-debug';\r\n\r\nexport interface NextAuthUser {\r\n id: number;\r\n email: string;\r\n name: string | null;\r\n password: string | null;\r\n blocked?: boolean;\r\n deleted?: boolean;\r\n groupId?: number | null;\r\n adminAccess?: boolean;\r\n group?: {\r\n name?: string;\r\n permissions?: Array<{\r\n entity: string;\r\n canCreate: boolean;\r\n canRead: boolean;\r\n canUpdate: boolean;\r\n canDelete: boolean;\r\n }>;\r\n };\r\n vendorIds?: number[];\r\n activeVendorId?: number | null;\r\n vendorRole?: 'owner' | 'staff' | null;\r\n}\r\n\r\nexport interface AuthorizeOtpInput {\r\n identifier: string;\r\n channel: 'email' | 'sms';\r\n code: string;\r\n}\r\n\r\nexport interface NextAuthOptionsConfig {\r\n /** Resolve user by email (e.g. from TypeORM). Return null if not found. */\r\n getUserByEmail: (email: string) => Promise<NextAuthUser | null>;\r\n comparePassword: (plain: string, hash: string) => Promise<boolean>;\r\n signInPage?: string;\r\n secret?: string;\r\n extend?: (options: NextAuthOptions) => NextAuthOptions;\r\n /** When false, password CredentialsProvider is omitted. Default true. */\r\n enablePasswordLogin?: boolean;\r\n /** When true, registers CredentialsProvider id `otp`. Requires authorizeOtp. Default false. */\r\n enableOtpLogin?: boolean;\r\n /** Validate OTP and return user (same shape as password flow) or null. */\r\n authorizeOtp?: (input: AuthorizeOtpInput) => Promise<NextAuthUser | null>;\r\n}\r\n\r\nfunction sessionUserFromNextAuthUser(user: NextAuthUser) {\r\n const g = user.group;\r\n const isRBACAdmin = isSuperAdminGroupName(g?.name);\r\n const entityPerms = permissionRowsToRecord(g?.permissions);\r\n // Preserve the DB value as-is: true → true, false → false, null/undefined → undefined.\r\n // Coercing null to false would make requireAdminAccess deny vendor/unset users before\r\n // the vendor-portal check can allow them.\r\n const rawAdminAccess = (user as NextAuthUser & { adminAccess?: boolean }).adminAccess;\r\n const adminAccess: boolean | undefined =\r\n rawAdminAccess === true ? true : rawAdminAccess === false ? false : undefined;\r\n const vendorIds = user.vendorIds ?? [];\r\n const vendorRole = user.vendorRole ?? null;\r\n const { isVendorPortal, isVendorOwner } = vendorPortalFlagsFromUser({\r\n email: user.email,\r\n isRBACAdmin,\r\n groupName: g?.name,\r\n vendorIds,\r\n vendorRole,\r\n });\r\n return {\r\n id: user.id.toString(),\r\n email: user.email,\r\n name: user.name,\r\n groupId: user.groupId ?? undefined,\r\n groupName: g?.name ?? undefined,\r\n isRBACAdmin,\r\n entityPerms,\r\n adminAccess,\r\n vendorIds,\r\n activeVendorId: user.activeVendorId ?? vendorIds[0] ?? null,\r\n vendorRole,\r\n isVendorPortal,\r\n isVendorOwner,\r\n };\r\n}\r\n\r\nexport function getNextAuthOptions(config: NextAuthOptionsConfig): NextAuthOptions {\r\n const {\r\n getUserByEmail,\r\n comparePassword,\r\n signInPage = '/admin/signin',\r\n secret,\r\n extend,\r\n enablePasswordLogin = true,\r\n enableOtpLogin = false,\r\n authorizeOtp,\r\n } = config;\r\n\r\n logAuth('getNextAuthOptions init', nextAuthCookieDebugInfo());\r\n\r\n const providers: NextAuthOptions['providers'] = [];\r\n\r\n if (enablePasswordLogin) {\r\n providers.push(\r\n CredentialsProvider({\r\n name: 'credentials',\r\n credentials: {\r\n email: { label: 'Email', type: 'email' },\r\n password: { label: 'Password', type: 'password' },\r\n },\r\n async authorize(credentials) {\r\n const email = credentials?.email?.trim() ?? '';\r\n if (!email || !credentials?.password) {\r\n logAuth('authorize(credentials) rejected', { reason: 'missing_email_or_password' });\r\n return null;\r\n }\r\n try {\r\n const user = await getUserByEmail(email);\r\n if (!user) {\r\n logAuth('authorize(credentials) rejected', { reason: 'user_not_found', email });\r\n return null;\r\n }\r\n if (user.blocked) {\r\n logAuth('authorize(credentials) rejected', { reason: 'blocked', email, userId: user.id });\r\n return null;\r\n }\r\n if ((user as { deleted?: boolean }).deleted) {\r\n logAuth('authorize(credentials) rejected', { reason: 'deleted', email, userId: user.id });\r\n return null;\r\n }\r\n if (!user.password) {\r\n logAuth('authorize(credentials) rejected', { reason: 'no_password', email, userId: user.id });\r\n return null;\r\n }\r\n const valid = await comparePassword(credentials.password, user.password);\r\n if (!valid) {\r\n logAuth('authorize(credentials) rejected', { reason: 'invalid_password', email, userId: user.id });\r\n return null;\r\n }\r\n const sessionUser = sessionUserFromNextAuthUser(user);\r\n logAuth('authorize(credentials) ok', summarizeSessionUserForLog(sessionUser));\r\n return sessionUser;\r\n } catch (err) {\r\n // Log so infrastructure errors (DB down, missing entity, etc.) are\r\n // visible in server logs rather than silently failing as \"wrong password\".\r\n console.error('[cms-auth] authorize error (credentials):', err instanceof Error ? err.message : err);\r\n logAuth('authorize(credentials) error', {\r\n email,\r\n message: err instanceof Error ? err.message : String(err),\r\n });\r\n return null;\r\n }\r\n },\r\n })\r\n );\r\n }\r\n\r\n if (enableOtpLogin && authorizeOtp) {\r\n providers.push(\r\n CredentialsProvider({\r\n id: 'otp',\r\n name: 'otp',\r\n credentials: {\r\n identifier: { label: 'Email or phone', type: 'text' },\r\n code: { label: 'Code', type: 'text' },\r\n channel: { label: 'Channel', type: 'text' },\r\n },\r\n async authorize(credentials) {\r\n const identifier = typeof credentials?.identifier === 'string' ? credentials.identifier.trim() : '';\r\n const code = typeof credentials?.code === 'string' ? credentials.code.trim() : '';\r\n const ch = credentials?.channel === 'sms' ? 'sms' : 'email';\r\n if (!identifier || !code) return null;\r\n try {\r\n const user = await authorizeOtp({ identifier, channel: ch, code });\r\n if (!user || user.blocked || (user as { deleted?: boolean }).deleted) return null;\r\n return sessionUserFromNextAuthUser(user);\r\n } catch (err) {\r\n console.error('[cms-auth] authorize error (otp):', err instanceof Error ? err.message : err);\r\n return null;\r\n }\r\n },\r\n })\r\n );\r\n }\r\n\r\n const options: NextAuthOptions = {\r\n secret: secret ?? process.env.NEXTAUTH_SECRET,\r\n providers,\r\n session: { strategy: 'jwt' },\r\n pages: { signIn: signInPage },\r\n cookies: {\r\n sessionToken: {\r\n name: process.env.NEXTAUTH_URL?.startsWith('https')\r\n ? '__Secure-next-auth.session-token'\r\n : 'next-auth.session-token',\r\n options: {\r\n httpOnly: true,\r\n sameSite: 'lax',\r\n path: '/',\r\n secure: process.env.NEXTAUTH_URL?.startsWith('https') ?? false,\r\n },\r\n },\r\n },\r\n callbacks: {\r\n async jwt({ token, user, trigger, session }) {\r\n if (user) {\r\n logAuth('jwt callback: new sign-in', {\r\n trigger,\r\n user: summarizeSessionUserForLog(user),\r\n });\r\n const u = user as unknown as Record<string, unknown>;\r\n (token as Record<string, unknown>).id = u.id;\r\n (token as Record<string, unknown>).groupId = u.groupId;\r\n (token as Record<string, unknown>).groupName = u.groupName;\r\n (token as Record<string, unknown>).isRBACAdmin = u.isRBACAdmin;\r\n (token as Record<string, unknown>).entityPerms = u.entityPerms;\r\n (token as Record<string, unknown>).adminAccess = u.adminAccess;\r\n (token as Record<string, unknown>).vendorIds = u.vendorIds;\r\n (token as Record<string, unknown>).activeVendorId = u.activeVendorId;\r\n (token as Record<string, unknown>).vendorRole = u.vendorRole;\r\n (token as Record<string, unknown>).isVendorPortal = u.isVendorPortal;\r\n (token as Record<string, unknown>).isVendorOwner = u.isVendorOwner;\r\n }\r\n if (trigger === 'update' && session && typeof session === 'object') {\r\n logAuth('jwt callback: session update', { trigger });\r\n const s = session as Record<string, unknown>;\r\n const t = token as Record<string, unknown>;\r\n if (typeof s.name === 'string') t.name = s.name;\r\n if (typeof s.email === 'string') t.email = s.email;\r\n if (typeof s.activeVendorId === 'number') t.activeVendorId = s.activeVendorId;\r\n }\r\n return token;\r\n },\r\n async session({ session, token }) {\r\n const t = token as Record<string, unknown>;\r\n logAuth('session callback', {\r\n tokenHasId: t.id != null,\r\n tokenEmail: typeof t.email === 'string' ? t.email : null,\r\n sessionUser: summarizeSessionUserForLog(session.user),\r\n });\r\n if (session.user) {\r\n if (typeof t.name === 'string') session.user.name = t.name;\r\n if (typeof t.email === 'string') session.user.email = t.email;\r\n (session.user as Record<string, unknown>).id = t.id;\r\n (session.user as Record<string, unknown>).groupId = t.groupId;\r\n (session.user as Record<string, unknown>).groupName = t.groupName;\r\n (session.user as Record<string, unknown>).isRBACAdmin = t.isRBACAdmin;\r\n (session.user as Record<string, unknown>).entityPerms = t.entityPerms;\r\n (session.user as Record<string, unknown>).adminAccess = t.adminAccess;\r\n (session.user as Record<string, unknown>).vendorIds = t.vendorIds;\r\n (session.user as Record<string, unknown>).activeVendorId = t.activeVendorId;\r\n (session.user as Record<string, unknown>).vendorRole = t.vendorRole;\r\n (session.user as Record<string, unknown>).isVendorPortal = t.isVendorPortal;\r\n (session.user as Record<string, unknown>).isVendorOwner = t.isVendorOwner;\r\n }\r\n return session;\r\n },\r\n },\r\n };\r\n\r\n return extend ? extend(options) : options;\r\n}\r\n"],"mappings":"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","names":["isVendorOwner","allowed","loadDbPermissionsForUser","LOG_PREFIX","isPublicMethod","_CredentialsProvider","isVendorOwner"]}
|