@strapi-community/plugin-better-auth-dashboard 1.0.0-alpha.8 → 1.0.0-beta.1

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.
@@ -1,6 +1,55 @@
1
1
  "use strict";
2
2
  Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
3
3
  const utils = require("@strapi/utils");
4
+ const config = {
5
+ default: {},
6
+ validator(config2) {
7
+ if (config2.email_callback_url === void 0) return;
8
+ if (typeof config2.email_callback_url !== "string" || config2.email_callback_url.length === 0) {
9
+ throw new Error("email_callback_url must be a non-empty string");
10
+ }
11
+ try {
12
+ new URL(config2.email_callback_url);
13
+ } catch {
14
+ throw new Error("email_callback_url must be a valid absolute URL");
15
+ }
16
+ }
17
+ };
18
+ const strapi$1 = { "name": "better-auth-dashboard" };
19
+ const packageJson = {
20
+ strapi: strapi$1
21
+ };
22
+ const PLUGIN_ID = packageJson.strapi.name;
23
+ const bootstrap = async ({ strapi: strapi2 }) => {
24
+ const provider = strapi2.admin.services.permission.actionProvider;
25
+ const candidates = [
26
+ { resource: "user", uid: "plugin::better-auth.user" },
27
+ { resource: "organization", uid: "plugin::better-auth.organization" }
28
+ ];
29
+ const subjects = candidates.filter(({ uid }) => uid in strapi2.contentTypes);
30
+ for (const { resource, uid } of subjects) {
31
+ for (const action of ["create", "read", "update", "delete"]) {
32
+ const explorerActionId = `plugin::content-manager.explorer.${action}`;
33
+ const dashboardAction = provider.get(
34
+ `plugin::${PLUGIN_ID}.${resource}.${action}`
35
+ );
36
+ if (!dashboardAction) continue;
37
+ if (!dashboardAction.aliases) dashboardAction.aliases = [];
38
+ const alreadyAliased = dashboardAction.aliases.some(
39
+ ({
40
+ actionId,
41
+ subjects: aliasSubjects
42
+ }) => actionId === explorerActionId && aliasSubjects?.includes(uid)
43
+ );
44
+ if (!alreadyAliased) {
45
+ dashboardAction.aliases.push({
46
+ actionId: explorerActionId,
47
+ subjects: [uid]
48
+ });
49
+ }
50
+ }
51
+ }
52
+ };
4
53
  const DASHBOARD_API_KEY = process.env.BETTER_AUTH_DASHBOARD_SECRET || "strapi-internal-dashboard-key";
5
54
  const DASH_CONTEXT_HEADER = "x-dash-context";
6
55
  async function hashApiKey(value) {
@@ -151,9 +200,157 @@ const dbController = () => ({
151
200
  ctx.body = result;
152
201
  }
153
202
  });
203
+ const settingsController = () => ({
204
+ async get(ctx) {
205
+ ctx.body = strapi.config.get(`plugin::${PLUGIN_ID}`, {});
206
+ }
207
+ });
154
208
  const controllers = {
155
209
  "auth-controller": proxyController,
156
- "db-controller": dbController
210
+ "db-controller": dbController,
211
+ "settings-controller": settingsController
212
+ };
213
+ const { PolicyError } = utils.errors;
214
+ const endpointsCategories = Object.freeze({
215
+ "/auth/dash/config": ["overview", "user", "organization"],
216
+ "/auth/dash/user-stats": ["overview"],
217
+ "/auth/dash/user-graph-data": ["overview"],
218
+ "/auth/dash/user-retention-data": ["overview"],
219
+ "/auth/dash/list-users": ["overview", "user"],
220
+ "/auth/dash/list-organization": ["overview", "organization"],
221
+ "/auth/dash/user": ["user"],
222
+ "/auth/dash/organization": ["organization"]
223
+ });
224
+ const types = Object.freeze({
225
+ POST: "read",
226
+ PUT: "update",
227
+ GET: "read",
228
+ DELETE: "delete"
229
+ });
230
+ const endpointsTypes = Object.freeze({
231
+ "/auth/dash/user-stats": "read",
232
+ "/auth/dash/user-graph-data": "read",
233
+ "/auth/dash/user-retention-data": "read",
234
+ "/auth/dash/list-users": "read",
235
+ "/auth/dash/list-organizations": "read",
236
+ "/auth/dash/organization/options": "read",
237
+ "/auth/dash/create-user": "create",
238
+ "/auth/dash/update-user": "update",
239
+ "/auth/dash/user": "read",
240
+ "/auth/dash/delete-user": "delete",
241
+ "/auth/dash/organization/create": "create",
242
+ "/auth/dash/organization/delete": "delete"
243
+ });
244
+ const hasPermission = async (ctx, _, { strapi: strapi2 }) => {
245
+ const { user, route } = ctx.state;
246
+ if (!user) return false;
247
+ const inherentType = types[route.method];
248
+ const determinedType = endpointsTypes?.[Object.keys(endpointsTypes)?.find(
249
+ (k) => ctx.originalUrl?.includes(k)
250
+ )];
251
+ const found = [];
252
+ for await (const role of user.roles) {
253
+ const categories = endpointsCategories[Object.keys(endpointsCategories).find(
254
+ (key) => ctx.originalUrl.startsWith(key)
255
+ )];
256
+ const permissions = await strapi2.documents("admin::permission").findMany({
257
+ filters: {
258
+ $or: (categories || []).map((cat) => ({
259
+ role: { id: role.id },
260
+ action: {
261
+ $startsWith: "plugin::better-auth-dashboard",
262
+ $containsi: cat,
263
+ $endsWith: determinedType || inherentType
264
+ }
265
+ }))
266
+ }
267
+ });
268
+ if (permissions?.length > 0) found.push(...permissions);
269
+ }
270
+ if (found.length <= 0) {
271
+ throw new PolicyError("You do not have permission to see this content.");
272
+ }
273
+ return true;
274
+ };
275
+ const policies = { "has-permission": hasPermission };
276
+ const ACTIONS = {
277
+ overview: [
278
+ {
279
+ section: "plugins",
280
+ subCategory: "overview",
281
+ displayName: "Read",
282
+ pluginName: PLUGIN_ID,
283
+ uid: "overview.read"
284
+ }
285
+ ],
286
+ user: [
287
+ {
288
+ section: "plugins",
289
+ subCategory: "user",
290
+ displayName: "Create",
291
+ pluginName: PLUGIN_ID,
292
+ uid: "user.create"
293
+ },
294
+ {
295
+ section: "plugins",
296
+ subCategory: "user",
297
+ displayName: "Read",
298
+ pluginName: PLUGIN_ID,
299
+ uid: "user.read"
300
+ },
301
+ {
302
+ section: "plugins",
303
+ subCategory: "user",
304
+ displayName: "Update",
305
+ pluginName: PLUGIN_ID,
306
+ uid: "user.update"
307
+ },
308
+ {
309
+ section: "plugins",
310
+ subCategory: "user",
311
+ displayName: "Delete",
312
+ pluginName: PLUGIN_ID,
313
+ uid: "user.delete"
314
+ }
315
+ ],
316
+ organization: [
317
+ {
318
+ section: "plugins",
319
+ subCategory: "organization",
320
+ displayName: "Create",
321
+ pluginName: PLUGIN_ID,
322
+ uid: "organization.create"
323
+ },
324
+ {
325
+ section: "plugins",
326
+ subCategory: "organization",
327
+ displayName: "Read",
328
+ pluginName: PLUGIN_ID,
329
+ uid: "organization.read"
330
+ },
331
+ {
332
+ section: "plugins",
333
+ subCategory: "organization",
334
+ displayName: "Update",
335
+ pluginName: PLUGIN_ID,
336
+ uid: "organization.update"
337
+ },
338
+ {
339
+ section: "plugins",
340
+ subCategory: "organization",
341
+ displayName: "Delete",
342
+ pluginName: PLUGIN_ID,
343
+ uid: "organization.delete"
344
+ }
345
+ ]
346
+ };
347
+ const register = ({ strapi: strapi2 }) => {
348
+ const actionsToRegister = [...ACTIONS.overview, ...ACTIONS.user];
349
+ if (strapi2.plugin("better-auth").contentTypes?.organization)
350
+ actionsToRegister.push(...ACTIONS.organization);
351
+ strapi2.admin.services.permission.actionProvider.registerMany(
352
+ actionsToRegister
353
+ );
157
354
  };
158
355
  const adminRoutes = () => ({
159
356
  type: "admin",
@@ -163,9 +360,8 @@ const adminRoutes = () => ({
163
360
  path: "/auth/:path*",
164
361
  handler: "auth-controller.handleAuthRequest",
165
362
  config: {
166
- policies: [],
167
- prefix: "",
168
- auth: false
363
+ policies: ["has-permission"],
364
+ prefix: ""
169
365
  }
170
366
  },
171
367
  {
@@ -173,8 +369,7 @@ const adminRoutes = () => ({
173
369
  path: "/auth/:path*",
174
370
  handler: "auth-controller.handleAuthRequest",
175
371
  config: {
176
- policies: [],
177
- auth: false,
372
+ policies: ["has-permission"],
178
373
  prefix: ""
179
374
  }
180
375
  },
@@ -183,8 +378,7 @@ const adminRoutes = () => ({
183
378
  path: "/auth/:path*",
184
379
  handler: "auth-controller.handleAuthRequest",
185
380
  config: {
186
- policies: [],
187
- auth: false,
381
+ policies: ["has-permission"],
188
382
  prefix: ""
189
383
  }
190
384
  },
@@ -193,8 +387,7 @@ const adminRoutes = () => ({
193
387
  path: "/auth/:path*",
194
388
  handler: "auth-controller.handleAuthRequest",
195
389
  config: {
196
- policies: [],
197
- auth: false,
390
+ policies: ["has-permission"],
198
391
  prefix: ""
199
392
  }
200
393
  },
@@ -203,8 +396,7 @@ const adminRoutes = () => ({
203
396
  path: "/auth/:path*",
204
397
  handler: "auth-controller.handleAuthRequest",
205
398
  config: {
206
- policies: [],
207
- auth: false,
399
+ policies: ["has-permission"],
208
400
  prefix: ""
209
401
  }
210
402
  },
@@ -213,7 +405,7 @@ const adminRoutes = () => ({
213
405
  path: "/better-auth-dashboard/db",
214
406
  handler: "db-controller.list",
215
407
  config: {
216
- policies: [],
408
+ policies: ["has-permission"],
217
409
  prefix: ""
218
410
  }
219
411
  },
@@ -222,7 +414,16 @@ const adminRoutes = () => ({
222
414
  path: "/better-auth-dashboard/db/:documentId",
223
415
  handler: "db-controller.update",
224
416
  config: {
225
- policies: [],
417
+ policies: ["has-permission"],
418
+ prefix: ""
419
+ }
420
+ },
421
+ {
422
+ method: "GET",
423
+ path: "/better-auth-dashboard/settings",
424
+ handler: "settings-controller.get",
425
+ config: {
426
+ policies: ["has-permission"],
226
427
  prefix: ""
227
428
  }
228
429
  }
@@ -230,7 +431,11 @@ const adminRoutes = () => ({
230
431
  });
231
432
  const routes = { admin: adminRoutes };
232
433
  const index = {
434
+ config,
233
435
  controllers,
234
- routes
436
+ routes,
437
+ policies,
438
+ register,
439
+ bootstrap
235
440
  };
236
441
  exports.default = index;
@@ -1,4 +1,53 @@
1
1
  import { errors } from "@strapi/utils";
2
+ const config = {
3
+ default: {},
4
+ validator(config2) {
5
+ if (config2.email_callback_url === void 0) return;
6
+ if (typeof config2.email_callback_url !== "string" || config2.email_callback_url.length === 0) {
7
+ throw new Error("email_callback_url must be a non-empty string");
8
+ }
9
+ try {
10
+ new URL(config2.email_callback_url);
11
+ } catch {
12
+ throw new Error("email_callback_url must be a valid absolute URL");
13
+ }
14
+ }
15
+ };
16
+ const strapi$1 = { "name": "better-auth-dashboard" };
17
+ const packageJson = {
18
+ strapi: strapi$1
19
+ };
20
+ const PLUGIN_ID = packageJson.strapi.name;
21
+ const bootstrap = async ({ strapi: strapi2 }) => {
22
+ const provider = strapi2.admin.services.permission.actionProvider;
23
+ const candidates = [
24
+ { resource: "user", uid: "plugin::better-auth.user" },
25
+ { resource: "organization", uid: "plugin::better-auth.organization" }
26
+ ];
27
+ const subjects = candidates.filter(({ uid }) => uid in strapi2.contentTypes);
28
+ for (const { resource, uid } of subjects) {
29
+ for (const action of ["create", "read", "update", "delete"]) {
30
+ const explorerActionId = `plugin::content-manager.explorer.${action}`;
31
+ const dashboardAction = provider.get(
32
+ `plugin::${PLUGIN_ID}.${resource}.${action}`
33
+ );
34
+ if (!dashboardAction) continue;
35
+ if (!dashboardAction.aliases) dashboardAction.aliases = [];
36
+ const alreadyAliased = dashboardAction.aliases.some(
37
+ ({
38
+ actionId,
39
+ subjects: aliasSubjects
40
+ }) => actionId === explorerActionId && aliasSubjects?.includes(uid)
41
+ );
42
+ if (!alreadyAliased) {
43
+ dashboardAction.aliases.push({
44
+ actionId: explorerActionId,
45
+ subjects: [uid]
46
+ });
47
+ }
48
+ }
49
+ }
50
+ };
2
51
  const DASHBOARD_API_KEY = process.env.BETTER_AUTH_DASHBOARD_SECRET || "strapi-internal-dashboard-key";
3
52
  const DASH_CONTEXT_HEADER = "x-dash-context";
4
53
  async function hashApiKey(value) {
@@ -149,9 +198,157 @@ const dbController = () => ({
149
198
  ctx.body = result;
150
199
  }
151
200
  });
201
+ const settingsController = () => ({
202
+ async get(ctx) {
203
+ ctx.body = strapi.config.get(`plugin::${PLUGIN_ID}`, {});
204
+ }
205
+ });
152
206
  const controllers = {
153
207
  "auth-controller": proxyController,
154
- "db-controller": dbController
208
+ "db-controller": dbController,
209
+ "settings-controller": settingsController
210
+ };
211
+ const { PolicyError } = errors;
212
+ const endpointsCategories = Object.freeze({
213
+ "/auth/dash/config": ["overview", "user", "organization"],
214
+ "/auth/dash/user-stats": ["overview"],
215
+ "/auth/dash/user-graph-data": ["overview"],
216
+ "/auth/dash/user-retention-data": ["overview"],
217
+ "/auth/dash/list-users": ["overview", "user"],
218
+ "/auth/dash/list-organization": ["overview", "organization"],
219
+ "/auth/dash/user": ["user"],
220
+ "/auth/dash/organization": ["organization"]
221
+ });
222
+ const types = Object.freeze({
223
+ POST: "read",
224
+ PUT: "update",
225
+ GET: "read",
226
+ DELETE: "delete"
227
+ });
228
+ const endpointsTypes = Object.freeze({
229
+ "/auth/dash/user-stats": "read",
230
+ "/auth/dash/user-graph-data": "read",
231
+ "/auth/dash/user-retention-data": "read",
232
+ "/auth/dash/list-users": "read",
233
+ "/auth/dash/list-organizations": "read",
234
+ "/auth/dash/organization/options": "read",
235
+ "/auth/dash/create-user": "create",
236
+ "/auth/dash/update-user": "update",
237
+ "/auth/dash/user": "read",
238
+ "/auth/dash/delete-user": "delete",
239
+ "/auth/dash/organization/create": "create",
240
+ "/auth/dash/organization/delete": "delete"
241
+ });
242
+ const hasPermission = async (ctx, _, { strapi: strapi2 }) => {
243
+ const { user, route } = ctx.state;
244
+ if (!user) return false;
245
+ const inherentType = types[route.method];
246
+ const determinedType = endpointsTypes?.[Object.keys(endpointsTypes)?.find(
247
+ (k) => ctx.originalUrl?.includes(k)
248
+ )];
249
+ const found = [];
250
+ for await (const role of user.roles) {
251
+ const categories = endpointsCategories[Object.keys(endpointsCategories).find(
252
+ (key) => ctx.originalUrl.startsWith(key)
253
+ )];
254
+ const permissions = await strapi2.documents("admin::permission").findMany({
255
+ filters: {
256
+ $or: (categories || []).map((cat) => ({
257
+ role: { id: role.id },
258
+ action: {
259
+ $startsWith: "plugin::better-auth-dashboard",
260
+ $containsi: cat,
261
+ $endsWith: determinedType || inherentType
262
+ }
263
+ }))
264
+ }
265
+ });
266
+ if (permissions?.length > 0) found.push(...permissions);
267
+ }
268
+ if (found.length <= 0) {
269
+ throw new PolicyError("You do not have permission to see this content.");
270
+ }
271
+ return true;
272
+ };
273
+ const policies = { "has-permission": hasPermission };
274
+ const ACTIONS = {
275
+ overview: [
276
+ {
277
+ section: "plugins",
278
+ subCategory: "overview",
279
+ displayName: "Read",
280
+ pluginName: PLUGIN_ID,
281
+ uid: "overview.read"
282
+ }
283
+ ],
284
+ user: [
285
+ {
286
+ section: "plugins",
287
+ subCategory: "user",
288
+ displayName: "Create",
289
+ pluginName: PLUGIN_ID,
290
+ uid: "user.create"
291
+ },
292
+ {
293
+ section: "plugins",
294
+ subCategory: "user",
295
+ displayName: "Read",
296
+ pluginName: PLUGIN_ID,
297
+ uid: "user.read"
298
+ },
299
+ {
300
+ section: "plugins",
301
+ subCategory: "user",
302
+ displayName: "Update",
303
+ pluginName: PLUGIN_ID,
304
+ uid: "user.update"
305
+ },
306
+ {
307
+ section: "plugins",
308
+ subCategory: "user",
309
+ displayName: "Delete",
310
+ pluginName: PLUGIN_ID,
311
+ uid: "user.delete"
312
+ }
313
+ ],
314
+ organization: [
315
+ {
316
+ section: "plugins",
317
+ subCategory: "organization",
318
+ displayName: "Create",
319
+ pluginName: PLUGIN_ID,
320
+ uid: "organization.create"
321
+ },
322
+ {
323
+ section: "plugins",
324
+ subCategory: "organization",
325
+ displayName: "Read",
326
+ pluginName: PLUGIN_ID,
327
+ uid: "organization.read"
328
+ },
329
+ {
330
+ section: "plugins",
331
+ subCategory: "organization",
332
+ displayName: "Update",
333
+ pluginName: PLUGIN_ID,
334
+ uid: "organization.update"
335
+ },
336
+ {
337
+ section: "plugins",
338
+ subCategory: "organization",
339
+ displayName: "Delete",
340
+ pluginName: PLUGIN_ID,
341
+ uid: "organization.delete"
342
+ }
343
+ ]
344
+ };
345
+ const register = ({ strapi: strapi2 }) => {
346
+ const actionsToRegister = [...ACTIONS.overview, ...ACTIONS.user];
347
+ if (strapi2.plugin("better-auth").contentTypes?.organization)
348
+ actionsToRegister.push(...ACTIONS.organization);
349
+ strapi2.admin.services.permission.actionProvider.registerMany(
350
+ actionsToRegister
351
+ );
155
352
  };
156
353
  const adminRoutes = () => ({
157
354
  type: "admin",
@@ -161,9 +358,8 @@ const adminRoutes = () => ({
161
358
  path: "/auth/:path*",
162
359
  handler: "auth-controller.handleAuthRequest",
163
360
  config: {
164
- policies: [],
165
- prefix: "",
166
- auth: false
361
+ policies: ["has-permission"],
362
+ prefix: ""
167
363
  }
168
364
  },
169
365
  {
@@ -171,8 +367,7 @@ const adminRoutes = () => ({
171
367
  path: "/auth/:path*",
172
368
  handler: "auth-controller.handleAuthRequest",
173
369
  config: {
174
- policies: [],
175
- auth: false,
370
+ policies: ["has-permission"],
176
371
  prefix: ""
177
372
  }
178
373
  },
@@ -181,8 +376,7 @@ const adminRoutes = () => ({
181
376
  path: "/auth/:path*",
182
377
  handler: "auth-controller.handleAuthRequest",
183
378
  config: {
184
- policies: [],
185
- auth: false,
379
+ policies: ["has-permission"],
186
380
  prefix: ""
187
381
  }
188
382
  },
@@ -191,8 +385,7 @@ const adminRoutes = () => ({
191
385
  path: "/auth/:path*",
192
386
  handler: "auth-controller.handleAuthRequest",
193
387
  config: {
194
- policies: [],
195
- auth: false,
388
+ policies: ["has-permission"],
196
389
  prefix: ""
197
390
  }
198
391
  },
@@ -201,8 +394,7 @@ const adminRoutes = () => ({
201
394
  path: "/auth/:path*",
202
395
  handler: "auth-controller.handleAuthRequest",
203
396
  config: {
204
- policies: [],
205
- auth: false,
397
+ policies: ["has-permission"],
206
398
  prefix: ""
207
399
  }
208
400
  },
@@ -211,7 +403,7 @@ const adminRoutes = () => ({
211
403
  path: "/better-auth-dashboard/db",
212
404
  handler: "db-controller.list",
213
405
  config: {
214
- policies: [],
406
+ policies: ["has-permission"],
215
407
  prefix: ""
216
408
  }
217
409
  },
@@ -220,7 +412,16 @@ const adminRoutes = () => ({
220
412
  path: "/better-auth-dashboard/db/:documentId",
221
413
  handler: "db-controller.update",
222
414
  config: {
223
- policies: [],
415
+ policies: ["has-permission"],
416
+ prefix: ""
417
+ }
418
+ },
419
+ {
420
+ method: "GET",
421
+ path: "/better-auth-dashboard/settings",
422
+ handler: "settings-controller.get",
423
+ config: {
424
+ policies: ["has-permission"],
224
425
  prefix: ""
225
426
  }
226
427
  }
@@ -228,8 +429,12 @@ const adminRoutes = () => ({
228
429
  });
229
430
  const routes = { admin: adminRoutes };
230
431
  const index = {
432
+ config,
231
433
  controllers,
232
- routes
434
+ routes,
435
+ policies,
436
+ register,
437
+ bootstrap
233
438
  };
234
439
  export {
235
440
  index as default
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@strapi-community/plugin-better-auth-dashboard",
3
- "version": "1.0.0-alpha.8",
3
+ "version": "1.0.0-beta.1",
4
4
  "description": "Better Auth dashboard for the Strapi admin panel",
5
5
  "keywords": [
6
6
  "strapi",
@@ -64,7 +64,8 @@
64
64
  "react-intl": "^6.0.0 || ^7.0.0",
65
65
  "react-query": "^3.0.0",
66
66
  "styled-components": "^6.0.0",
67
- "@strapi-community/plugin-better-auth": "^1.0.0-beta.6"
67
+ "react-router-dom": "^6.0.0",
68
+ "@strapi-community/plugin-better-auth": "^1.0.0-beta.7"
68
69
  },
69
70
  "strapi": {
70
71
  "kind": "plugin",