@infuro/cms-core 1.0.30 → 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 +20 -15
- package/dist/admin.cjs +13061 -7814
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +13 -2
- package/dist/admin.d.ts +13 -2
- package/dist/admin.js +8416 -3167
- package/dist/admin.js.map +1 -1
- package/dist/api.cjs +5667 -1110
- package/dist/api.cjs.map +1 -1
- package/dist/api.d.cts +2 -2
- package/dist/api.d.ts +2 -2
- package/dist/api.js +5418 -855
- package/dist/api.js.map +1 -1
- package/dist/auth.cjs +620 -76
- package/dist/auth.cjs.map +1 -1
- package/dist/auth.d.cts +93 -52
- package/dist/auth.d.ts +93 -52
- package/dist/auth.js +578 -52
- package/dist/auth.js.map +1 -1
- package/dist/cli.cjs +19 -15
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +19 -15
- package/dist/cli.js.map +1 -1
- package/dist/{index-BPQSXgXF.d.cts → index-DWd5Gjc4.d.ts} +38 -5
- package/dist/{index-D9SdaDJ0.d.ts → index-rZTnpK7y.d.cts} +38 -5
- package/dist/index.cjs +5921 -1177
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +334 -59
- package/dist/index.d.ts +334 -59
- package/dist/index.js +5733 -1026
- package/dist/index.js.map +1 -1
- package/dist/migrations/1775400000001-AddDiscountAndOrderAddresses.ts +274 -0
- package/dist/migrations/1775800000000-VendorsAndVendorUsers.ts +74 -0
- package/dist/migrations/1775900000000-StoreVendorIdColumns.ts +124 -0
- package/dist/migrations/1775910000000-VendorOwnerRbacSeed.ts +54 -0
- package/dist/migrations/1775920000000-VendorOwnerSettingsPermission.ts +25 -0
- package/dist/migrations/1775930000000-VendorGroupStorePermissions.ts +54 -0
- package/dist/migrations/1775940000000-VendorRls.ts +71 -0
- package/dist/migrations/1775950000000-VendorCustomers.ts +87 -0
- package/dist/migrations/1775950000001-VendorCustomersPermissions.ts +67 -0
- package/dist/migrations/1778652250860-CreateCurrencyTables.ts +16 -0
- package/dist/migrations/1778652250861-OrderAddressTables.ts +88 -0
- package/dist/migrations/1778652250862-UpdateDiscountandRules.ts +100 -0
- package/dist/migrations/1778652250863-MakeCouponCodeNullable.ts +19 -0
- package/dist/migrations/1778652250864-RemoveUniqueConstraintFromDiscountCouponCode.ts +22 -0
- package/dist/migrations/1778652250865-FixOrdersAddressForeignKeys.ts +71 -0
- package/dist/migrations/1778660000000-DiscountVendorId.ts +90 -0
- package/dist/migrations/1778660000001-FixOrdersAddressFkToOrderAddresses.ts +79 -0
- package/dist/migrations/1778660000002-VendorUserIdInviteStatus.ts +61 -0
- 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/dist/theme.d.cts +2 -2
- package/dist/theme.d.ts +2 -2
- package/dist/{types-D34wmivy.d.cts → types-DCVaXlPV.d.cts} +1 -1
- package/dist/{types-D34wmivy.d.ts → types-DCVaXlPV.d.ts} +1 -1
- package/dist/vendor-scope-DTYhJk_I.d.cts +129 -0
- package/dist/vendor-scope-DTYhJk_I.d.ts +129 -0
- package/package.json +3 -2
- package/dist/helpers-dlrF_49e.d.cts +0 -60
- package/dist/helpers-dlrF_49e.d.ts +0 -60
package/dist/auth.cjs
CHANGED
|
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
8
11
|
var __export = (target, all) => {
|
|
9
12
|
for (var name in all)
|
|
10
13
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -27,57 +30,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
27
30
|
));
|
|
28
31
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
32
|
|
|
30
|
-
// src/auth/index.ts
|
|
31
|
-
var auth_exports = {};
|
|
32
|
-
__export(auth_exports, {
|
|
33
|
-
ADMIN_GROUP_NAME: () => ADMIN_GROUP_NAME,
|
|
34
|
-
OPEN_ENDPOINTS: () => OPEN_ENDPOINTS,
|
|
35
|
-
PERMISSION_REQUIRED_ENDPOINTS: () => PERMISSION_REQUIRED_ENDPOINTS,
|
|
36
|
-
RBAC_ADMIN_ONLY_ENTITIES: () => RBAC_ADMIN_ONLY_ENTITIES,
|
|
37
|
-
canManageRoles: () => canManageRoles,
|
|
38
|
-
createAuthHelpers: () => createAuthHelpers,
|
|
39
|
-
createCmsMiddleware: () => createCmsMiddleware,
|
|
40
|
-
defaultPublicApiMethods: () => defaultPublicApiMethods,
|
|
41
|
-
getNextAuthOptions: () => getNextAuthOptions,
|
|
42
|
-
getPermissionableEntityKeys: () => getPermissionableEntityKeys,
|
|
43
|
-
getRequiredPermission: () => getRequiredPermission,
|
|
44
|
-
hasEntityPermission: () => hasEntityPermission,
|
|
45
|
-
isOpenEndpoint: () => isOpenEndpoint,
|
|
46
|
-
isPublicMethod: () => isPublicMethod,
|
|
47
|
-
isSuperAdminGroupName: () => isSuperAdminGroupName,
|
|
48
|
-
permissionRowsToRecord: () => permissionRowsToRecord,
|
|
49
|
-
seedAdministratorPermissions: () => seedAdministratorPermissions,
|
|
50
|
-
sessionHasEntityAccess: () => sessionHasEntityAccess
|
|
51
|
-
});
|
|
52
|
-
module.exports = __toCommonJS(auth_exports);
|
|
53
|
-
|
|
54
33
|
// src/auth/permission-entities.ts
|
|
55
|
-
var PERMISSION_ENTITY_INTERNAL_EXCLUDE = /* @__PURE__ */ new Set([
|
|
56
|
-
"users",
|
|
57
|
-
"password_reset_tokens",
|
|
58
|
-
"user_groups",
|
|
59
|
-
"permissions",
|
|
60
|
-
"comments",
|
|
61
|
-
"form_fields",
|
|
62
|
-
"configs",
|
|
63
|
-
"knowledge_base_chunks",
|
|
64
|
-
"carts",
|
|
65
|
-
"cart_items",
|
|
66
|
-
"wishlists",
|
|
67
|
-
"wishlist_items",
|
|
68
|
-
"message_templates"
|
|
69
|
-
]);
|
|
70
|
-
var PERMISSION_LOGICAL_ENTITIES = [
|
|
71
|
-
"users",
|
|
72
|
-
"forms",
|
|
73
|
-
"form_submissions",
|
|
74
|
-
"dashboard",
|
|
75
|
-
"upload",
|
|
76
|
-
"settings",
|
|
77
|
-
"analytics",
|
|
78
|
-
"chat"
|
|
79
|
-
];
|
|
80
|
-
var ADMIN_GROUP_NAME = "Administrator";
|
|
81
34
|
function isSuperAdminGroupName(name) {
|
|
82
35
|
return name === ADMIN_GROUP_NAME;
|
|
83
36
|
}
|
|
@@ -107,13 +60,364 @@ function hasEntityPermission(record, entity, action) {
|
|
|
107
60
|
if (action === "update") return p.u;
|
|
108
61
|
return p.d;
|
|
109
62
|
}
|
|
63
|
+
var PERMISSION_ENTITY_INTERNAL_EXCLUDE, PERMISSION_LOGICAL_ENTITIES, ADMIN_GROUP_NAME;
|
|
64
|
+
var init_permission_entities = __esm({
|
|
65
|
+
"src/auth/permission-entities.ts"() {
|
|
66
|
+
"use strict";
|
|
67
|
+
PERMISSION_ENTITY_INTERNAL_EXCLUDE = /* @__PURE__ */ new Set([
|
|
68
|
+
"users",
|
|
69
|
+
"password_reset_tokens",
|
|
70
|
+
"user_groups",
|
|
71
|
+
"permissions",
|
|
72
|
+
"comments",
|
|
73
|
+
"form_fields",
|
|
74
|
+
"configs",
|
|
75
|
+
"knowledge_base_chunks",
|
|
76
|
+
"carts",
|
|
77
|
+
"cart_items",
|
|
78
|
+
"wishlists",
|
|
79
|
+
"wishlist_items",
|
|
80
|
+
"message_templates",
|
|
81
|
+
"vendor_users"
|
|
82
|
+
]);
|
|
83
|
+
PERMISSION_LOGICAL_ENTITIES = [
|
|
84
|
+
"users",
|
|
85
|
+
"forms",
|
|
86
|
+
"form_submissions",
|
|
87
|
+
"dashboard",
|
|
88
|
+
"upload",
|
|
89
|
+
"settings",
|
|
90
|
+
"analytics",
|
|
91
|
+
"chat"
|
|
92
|
+
];
|
|
93
|
+
ADMIN_GROUP_NAME = "Administrator";
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// src/auth/vendor-scope.ts
|
|
98
|
+
function isVendorGroupName(name) {
|
|
99
|
+
if (!name?.trim()) return false;
|
|
100
|
+
const n = name.trim().toLowerCase();
|
|
101
|
+
return n === VENDOR_OWNER_GROUP_NAME.toLowerCase() || n.includes("vendor");
|
|
102
|
+
}
|
|
103
|
+
function isPlatformAdministrator(user) {
|
|
104
|
+
if (!user?.email) return false;
|
|
105
|
+
return !!(user.isRBACAdmin || isSuperAdminGroupName(user.groupName));
|
|
106
|
+
}
|
|
107
|
+
function isVendorPortalUser(user) {
|
|
108
|
+
if (user?.isVendorPortal === true) return true;
|
|
109
|
+
if (!user?.email || isPlatformAdministrator(user)) return false;
|
|
110
|
+
if ((user.vendorIds?.length ?? 0) > 0) return true;
|
|
111
|
+
return isVendorGroupName(user.groupName);
|
|
112
|
+
}
|
|
113
|
+
function isVendorStaff(user) {
|
|
114
|
+
return isVendorPortalUser(user);
|
|
115
|
+
}
|
|
116
|
+
function isVendorOwner(user) {
|
|
117
|
+
if (user?.isVendorOwner === true) return true;
|
|
118
|
+
if (!user?.email || isPlatformAdministrator(user)) return false;
|
|
119
|
+
if (user.vendorRole === "staff") return false;
|
|
120
|
+
if (user.vendorRole === "owner") return true;
|
|
121
|
+
if (!isVendorPortalUser(user)) return false;
|
|
122
|
+
return user.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase();
|
|
123
|
+
}
|
|
124
|
+
function canManageVendorTeam(user) {
|
|
125
|
+
return isPlatformAdministrator(user) || isVendorOwner(user);
|
|
126
|
+
}
|
|
127
|
+
function canManageVendorRoles(user) {
|
|
128
|
+
return isPlatformAdministrator(user) || isVendorOwner(user);
|
|
129
|
+
}
|
|
130
|
+
function canOnboardVendors(user) {
|
|
131
|
+
return isPlatformAdministrator(user);
|
|
132
|
+
}
|
|
133
|
+
function resolveVendorScopeFromSessionUser(user) {
|
|
134
|
+
if (!user?.email) return { type: "deny" };
|
|
135
|
+
if (isPlatformAdministrator(user)) return { type: "all" };
|
|
136
|
+
const vendorIds = user.vendorIds ?? [];
|
|
137
|
+
if (vendorIds.length === 0) return { type: "deny" };
|
|
138
|
+
const preferred = user.activeVendorId ?? vendorIds[0];
|
|
139
|
+
const vendorId = vendorIds.includes(preferred) ? preferred : vendorIds[0];
|
|
140
|
+
return { type: "vendor", vendorId, vendorIds };
|
|
141
|
+
}
|
|
142
|
+
function vendorPortalFlagsFromUser(input) {
|
|
143
|
+
const vendorIds = input.vendorIds ?? [];
|
|
144
|
+
const isVendorPortal = !input.isRBACAdmin && (vendorIds.length > 0 || isVendorGroupName(input.groupName));
|
|
145
|
+
const isVendorOwner2 = isVendorPortal && input.vendorRole !== "staff" && (input.vendorRole === "owner" || input.groupName?.trim().toLowerCase() === VENDOR_OWNER_GROUP_NAME.toLowerCase());
|
|
146
|
+
return { isVendorPortal, isVendorOwner: isVendorOwner2 };
|
|
147
|
+
}
|
|
148
|
+
var VENDOR_SCOPED_STORE_ENTITIES, VENDOR_STORE_RBAC_ENTITIES, VENDOR_OWNER_GROUP_NAME;
|
|
149
|
+
var init_vendor_scope = __esm({
|
|
150
|
+
"src/auth/vendor-scope.ts"() {
|
|
151
|
+
"use strict";
|
|
152
|
+
init_permission_entities();
|
|
153
|
+
VENDOR_SCOPED_STORE_ENTITIES = /* @__PURE__ */ new Set([
|
|
154
|
+
"products",
|
|
155
|
+
"collections",
|
|
156
|
+
"brands",
|
|
157
|
+
"product_categories",
|
|
158
|
+
"orders",
|
|
159
|
+
"payments",
|
|
160
|
+
"taxes",
|
|
161
|
+
"attributes",
|
|
162
|
+
"vendor_customers",
|
|
163
|
+
"discounts"
|
|
164
|
+
]);
|
|
165
|
+
VENDOR_STORE_RBAC_ENTITIES = /* @__PURE__ */ new Set([
|
|
166
|
+
...VENDOR_SCOPED_STORE_ENTITIES,
|
|
167
|
+
"order_discounts",
|
|
168
|
+
"order_addresses"
|
|
169
|
+
]);
|
|
170
|
+
VENDOR_OWNER_GROUP_NAME = "Vendor Owner";
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
// src/auth/rbac-debug-db.ts
|
|
175
|
+
var rbac_debug_db_exports = {};
|
|
176
|
+
__export(rbac_debug_db_exports, {
|
|
177
|
+
loadDbPermissionsForUser: () => loadDbPermissionsForUser
|
|
178
|
+
});
|
|
179
|
+
async function loadDbPermissionsForUser(dataSource, userId) {
|
|
180
|
+
const rows = await dataSource.query(
|
|
181
|
+
`
|
|
182
|
+
SELECT u."groupId" AS "groupId", g.name AS "groupName",
|
|
183
|
+
p.entity, p."canCreate", p."canRead", p."canUpdate", p."canDelete"
|
|
184
|
+
FROM users u
|
|
185
|
+
LEFT JOIN user_groups g ON g.id = u."groupId" AND g.deleted = false
|
|
186
|
+
LEFT JOIN permissions p ON p."groupId" = g.id
|
|
187
|
+
WHERE u.id = $1
|
|
188
|
+
`,
|
|
189
|
+
[userId]
|
|
190
|
+
);
|
|
191
|
+
const groupId = rows[0]?.groupId ?? null;
|
|
192
|
+
const groupName = rows[0]?.groupName ?? null;
|
|
193
|
+
const permRows = rows.filter((r) => r.entity).map((r) => ({
|
|
194
|
+
entity: r.entity,
|
|
195
|
+
canCreate: !!r.canCreate,
|
|
196
|
+
canRead: !!r.canRead,
|
|
197
|
+
canUpdate: !!r.canUpdate,
|
|
198
|
+
canDelete: !!r.canDelete
|
|
199
|
+
}));
|
|
200
|
+
return {
|
|
201
|
+
groupId,
|
|
202
|
+
groupName,
|
|
203
|
+
dbEntityPerms: summarizeEntityPerms(permissionRowsToRecord(permRows))
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
var init_rbac_debug_db = __esm({
|
|
207
|
+
"src/auth/rbac-debug-db.ts"() {
|
|
208
|
+
"use strict";
|
|
209
|
+
init_permission_entities();
|
|
210
|
+
init_rbac_debug();
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// src/auth/rbac-debug.ts
|
|
215
|
+
function isRbacDebugEnabled() {
|
|
216
|
+
const v = process.env.CMS_RBAC_DEBUG?.trim().toLowerCase();
|
|
217
|
+
if (v === "1" || v === "true" || v === "yes") return true;
|
|
218
|
+
if (v === "0" || v === "false" || v === "no") return false;
|
|
219
|
+
return process.env.NODE_ENV === "development";
|
|
220
|
+
}
|
|
221
|
+
function logRbac(message, data) {
|
|
222
|
+
if (!isRbacDebugEnabled()) return;
|
|
223
|
+
if (data) console.info(LOG_PREFIX, message, data);
|
|
224
|
+
else console.info(LOG_PREFIX, message);
|
|
225
|
+
}
|
|
226
|
+
function summarizeEntityPerms(entityPerms) {
|
|
227
|
+
const out = {};
|
|
228
|
+
if (!entityPerms) return out;
|
|
229
|
+
for (const [entity, p] of Object.entries(entityPerms)) {
|
|
230
|
+
out[entity] = { c: p.c, r: p.r, u: p.u, d: p.d };
|
|
231
|
+
}
|
|
232
|
+
return out;
|
|
233
|
+
}
|
|
234
|
+
function vendorPortalFallbackReason(user, entity, action) {
|
|
235
|
+
if (!isVendorPortalUser(user)) return null;
|
|
236
|
+
if (entity === "dashboard" && action === "read") return "vendor_portal_dashboard_fallback";
|
|
237
|
+
if (entity === "analytics" && action === "read") return "vendor_portal_analytics_fallback";
|
|
238
|
+
if (entity === "settings" && action === "read") return "vendor_portal_settings_read_fallback";
|
|
239
|
+
if (VENDOR_STORE_RBAC_ENTITIES.has(entity) && action === "read") return "vendor_portal_store_read_fallback";
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
function explainSessionEntityAccess(user, entity, action) {
|
|
243
|
+
const userSnapshot = {
|
|
244
|
+
email: user?.email ?? null,
|
|
245
|
+
id: user?.id ?? null,
|
|
246
|
+
groupId: user?.groupId ?? null,
|
|
247
|
+
groupName: user?.groupName ?? null,
|
|
248
|
+
isRBACAdmin: user?.isRBACAdmin ?? false,
|
|
249
|
+
adminAccess: user?.adminAccess ?? null,
|
|
250
|
+
vendorIds: user?.vendorIds ?? [],
|
|
251
|
+
activeVendorId: user?.activeVendorId ?? null,
|
|
252
|
+
vendorRole: user?.vendorRole ?? null,
|
|
253
|
+
isVendorPortal: user?.isVendorPortal ?? false,
|
|
254
|
+
isVendorOwner: user?.isVendorOwner ?? false,
|
|
255
|
+
isVendorPortalComputed: isVendorPortalUser(user),
|
|
256
|
+
isVendorOwnerComputed: isVendorOwner(user),
|
|
257
|
+
jwtEntityPerms: summarizeEntityPerms(user?.entityPerms),
|
|
258
|
+
jwtEntityPermForTarget: user?.entityPerms?.[entity] ?? null
|
|
259
|
+
};
|
|
260
|
+
if (!user?.email) {
|
|
261
|
+
return { allowed: false, reason: "no_session_email", userSnapshot };
|
|
262
|
+
}
|
|
263
|
+
if (user.isRBACAdmin) {
|
|
264
|
+
return { allowed: true, reason: "platform_administrator", userSnapshot };
|
|
265
|
+
}
|
|
266
|
+
const vendorIds = user.vendorIds ?? [];
|
|
267
|
+
const isStaff = user.vendorRole === "staff";
|
|
268
|
+
if (vendorIds.length > 0) {
|
|
269
|
+
if (entity === "dashboard" && action === "read") {
|
|
270
|
+
return { allowed: true, reason: "vendor_link_dashboard_read", userSnapshot };
|
|
271
|
+
}
|
|
272
|
+
if (entity === "analytics" && action === "read") {
|
|
273
|
+
return { allowed: true, reason: "vendor_link_analytics_read", userSnapshot };
|
|
274
|
+
}
|
|
275
|
+
if (entity === "settings") {
|
|
276
|
+
if (action === "read") {
|
|
277
|
+
return { allowed: true, reason: "vendor_link_settings_read", userSnapshot };
|
|
278
|
+
}
|
|
279
|
+
if (action === "update" && !isStaff) {
|
|
280
|
+
return { allowed: true, reason: "vendor_link_settings_update", userSnapshot };
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (VENDOR_STORE_RBAC_ENTITIES.has(entity)) {
|
|
284
|
+
if (isStaff && action === "read") {
|
|
285
|
+
return { allowed: true, reason: "vendor_staff_store_read", userSnapshot };
|
|
286
|
+
}
|
|
287
|
+
if (!isStaff) {
|
|
288
|
+
return { allowed: true, reason: "vendor_link_store_full", userSnapshot };
|
|
289
|
+
}
|
|
290
|
+
return {
|
|
291
|
+
allowed: false,
|
|
292
|
+
reason: "vendor_staff_store_write_denied",
|
|
293
|
+
userSnapshot
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (isVendorPortalUser(user) && isVendorOwner(user)) {
|
|
298
|
+
if (entity === "dashboard" && action === "read") {
|
|
299
|
+
return { allowed: true, reason: "vendor_owner_group_dashboard", userSnapshot };
|
|
300
|
+
}
|
|
301
|
+
if (entity === "analytics" && action === "read") {
|
|
302
|
+
return { allowed: true, reason: "vendor_owner_group_analytics", userSnapshot };
|
|
303
|
+
}
|
|
304
|
+
if (entity === "settings" && (action === "read" || action === "update")) {
|
|
305
|
+
return { allowed: true, reason: "vendor_owner_group_settings", userSnapshot };
|
|
306
|
+
}
|
|
307
|
+
if (VENDOR_STORE_RBAC_ENTITIES.has(entity)) {
|
|
308
|
+
return { allowed: true, reason: "vendor_owner_group_store", userSnapshot };
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
const vendorPortalReason = vendorPortalFallbackReason(user, entity, action);
|
|
312
|
+
if (vendorPortalReason) {
|
|
313
|
+
return { allowed: true, reason: vendorPortalReason, userSnapshot };
|
|
314
|
+
}
|
|
315
|
+
const explicit = user.entityPerms?.[entity];
|
|
316
|
+
if (explicit !== void 0) {
|
|
317
|
+
const allowed2 = hasEntityPermission(user.entityPerms, entity, action);
|
|
318
|
+
return {
|
|
319
|
+
allowed: allowed2,
|
|
320
|
+
reason: allowed2 ? "jwt_entity_perms_allow" : "jwt_entity_perms_deny",
|
|
321
|
+
userSnapshot
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
const allowed = hasEntityPermission(user.entityPerms, entity, action);
|
|
325
|
+
return {
|
|
326
|
+
allowed,
|
|
327
|
+
reason: allowed ? "entity_perms_fallback_allow" : "no_matching_rule",
|
|
328
|
+
userSnapshot
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
async function logEntityAccessDecision(dataSource, context, user, entity, action, extra) {
|
|
332
|
+
if (!isRbacDebugEnabled()) return;
|
|
333
|
+
const explanation = explainSessionEntityAccess(user, entity, action);
|
|
334
|
+
let dbPermissions;
|
|
335
|
+
if (dataSource && user?.id) {
|
|
336
|
+
const id = Number(user.id);
|
|
337
|
+
if (Number.isFinite(id)) {
|
|
338
|
+
try {
|
|
339
|
+
const { loadDbPermissionsForUser: loadDbPermissionsForUser2 } = await Promise.resolve().then(() => (init_rbac_debug_db(), rbac_debug_db_exports));
|
|
340
|
+
dbPermissions = await loadDbPermissionsForUser2(dataSource, id);
|
|
341
|
+
} catch (e) {
|
|
342
|
+
dbPermissions = { error: e instanceof Error ? e.message : String(e) };
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
logRbac(context, {
|
|
347
|
+
entity,
|
|
348
|
+
action,
|
|
349
|
+
allowed: explanation.allowed,
|
|
350
|
+
reason: explanation.reason,
|
|
351
|
+
...explanation.userSnapshot,
|
|
352
|
+
dbPermissions,
|
|
353
|
+
...extra
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
var LOG_PREFIX;
|
|
357
|
+
var init_rbac_debug = __esm({
|
|
358
|
+
"src/auth/rbac-debug.ts"() {
|
|
359
|
+
"use strict";
|
|
360
|
+
init_permission_entities();
|
|
361
|
+
init_vendor_scope();
|
|
362
|
+
LOG_PREFIX = "[cms-rbac]";
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// src/auth/index.ts
|
|
367
|
+
var auth_exports = {};
|
|
368
|
+
__export(auth_exports, {
|
|
369
|
+
ADMIN_GROUP_NAME: () => ADMIN_GROUP_NAME,
|
|
370
|
+
OPEN_ENDPOINTS: () => OPEN_ENDPOINTS,
|
|
371
|
+
PERMISSION_REQUIRED_ENDPOINTS: () => PERMISSION_REQUIRED_ENDPOINTS,
|
|
372
|
+
RBAC_ADMIN_ONLY_ENTITIES: () => RBAC_ADMIN_ONLY_ENTITIES,
|
|
373
|
+
VENDOR_OWNER_GROUP_NAME: () => VENDOR_OWNER_GROUP_NAME,
|
|
374
|
+
VENDOR_SCOPED_STORE_ENTITIES: () => VENDOR_SCOPED_STORE_ENTITIES,
|
|
375
|
+
VENDOR_STORE_RBAC_ENTITIES: () => VENDOR_STORE_RBAC_ENTITIES,
|
|
376
|
+
canManageRoles: () => canManageRoles,
|
|
377
|
+
canManageVendorRoles: () => canManageVendorRoles,
|
|
378
|
+
canManageVendorTeam: () => canManageVendorTeam,
|
|
379
|
+
canOnboardVendors: () => canOnboardVendors,
|
|
380
|
+
createAuthHelpers: () => createAuthHelpers,
|
|
381
|
+
createCmsAuthBundle: () => createCmsAuthBundle,
|
|
382
|
+
createCmsMiddleware: () => createCmsMiddleware,
|
|
383
|
+
defaultPublicApiMethods: () => defaultPublicApiMethods,
|
|
384
|
+
explainSessionEntityAccess: () => explainSessionEntityAccess,
|
|
385
|
+
getNextAuthOptions: () => getNextAuthOptions,
|
|
386
|
+
getPermissionableEntityKeys: () => getPermissionableEntityKeys,
|
|
387
|
+
getRequiredPermission: () => getRequiredPermission,
|
|
388
|
+
hasEntityPermission: () => hasEntityPermission,
|
|
389
|
+
isAuthDebugClientEnabled: () => isAuthDebugClientEnabled,
|
|
390
|
+
isAuthDebugEnabled: () => isAuthDebugEnabled,
|
|
391
|
+
isOpenEndpoint: () => isOpenEndpoint,
|
|
392
|
+
isPlatformAdministrator: () => isPlatformAdministrator,
|
|
393
|
+
isPublicMethod: () => isPublicMethod,
|
|
394
|
+
isRbacDebugEnabled: () => isRbacDebugEnabled,
|
|
395
|
+
isSuperAdminGroupName: () => isSuperAdminGroupName,
|
|
396
|
+
isVendorGroupName: () => isVendorGroupName,
|
|
397
|
+
isVendorOwner: () => isVendorOwner,
|
|
398
|
+
isVendorPortalUser: () => isVendorPortalUser,
|
|
399
|
+
isVendorStaff: () => isVendorStaff,
|
|
400
|
+
logAuth: () => logAuth,
|
|
401
|
+
logAuthClient: () => logAuthClient,
|
|
402
|
+
logEntityAccessDecision: () => logEntityAccessDecision,
|
|
403
|
+
logRbac: () => logRbac,
|
|
404
|
+
nextAuthCookieDebugInfo: () => nextAuthCookieDebugInfo,
|
|
405
|
+
permissionRowsToRecord: () => permissionRowsToRecord,
|
|
406
|
+
resolveVendorScopeFromSessionUser: () => resolveVendorScopeFromSessionUser,
|
|
407
|
+
seedAdministratorPermissions: () => seedAdministratorPermissions,
|
|
408
|
+
sessionHasEntityAccess: () => sessionHasEntityAccess,
|
|
409
|
+
summarizeEntityPerms: () => summarizeEntityPerms,
|
|
410
|
+
summarizeSessionUserForLog: () => summarizeSessionUserForLog,
|
|
411
|
+
vendorPortalFlagsFromUser: () => vendorPortalFlagsFromUser
|
|
412
|
+
});
|
|
413
|
+
module.exports = __toCommonJS(auth_exports);
|
|
110
414
|
|
|
111
415
|
// src/auth/helpers.ts
|
|
416
|
+
init_rbac_debug();
|
|
417
|
+
init_vendor_scope();
|
|
112
418
|
var RBAC_ADMIN_ONLY_ENTITIES = /* @__PURE__ */ new Set(["users", "user_groups", "permissions"]);
|
|
113
419
|
function sessionHasEntityAccess(user, entity, action) {
|
|
114
|
-
|
|
115
|
-
if (user.isRBACAdmin && RBAC_ADMIN_ONLY_ENTITIES.has(entity)) return true;
|
|
116
|
-
return hasEntityPermission(user.entityPerms, entity, action);
|
|
420
|
+
return explainSessionEntityAccess(user, entity, action).allowed;
|
|
117
421
|
}
|
|
118
422
|
function canManageRoles(user) {
|
|
119
423
|
return !!(user?.email && user.isRBACAdmin);
|
|
@@ -138,6 +442,19 @@ function isPublicMethod(pathname, method) {
|
|
|
138
442
|
return false;
|
|
139
443
|
}
|
|
140
444
|
function createAuthHelpers(getSession, NextResponse) {
|
|
445
|
+
return createAuthHelpersFromGetSession(getSession, NextResponse);
|
|
446
|
+
}
|
|
447
|
+
function createCmsAuthBundle(getSession, NextResponse) {
|
|
448
|
+
const auth = createAuthHelpers(getSession, NextResponse);
|
|
449
|
+
return {
|
|
450
|
+
requireAuth: auth.requireAuth,
|
|
451
|
+
requireAdminAccess: auth.requireAdminAccess,
|
|
452
|
+
requireEntityPermission: auth.requireEntityPermission,
|
|
453
|
+
getSessionUser: auth.getAuthenticatedUser,
|
|
454
|
+
getAuthenticatedUser: auth.getAuthenticatedUser
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
function createAuthHelpersFromGetSession(getSession, NextResponse) {
|
|
141
458
|
return {
|
|
142
459
|
async requireAuth() {
|
|
143
460
|
const session = await getSession();
|
|
@@ -159,8 +476,21 @@ function createAuthHelpers(getSession, NextResponse) {
|
|
|
159
476
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
|
160
477
|
}
|
|
161
478
|
const u = session.user;
|
|
162
|
-
|
|
163
|
-
|
|
479
|
+
const allowed = sessionHasEntityAccess(u, entity, action);
|
|
480
|
+
const { reason } = explainSessionEntityAccess(u, entity, action);
|
|
481
|
+
logRbac("authHelpers.requireEntityPermission", {
|
|
482
|
+
entity,
|
|
483
|
+
action,
|
|
484
|
+
allowed,
|
|
485
|
+
reason,
|
|
486
|
+
email: u.email,
|
|
487
|
+
groupName: u.groupName,
|
|
488
|
+
vendorIds: u.vendorIds,
|
|
489
|
+
isVendorPortal: u.isVendorPortal,
|
|
490
|
+
isVendorOwner: u.isVendorOwner
|
|
491
|
+
});
|
|
492
|
+
if (allowed) return null;
|
|
493
|
+
return NextResponse.json({ error: "Forbidden", entity, action, reason }, { status: 403 });
|
|
164
494
|
},
|
|
165
495
|
async requireAdminAccess() {
|
|
166
496
|
const session = await getSession();
|
|
@@ -169,8 +499,23 @@ function createAuthHelpers(getSession, NextResponse) {
|
|
|
169
499
|
}
|
|
170
500
|
const u = session.user;
|
|
171
501
|
if (u.isRBACAdmin) return null;
|
|
172
|
-
if (u
|
|
173
|
-
return null;
|
|
502
|
+
if (isVendorPortalUser(u)) return null;
|
|
503
|
+
if (u.adminAccess === true) return null;
|
|
504
|
+
if (u.adminAccess === false) {
|
|
505
|
+
logRbac("requireAdminAccess denied (adminAccess:false)", {
|
|
506
|
+
email: u.email,
|
|
507
|
+
groupName: u.groupName,
|
|
508
|
+
isVendorPortal: u.isVendorPortal
|
|
509
|
+
});
|
|
510
|
+
return NextResponse.json({ error: "Forbidden", reason: "admin_access" }, { status: 403 });
|
|
511
|
+
}
|
|
512
|
+
logRbac("requireAdminAccess denied (no matching rule)", {
|
|
513
|
+
email: u.email,
|
|
514
|
+
adminAccess: u.adminAccess,
|
|
515
|
+
groupName: u.groupName,
|
|
516
|
+
isVendorPortal: u.isVendorPortal
|
|
517
|
+
});
|
|
518
|
+
return NextResponse.json({ error: "Forbidden", reason: "admin_access" }, { status: 403 });
|
|
174
519
|
},
|
|
175
520
|
async getAuthenticatedUser() {
|
|
176
521
|
const session = await getSession();
|
|
@@ -179,18 +524,26 @@ function createAuthHelpers(getSession, NextResponse) {
|
|
|
179
524
|
};
|
|
180
525
|
}
|
|
181
526
|
|
|
527
|
+
// src/auth/index.ts
|
|
528
|
+
init_rbac_debug();
|
|
529
|
+
init_vendor_scope();
|
|
530
|
+
init_permission_entities();
|
|
531
|
+
|
|
182
532
|
// src/auth/seed-permissions.ts
|
|
533
|
+
init_permission_entities();
|
|
183
534
|
async function seedAdministratorPermissions(dataSource, entityMap) {
|
|
184
535
|
const entities = getPermissionableEntityKeys(entityMap);
|
|
185
536
|
const groupRepo = dataSource.getRepository(entityMap.user_groups);
|
|
186
537
|
const permRepo = dataSource.getRepository(entityMap.permissions);
|
|
187
538
|
const adminGroup = await groupRepo.findOne({ where: { name: ADMIN_GROUP_NAME, deleted: false } });
|
|
539
|
+
console.log("ADMIN GROUP", adminGroup);
|
|
188
540
|
if (!adminGroup) return;
|
|
189
541
|
const fullCrud = { canCreate: true, canRead: true, canUpdate: true, canDelete: true };
|
|
190
542
|
for (const entity of entities) {
|
|
191
543
|
const existing = await permRepo.findOne({
|
|
192
544
|
where: { groupId: adminGroup.id, entity }
|
|
193
545
|
});
|
|
546
|
+
console.log("EXISTING", existing);
|
|
194
547
|
if (existing) {
|
|
195
548
|
existing.canCreate = true;
|
|
196
549
|
existing.canRead = true;
|
|
@@ -209,6 +562,59 @@ async function seedAdministratorPermissions(dataSource, entityMap) {
|
|
|
209
562
|
}
|
|
210
563
|
}
|
|
211
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
|
+
|
|
212
618
|
// src/auth/middleware.ts
|
|
213
619
|
var defaultPublicApiMethods = {
|
|
214
620
|
"/api/contacts": ["POST"],
|
|
@@ -221,8 +627,21 @@ var defaultPublicApiMethods = {
|
|
|
221
627
|
"/api/users/set-password": ["POST"],
|
|
222
628
|
"/api/users/invite": ["POST"]
|
|
223
629
|
};
|
|
224
|
-
function
|
|
225
|
-
|
|
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
|
+
};
|
|
226
645
|
}
|
|
227
646
|
function isPublicMethod2(pathname, method, publicApiMethods) {
|
|
228
647
|
for (const [endpoint, methods] of Object.entries(publicApiMethods)) {
|
|
@@ -230,31 +649,59 @@ function isPublicMethod2(pathname, method, publicApiMethods) {
|
|
|
230
649
|
}
|
|
231
650
|
return false;
|
|
232
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
|
+
}
|
|
233
659
|
function createCmsMiddleware(config = {}) {
|
|
234
660
|
const {
|
|
235
661
|
publicAdminPaths = ["/admin/signin", "/admin/forgot-password", "/admin/reset-password", "/admin/invite"],
|
|
236
662
|
publicApiMethods = defaultPublicApiMethods,
|
|
237
663
|
signInPath = "/admin/signin",
|
|
238
|
-
getSessionToken =
|
|
664
|
+
getSessionToken = legacyGetSessionToken,
|
|
665
|
+
secret = process.env.NEXTAUTH_SECRET
|
|
239
666
|
} = config;
|
|
240
|
-
return function cmsMiddleware(request) {
|
|
667
|
+
return async function cmsMiddleware(request) {
|
|
241
668
|
const pathname = request.nextUrl.pathname;
|
|
242
669
|
const method = request.method;
|
|
243
670
|
if (publicAdminPaths.some((p) => pathname === p || pathname.startsWith(p + "/"))) {
|
|
244
671
|
return { type: "next" };
|
|
245
672
|
}
|
|
246
673
|
if (pathname.startsWith("/admin")) {
|
|
247
|
-
const
|
|
248
|
-
|
|
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
|
+
});
|
|
249
684
|
return { type: "redirect", url: new URL(signInPath, request.url).toString() };
|
|
250
685
|
}
|
|
686
|
+
logAuth("middleware: admin allowed", {
|
|
687
|
+
pathname,
|
|
688
|
+
method,
|
|
689
|
+
usesGetToken: Boolean(request.req),
|
|
690
|
+
...cookies
|
|
691
|
+
});
|
|
251
692
|
}
|
|
252
693
|
if (pathname.startsWith("/api")) {
|
|
253
694
|
if (isPublicMethod2(pathname, method, publicApiMethods)) {
|
|
254
695
|
return { type: "next" };
|
|
255
696
|
}
|
|
256
|
-
const
|
|
257
|
-
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
|
+
});
|
|
258
705
|
return { type: "json", status: 401, body: { error: "Unauthorized" } };
|
|
259
706
|
}
|
|
260
707
|
}
|
|
@@ -264,20 +711,38 @@ function createCmsMiddleware(config = {}) {
|
|
|
264
711
|
|
|
265
712
|
// src/auth/nextauth-options.ts
|
|
266
713
|
var import_credentials = __toESM(require("next-auth/providers/credentials"), 1);
|
|
714
|
+
init_permission_entities();
|
|
715
|
+
init_vendor_scope();
|
|
267
716
|
var CredentialsProvider = import_credentials.default.default ?? import_credentials.default;
|
|
268
717
|
function sessionUserFromNextAuthUser(user) {
|
|
269
718
|
const g = user.group;
|
|
270
719
|
const isRBACAdmin = isSuperAdminGroupName(g?.name);
|
|
271
720
|
const entityPerms = permissionRowsToRecord(g?.permissions);
|
|
272
|
-
const
|
|
721
|
+
const rawAdminAccess = user.adminAccess;
|
|
722
|
+
const adminAccess = rawAdminAccess === true ? true : rawAdminAccess === false ? false : void 0;
|
|
723
|
+
const vendorIds = user.vendorIds ?? [];
|
|
724
|
+
const vendorRole = user.vendorRole ?? null;
|
|
725
|
+
const { isVendorPortal, isVendorOwner: isVendorOwner2 } = vendorPortalFlagsFromUser({
|
|
726
|
+
email: user.email,
|
|
727
|
+
isRBACAdmin,
|
|
728
|
+
groupName: g?.name,
|
|
729
|
+
vendorIds,
|
|
730
|
+
vendorRole
|
|
731
|
+
});
|
|
273
732
|
return {
|
|
274
733
|
id: user.id.toString(),
|
|
275
734
|
email: user.email,
|
|
276
735
|
name: user.name,
|
|
277
736
|
groupId: user.groupId ?? void 0,
|
|
737
|
+
groupName: g?.name ?? void 0,
|
|
278
738
|
isRBACAdmin,
|
|
279
739
|
entityPerms,
|
|
280
|
-
adminAccess
|
|
740
|
+
adminAccess,
|
|
741
|
+
vendorIds,
|
|
742
|
+
activeVendorId: user.activeVendorId ?? vendorIds[0] ?? null,
|
|
743
|
+
vendorRole,
|
|
744
|
+
isVendorPortal,
|
|
745
|
+
isVendorOwner: isVendorOwner2
|
|
281
746
|
};
|
|
282
747
|
}
|
|
283
748
|
function getNextAuthOptions(config) {
|
|
@@ -291,6 +756,7 @@ function getNextAuthOptions(config) {
|
|
|
291
756
|
enableOtpLogin = false,
|
|
292
757
|
authorizeOtp
|
|
293
758
|
} = config;
|
|
759
|
+
logAuth("getNextAuthOptions init", nextAuthCookieDebugInfo());
|
|
294
760
|
const providers = [];
|
|
295
761
|
if (enablePasswordLogin) {
|
|
296
762
|
providers.push(
|
|
@@ -301,14 +767,43 @@ function getNextAuthOptions(config) {
|
|
|
301
767
|
password: { label: "Password", type: "password" }
|
|
302
768
|
},
|
|
303
769
|
async authorize(credentials) {
|
|
304
|
-
|
|
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
|
+
}
|
|
305
775
|
try {
|
|
306
|
-
const user = await getUserByEmail(
|
|
307
|
-
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
|
+
}
|
|
308
793
|
const valid = await comparePassword(credentials.password, user.password);
|
|
309
|
-
if (!valid)
|
|
310
|
-
|
|
311
|
-
|
|
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;
|
|
801
|
+
} catch (err) {
|
|
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
|
+
});
|
|
312
807
|
return null;
|
|
313
808
|
}
|
|
314
809
|
}
|
|
@@ -334,7 +829,8 @@ function getNextAuthOptions(config) {
|
|
|
334
829
|
const user = await authorizeOtp({ identifier, channel: ch, code });
|
|
335
830
|
if (!user || user.blocked || user.deleted) return null;
|
|
336
831
|
return sessionUserFromNextAuthUser(user);
|
|
337
|
-
} catch {
|
|
832
|
+
} catch (err) {
|
|
833
|
+
console.error("[cms-auth] authorize error (otp):", err instanceof Error ? err.message : err);
|
|
338
834
|
return null;
|
|
339
835
|
}
|
|
340
836
|
}
|
|
@@ -360,31 +856,54 @@ function getNextAuthOptions(config) {
|
|
|
360
856
|
callbacks: {
|
|
361
857
|
async jwt({ token, user, trigger, session }) {
|
|
362
858
|
if (user) {
|
|
859
|
+
logAuth("jwt callback: new sign-in", {
|
|
860
|
+
trigger,
|
|
861
|
+
user: summarizeSessionUserForLog(user)
|
|
862
|
+
});
|
|
363
863
|
const u = user;
|
|
364
864
|
token.id = u.id;
|
|
365
865
|
token.groupId = u.groupId;
|
|
866
|
+
token.groupName = u.groupName;
|
|
366
867
|
token.isRBACAdmin = u.isRBACAdmin;
|
|
367
868
|
token.entityPerms = u.entityPerms;
|
|
368
869
|
token.adminAccess = u.adminAccess;
|
|
870
|
+
token.vendorIds = u.vendorIds;
|
|
871
|
+
token.activeVendorId = u.activeVendorId;
|
|
872
|
+
token.vendorRole = u.vendorRole;
|
|
873
|
+
token.isVendorPortal = u.isVendorPortal;
|
|
874
|
+
token.isVendorOwner = u.isVendorOwner;
|
|
369
875
|
}
|
|
370
876
|
if (trigger === "update" && session && typeof session === "object") {
|
|
877
|
+
logAuth("jwt callback: session update", { trigger });
|
|
371
878
|
const s = session;
|
|
372
879
|
const t = token;
|
|
373
880
|
if (typeof s.name === "string") t.name = s.name;
|
|
374
881
|
if (typeof s.email === "string") t.email = s.email;
|
|
882
|
+
if (typeof s.activeVendorId === "number") t.activeVendorId = s.activeVendorId;
|
|
375
883
|
}
|
|
376
884
|
return token;
|
|
377
885
|
},
|
|
378
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
|
+
});
|
|
379
893
|
if (session.user) {
|
|
380
|
-
const t = token;
|
|
381
894
|
if (typeof t.name === "string") session.user.name = t.name;
|
|
382
895
|
if (typeof t.email === "string") session.user.email = t.email;
|
|
383
896
|
session.user.id = t.id;
|
|
384
897
|
session.user.groupId = t.groupId;
|
|
898
|
+
session.user.groupName = t.groupName;
|
|
385
899
|
session.user.isRBACAdmin = t.isRBACAdmin;
|
|
386
900
|
session.user.entityPerms = t.entityPerms;
|
|
387
901
|
session.user.adminAccess = t.adminAccess;
|
|
902
|
+
session.user.vendorIds = t.vendorIds;
|
|
903
|
+
session.user.activeVendorId = t.activeVendorId;
|
|
904
|
+
session.user.vendorRole = t.vendorRole;
|
|
905
|
+
session.user.isVendorPortal = t.isVendorPortal;
|
|
906
|
+
session.user.isVendorOwner = t.isVendorOwner;
|
|
388
907
|
}
|
|
389
908
|
return session;
|
|
390
909
|
}
|
|
@@ -398,19 +917,44 @@ function getNextAuthOptions(config) {
|
|
|
398
917
|
OPEN_ENDPOINTS,
|
|
399
918
|
PERMISSION_REQUIRED_ENDPOINTS,
|
|
400
919
|
RBAC_ADMIN_ONLY_ENTITIES,
|
|
920
|
+
VENDOR_OWNER_GROUP_NAME,
|
|
921
|
+
VENDOR_SCOPED_STORE_ENTITIES,
|
|
922
|
+
VENDOR_STORE_RBAC_ENTITIES,
|
|
401
923
|
canManageRoles,
|
|
924
|
+
canManageVendorRoles,
|
|
925
|
+
canManageVendorTeam,
|
|
926
|
+
canOnboardVendors,
|
|
402
927
|
createAuthHelpers,
|
|
928
|
+
createCmsAuthBundle,
|
|
403
929
|
createCmsMiddleware,
|
|
404
930
|
defaultPublicApiMethods,
|
|
931
|
+
explainSessionEntityAccess,
|
|
405
932
|
getNextAuthOptions,
|
|
406
933
|
getPermissionableEntityKeys,
|
|
407
934
|
getRequiredPermission,
|
|
408
935
|
hasEntityPermission,
|
|
936
|
+
isAuthDebugClientEnabled,
|
|
937
|
+
isAuthDebugEnabled,
|
|
409
938
|
isOpenEndpoint,
|
|
939
|
+
isPlatformAdministrator,
|
|
410
940
|
isPublicMethod,
|
|
941
|
+
isRbacDebugEnabled,
|
|
411
942
|
isSuperAdminGroupName,
|
|
943
|
+
isVendorGroupName,
|
|
944
|
+
isVendorOwner,
|
|
945
|
+
isVendorPortalUser,
|
|
946
|
+
isVendorStaff,
|
|
947
|
+
logAuth,
|
|
948
|
+
logAuthClient,
|
|
949
|
+
logEntityAccessDecision,
|
|
950
|
+
logRbac,
|
|
951
|
+
nextAuthCookieDebugInfo,
|
|
412
952
|
permissionRowsToRecord,
|
|
953
|
+
resolveVendorScopeFromSessionUser,
|
|
413
954
|
seedAdministratorPermissions,
|
|
414
|
-
sessionHasEntityAccess
|
|
955
|
+
sessionHasEntityAccess,
|
|
956
|
+
summarizeEntityPerms,
|
|
957
|
+
summarizeSessionUserForLog,
|
|
958
|
+
vendorPortalFlagsFromUser
|
|
415
959
|
});
|
|
416
960
|
//# sourceMappingURL=auth.cjs.map
|