@strapi/admin 5.55.1 → 5.56.0

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.
Files changed (120) hide show
  1. package/dist/admin/admin/src/components/UpsellBanner.js +9 -16
  2. package/dist/admin/admin/src/components/UpsellBanner.js.map +1 -1
  3. package/dist/admin/admin/src/components/UpsellBanner.mjs +11 -18
  4. package/dist/admin/admin/src/components/UpsellBanner.mjs.map +1 -1
  5. package/dist/admin/admin/src/render.js +4 -69
  6. package/dist/admin/admin/src/render.js.map +1 -1
  7. package/dist/admin/admin/src/render.mjs +4 -69
  8. package/dist/admin/admin/src/render.mjs.map +1 -1
  9. package/dist/admin/admin/src/translations/en.json.js +10 -0
  10. package/dist/admin/admin/src/translations/en.json.js.map +1 -1
  11. package/dist/admin/admin/src/translations/en.json.mjs +10 -0
  12. package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
  13. package/dist/admin/admin/src/utils/browserStrapi.js +93 -0
  14. package/dist/admin/admin/src/utils/browserStrapi.js.map +1 -0
  15. package/dist/admin/admin/src/utils/browserStrapi.mjs +91 -0
  16. package/dist/admin/admin/src/utils/browserStrapi.mjs.map +1 -0
  17. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/hooks/useExportAuditLogs.js +2 -1
  18. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/hooks/useExportAuditLogs.js.map +1 -1
  19. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/hooks/useExportAuditLogs.mjs +2 -1
  20. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/hooks/useExportAuditLogs.mjs.map +1 -1
  21. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js +11 -1
  22. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js.map +1 -1
  23. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs +11 -1
  24. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs.map +1 -1
  25. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getDisplayedFilters.js +3 -1
  26. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getDisplayedFilters.js.map +1 -1
  27. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getDisplayedFilters.mjs +3 -1
  28. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getDisplayedFilters.mjs.map +1 -1
  29. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.js +64 -0
  30. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.js.map +1 -0
  31. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.mjs +60 -0
  32. package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.mjs.map +1 -0
  33. package/dist/admin/ee/admin/src/services/auditLogs.js +2 -1
  34. package/dist/admin/ee/admin/src/services/auditLogs.js.map +1 -1
  35. package/dist/admin/ee/admin/src/services/auditLogs.mjs +2 -1
  36. package/dist/admin/ee/admin/src/services/auditLogs.mjs.map +1 -1
  37. package/dist/admin/src/components/SubNav.d.ts +2 -2
  38. package/dist/admin/src/utils/browserStrapi.d.ts +11 -0
  39. package/dist/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.d.ts +10 -0
  40. package/dist/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.d.ts +14 -0
  41. package/dist/ee/server/src/audit-logs/services/lifecycles.d.ts +10 -1
  42. package/dist/ee/server/src/audit-logs/services/lifecycles.d.ts.map +1 -1
  43. package/dist/ee/server/src/controllers/admin.d.ts +2 -28
  44. package/dist/ee/server/src/controllers/admin.d.ts.map +1 -1
  45. package/dist/ee/server/src/controllers/index.d.ts +1 -28
  46. package/dist/ee/server/src/controllers/index.d.ts.map +1 -1
  47. package/dist/ee/server/src/index.d.ts +2 -29
  48. package/dist/ee/server/src/index.d.ts.map +1 -1
  49. package/dist/ee/server/src/services/auth.d.ts +1 -1
  50. package/dist/ee/server/src/services/auth.d.ts.map +1 -1
  51. package/dist/ee/server/src/services/index.d.ts +1 -1
  52. package/dist/ee/server/src/services/user.d.ts.map +1 -1
  53. package/dist/server/ee/server/src/audit-logs/services/lifecycles.js +37 -21
  54. package/dist/server/ee/server/src/audit-logs/services/lifecycles.js.map +1 -1
  55. package/dist/server/ee/server/src/audit-logs/services/lifecycles.mjs +37 -21
  56. package/dist/server/ee/server/src/audit-logs/services/lifecycles.mjs.map +1 -1
  57. package/dist/server/ee/server/src/controllers/admin.js +5 -3
  58. package/dist/server/ee/server/src/controllers/admin.js.map +1 -1
  59. package/dist/server/ee/server/src/controllers/admin.mjs +5 -3
  60. package/dist/server/ee/server/src/controllers/admin.mjs.map +1 -1
  61. package/dist/server/ee/server/src/index.js +4 -0
  62. package/dist/server/ee/server/src/index.js.map +1 -1
  63. package/dist/server/ee/server/src/index.mjs +4 -0
  64. package/dist/server/ee/server/src/index.mjs.map +1 -1
  65. package/dist/server/ee/server/src/services/auth.js +1 -6
  66. package/dist/server/ee/server/src/services/auth.js.map +1 -1
  67. package/dist/server/ee/server/src/services/auth.mjs +2 -7
  68. package/dist/server/ee/server/src/services/auth.mjs.map +1 -1
  69. package/dist/server/ee/server/src/services/user.js +36 -4
  70. package/dist/server/ee/server/src/services/user.js.map +1 -1
  71. package/dist/server/ee/server/src/services/user.mjs +36 -4
  72. package/dist/server/ee/server/src/services/user.mjs.map +1 -1
  73. package/dist/server/server/src/audit-logs/admin-users.js +169 -0
  74. package/dist/server/server/src/audit-logs/admin-users.js.map +1 -0
  75. package/dist/server/server/src/audit-logs/admin-users.mjs +157 -0
  76. package/dist/server/server/src/audit-logs/admin-users.mjs.map +1 -0
  77. package/dist/server/server/src/audit-logs/webhooks.js +106 -0
  78. package/dist/server/server/src/audit-logs/webhooks.js.map +1 -0
  79. package/dist/server/server/src/audit-logs/webhooks.mjs +100 -0
  80. package/dist/server/server/src/audit-logs/webhooks.mjs.map +1 -0
  81. package/dist/server/server/src/controllers/admin.js +1 -0
  82. package/dist/server/server/src/controllers/admin.js.map +1 -1
  83. package/dist/server/server/src/controllers/admin.mjs +1 -0
  84. package/dist/server/server/src/controllers/admin.mjs.map +1 -1
  85. package/dist/server/server/src/controllers/authentication.js +8 -1
  86. package/dist/server/server/src/controllers/authentication.js.map +1 -1
  87. package/dist/server/server/src/controllers/authentication.mjs +8 -1
  88. package/dist/server/server/src/controllers/authentication.mjs.map +1 -1
  89. package/dist/server/server/src/controllers/webhooks.js +26 -0
  90. package/dist/server/server/src/controllers/webhooks.js.map +1 -1
  91. package/dist/server/server/src/controllers/webhooks.mjs +27 -1
  92. package/dist/server/server/src/controllers/webhooks.mjs.map +1 -1
  93. package/dist/server/server/src/services/auth.js +27 -6
  94. package/dist/server/server/src/services/auth.js.map +1 -1
  95. package/dist/server/server/src/services/auth.mjs +28 -8
  96. package/dist/server/server/src/services/auth.mjs.map +1 -1
  97. package/dist/server/server/src/services/user.js +48 -9
  98. package/dist/server/server/src/services/user.js.map +1 -1
  99. package/dist/server/server/src/services/user.mjs +49 -10
  100. package/dist/server/server/src/services/user.mjs.map +1 -1
  101. package/dist/server/src/audit-logs/admin-users.d.ts +119 -0
  102. package/dist/server/src/audit-logs/admin-users.d.ts.map +1 -0
  103. package/dist/server/src/audit-logs/webhooks.d.ts +59 -0
  104. package/dist/server/src/audit-logs/webhooks.d.ts.map +1 -0
  105. package/dist/server/src/controllers/admin.d.ts +2 -11
  106. package/dist/server/src/controllers/admin.d.ts.map +1 -1
  107. package/dist/server/src/controllers/authentication.d.ts.map +1 -1
  108. package/dist/server/src/controllers/index.d.ts +1 -10
  109. package/dist/server/src/controllers/index.d.ts.map +1 -1
  110. package/dist/server/src/controllers/webhooks.d.ts.map +1 -1
  111. package/dist/server/src/domain/user.d.ts +2 -2
  112. package/dist/server/src/index.d.ts +1 -10
  113. package/dist/server/src/index.d.ts.map +1 -1
  114. package/dist/server/src/services/auth.d.ts +6 -1
  115. package/dist/server/src/services/auth.d.ts.map +1 -1
  116. package/dist/server/src/services/index.d.ts.map +1 -1
  117. package/dist/server/src/services/user.d.ts.map +1 -1
  118. package/dist/shared/contracts/admin.d.ts +36 -2
  119. package/dist/shared/contracts/admin.d.ts.map +1 -1
  120. package/package.json +11 -11
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-users.mjs","sources":["../../../../../server/src/audit-logs/admin-users.ts"],"sourcesContent":["import { isEqual, sortBy } from 'lodash/fp';\nimport type { Data, Modules } from '@strapi/types';\nimport { emitAudit } from '@strapi/utils';\n\nexport const AUDITED_EVENTS = {\n USER_CREATE: 'admin-user.create',\n USER_UPDATE: 'admin-user.update',\n USER_DELETE: 'admin-user.delete',\n PASSWORD_RESET_CREATE: 'admin-user.password-reset.create',\n PASSWORD_RESET_CONFIRM: 'admin-user.password-reset.confirm',\n PASSWORD_UPDATE: 'admin-user.password.update',\n INVITE_ACCEPT: 'admin-user.invite.accept',\n} as const;\n\n/**\n * Event hub events kept for custom listeners. The audit log no longer records them:\n * it records the AUDITED_EVENTS above, built from the row with before/after values.\n *\n * @deprecated Removed in the next major. Listen to the audit log events, or to the\n * database lifecycles, instead.\n */\nexport const LEGACY_USER_EVENTS = {\n CREATE: 'user.create',\n UPDATE: 'user.update',\n DELETE: 'user.delete',\n} as const;\n\nexport interface AdminUserResource extends Modules.AuditLogs.Resource {\n type: 'admin-user';\n id: Data.ID;\n email: string;\n}\n\n/**\n * The affected account, as read from the `admin::user` row after the write. Never the\n * row itself: it carries the password hash and the reset and registration tokens.\n */\nexport interface AdminUserEvent {\n userId: Data.ID;\n email: string;\n}\n\n/**\n * The fields an audit reader needs to identify the account and its access. Never\n * `password`, the tokens, or the timestamps: the row has its own date.\n */\nexport const ADMIN_USER_TRACKED_FIELDS = [\n 'firstname',\n 'lastname',\n 'email',\n 'username',\n 'preferedLanguage',\n 'isActive',\n] as const;\n\ntype TrackedField = (typeof ADMIN_USER_TRACKED_FIELDS)[number];\n\n/** A user row, or the attributes of an update: roles come as rows or as ids. */\nexport interface AdminUserSnapshot {\n firstname?: string | null;\n lastname?: string | null;\n email?: string | null;\n username?: string | null;\n preferedLanguage?: string | null;\n isActive?: boolean | null;\n roles?: Array<Data.ID | { id: Data.ID }> | null;\n}\n\nexport type AdminUserChanges = Partial<\n Record<TrackedField, Modules.AuditLogs.FieldChange<string | boolean | null>> & {\n roles: Modules.AuditLogs.FieldChange<Data.ID[]>;\n }\n>;\n\nexport interface CreateDetails {\n email: string;\n firstname: string | null;\n lastname: string | null;\n roles: Data.ID[];\n isActive: boolean;\n}\n\nexport type CreateEvent = AdminUserEvent & Omit<CreateDetails, 'email'>;\nexport type UpdateEvent = AdminUserEvent & { changes: AdminUserChanges };\nexport type PasswordResetCreateEvent = AdminUserEvent & { expiresAt: string | Date };\n\n/** Sorted, so order alone is not a change. */\nexport const toRoleIds = (roles: AdminUserSnapshot['roles']): Data.ID[] =>\n sortBy(\n (id: Data.ID) => String(id),\n (roles ?? []).map((role) => (typeof role === 'object' ? role.id : role))\n );\n\nexport const getAdminUserChanges = (\n previous: AdminUserSnapshot,\n next: AdminUserSnapshot\n): AdminUserChanges => {\n const changes: AdminUserChanges = {};\n\n for (const field of ADMIN_USER_TRACKED_FIELDS) {\n // isActive is a boolean column that older rows may hold as null\n const before = field === 'isActive' ? previous.isActive === true : (previous[field] ?? null);\n const after = field === 'isActive' ? next.isActive === true : (next[field] ?? null);\n\n if (before !== after) {\n changes[field] = { before, after };\n }\n }\n\n if (previous.roles != null || next.roles != null) {\n const before = toRoleIds(previous.roles);\n const after = toRoleIds(next.roles);\n\n if (!isEqual(before, after)) {\n changes.roles = { before, after };\n }\n }\n\n return changes;\n};\n\n/**\n * `email` is required by the admin::user schema; the contract type marks it optional\n * because it also describes creation payloads.\n */\nexport const toAdminUserEvent = (user: { id: Data.ID; email?: string | null }): AdminUserEvent => ({\n userId: user.id,\n email: user.email as string,\n});\n\ntype AuditStrapi = Parameters<typeof emitAudit>[0]['strapi'];\n\ninterface AdminUserRow extends AdminUserSnapshot {\n id: Data.ID;\n}\n\nexport const emitAdminUserCreated = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_CREATE, {\n ...toAdminUserEvent(user),\n firstname: user.firstname ?? null,\n lastname: user.lastname ?? null,\n roles: toRoleIds(user.roles),\n isActive: user.isActive === true,\n } satisfies CreateEvent);\n\nexport const emitAdminUserDeleted = ({ strapi }: { strapi: AuditStrapi }, user: AdminUserRow) =>\n emitAudit({ strapi }, AUDITED_EVENTS.USER_DELETE, toAdminUserEvent(user));\n\n/** Whether an update touches a field the audit log compares, so the previous row is needed. */\nexport const touchesTrackedFields = (attributes: Record<string, unknown>) =>\n [...ADMIN_USER_TRACKED_FIELDS, 'roles'].some((field) => field in attributes);\n\n/**\n * The account events an update can produce, emitted by updateById after the write:\n * `admin-user.update` with the fields that changed, `admin-user.password.update` when a\n * password was set. Both run through the request context, so a public flow (reset,\n * invitation) with no session emits them too and the subscriber drops them.\n */\nexport const emitAdminUserUpdateAudits = async (\n { strapi }: { strapi: AuditStrapi },\n {\n previous,\n updated,\n attributes,\n }: {\n previous: AdminUserSnapshot | null | undefined;\n updated: AdminUserRow | null | undefined;\n attributes: Record<string, unknown>;\n }\n) => {\n if (!updated) {\n return;\n }\n\n if (previous) {\n const changes = getAdminUserChanges(previous, updated);\n\n if (Object.keys(changes).length > 0) {\n await emitAudit({ strapi }, AUDITED_EVENTS.USER_UPDATE, {\n ...toAdminUserEvent(updated),\n changes,\n } satisfies UpdateEvent);\n }\n }\n\n if ('password' in attributes) {\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_UPDATE, toAdminUserEvent(updated));\n }\n};\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>,\n options?: { allowUnknownActor?: boolean }\n ): void;\n}\n\nexport const registerAdminUserAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const resource = (event: AdminUserEvent): AdminUserResource => ({\n type: 'admin-user',\n id: event.userId,\n email: event.email,\n });\n\n const withoutSession = { allowUnknownActor: true };\n\n // The first super admin registers from a public form too\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.USER_CREATE,\n (event: CreateEvent) => ({\n resource: resource(event),\n details: {\n email: event.email,\n firstname: event.firstname,\n lastname: event.lastname,\n roles: event.roles,\n isActive: event.isActive,\n },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<{ changes: AdminUserChanges }>(\n AUDITED_EVENTS.USER_UPDATE,\n (event: UpdateEvent) => ({\n resource: resource(event),\n details: { changes: event.changes },\n })\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.USER_DELETE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n\n auditLogsLifecycle.registerEvent<{ expiresAt: string }>(\n AUDITED_EVENTS.PASSWORD_RESET_CREATE,\n (event: PasswordResetCreateEvent) => ({\n resource: resource(event),\n details: { expiresAt: new Date(event.expiresAt).toISOString() },\n }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_RESET_CONFIRM,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.INVITE_ACCEPT,\n (event: AdminUserEvent) => ({ resource: resource(event) }),\n withoutSession\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.PASSWORD_UPDATE,\n (event: AdminUserEvent) => ({ resource: resource(event) })\n );\n};\n"],"names":["AUDITED_EVENTS","USER_CREATE","USER_UPDATE","USER_DELETE","PASSWORD_RESET_CREATE","PASSWORD_RESET_CONFIRM","PASSWORD_UPDATE","INVITE_ACCEPT","LEGACY_USER_EVENTS","CREATE","UPDATE","DELETE","ADMIN_USER_TRACKED_FIELDS","toRoleIds","roles","sortBy","id","String","map","role","getAdminUserChanges","previous","next","changes","field","before","isActive","after","isEqual","toAdminUserEvent","user","userId","email","emitAdminUserCreated","strapi","emitAudit","firstname","lastname","emitAdminUserDeleted","touchesTrackedFields","attributes","some","emitAdminUserUpdateAudits","updated","Object","keys","length","registerAdminUserAuditEvents","auditLogsLifecycle","resource","event","type","withoutSession","allowUnknownActor","registerEvent","details","expiresAt","Date","toISOString"],"mappings":"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"}
@@ -0,0 +1,106 @@
1
+ 'use strict';
2
+
3
+ var fp = require('lodash/fp');
4
+
5
+ const AUDITED_EVENTS = {
6
+ WEBHOOK_CREATE: 'webhook.create',
7
+ WEBHOOK_UPDATE: 'webhook.update',
8
+ WEBHOOK_DELETE: 'webhook.delete'
9
+ };
10
+ const AUDITED_FIELDS = [
11
+ 'name',
12
+ 'url',
13
+ 'events',
14
+ 'isEnabled'
15
+ ];
16
+ const sortStrings = (values)=>[
17
+ ...values
18
+ ].sort((a, b)=>a.localeCompare(b));
19
+ /**
20
+ * Scheme and host only. The rest of a webhook URL is often the credential: userinfo,
21
+ * `?token=`, or a path segment (Slack, Netlify, Discord hooks).
22
+ */ const toAuditedUrl = (url)=>{
23
+ try {
24
+ const { protocol, host } = new URL(url);
25
+ return `${protocol}//${host}`;
26
+ } catch {
27
+ return url.replace(/\/\/[^/@]*@/, '//').match(/^[^:]+:\/\/[^/?#]*/)?.[0] ?? '';
28
+ }
29
+ };
30
+ const toAuditedWebhook = (webhook)=>({
31
+ webhookId: webhook.id,
32
+ name: webhook.name,
33
+ url: toAuditedUrl(webhook.url),
34
+ events: sortStrings(webhook.events ?? []),
35
+ headers: sortStrings(Object.keys(webhook.headers ?? {})),
36
+ isEnabled: webhook.isEnabled
37
+ });
38
+ const getHeaderChanges = (previous, next)=>{
39
+ const before = previous ?? {};
40
+ const after = next ?? {};
41
+ const names = sortStrings([
42
+ ...new Set([
43
+ ...Object.keys(before),
44
+ ...Object.keys(after)
45
+ ])
46
+ ]);
47
+ const has = (headers, name)=>Object.hasOwn(headers, name);
48
+ const changes = {
49
+ added: names.filter((name)=>!has(before, name)),
50
+ removed: names.filter((name)=>!has(after, name)),
51
+ changed: names.filter((name)=>has(before, name) && has(after, name) && before[name] !== after[name])
52
+ };
53
+ return Object.values(changes).some((list)=>list.length > 0) ? changes : undefined;
54
+ };
55
+ const getWebhookChanges = (previous, next)=>{
56
+ const before = toAuditedWebhook(previous);
57
+ const after = toAuditedWebhook(next);
58
+ const changes = {};
59
+ for (const field of AUDITED_FIELDS){
60
+ // The url is compared as stored, so a change to its stripped part is recorded too.
61
+ const changed = field === 'url' ? previous.url !== next.url : !fp.isEqual(before[field], after[field]);
62
+ if (changed) {
63
+ changes[field] = {
64
+ before: before[field],
65
+ after: after[field]
66
+ };
67
+ }
68
+ }
69
+ const headers = getHeaderChanges(previous.headers, next.headers);
70
+ if (headers) {
71
+ changes.headers = headers;
72
+ }
73
+ return changes;
74
+ };
75
+ const registerWebhookAuditEvents = (auditLogsLifecycle)=>{
76
+ const webhookResource = (event)=>({
77
+ type: 'webhook',
78
+ id: event.webhookId,
79
+ name: event.name
80
+ });
81
+ auditLogsLifecycle.registerEvent(AUDITED_EVENTS.WEBHOOK_CREATE, (event)=>({
82
+ resource: webhookResource(event),
83
+ details: {
84
+ url: event.url,
85
+ events: event.events,
86
+ headers: event.headers,
87
+ isEnabled: event.isEnabled
88
+ }
89
+ }));
90
+ auditLogsLifecycle.registerEvent(AUDITED_EVENTS.WEBHOOK_UPDATE, (event)=>({
91
+ resource: webhookResource(event),
92
+ details: {
93
+ changes: event.changes
94
+ }
95
+ }));
96
+ auditLogsLifecycle.registerEvent(AUDITED_EVENTS.WEBHOOK_DELETE, (event)=>({
97
+ resource: webhookResource(event)
98
+ }));
99
+ };
100
+
101
+ exports.AUDITED_EVENTS = AUDITED_EVENTS;
102
+ exports.getWebhookChanges = getWebhookChanges;
103
+ exports.registerWebhookAuditEvents = registerWebhookAuditEvents;
104
+ exports.toAuditedUrl = toAuditedUrl;
105
+ exports.toAuditedWebhook = toAuditedWebhook;
106
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sources":["../../../../../server/src/audit-logs/webhooks.ts"],"sourcesContent":["import { isEqual } from 'lodash/fp';\nimport type { Modules } from '@strapi/types';\n\nexport const AUDITED_EVENTS = {\n WEBHOOK_CREATE: 'webhook.create',\n WEBHOOK_UPDATE: 'webhook.update',\n WEBHOOK_DELETE: 'webhook.delete',\n} as const;\n\ntype Webhook = Modules.WebhookStore.Webhook;\n\nexport interface WebhookEvent {\n webhookId: string;\n name: string;\n}\n\n/**\n * The webhook as it may enter a payload: header names only, sorted. Header values\n * carry `Authorization` tokens and are never recorded, not even on the event hub.\n */\nexport interface AuditedWebhook extends WebhookEvent {\n url: string;\n events: string[];\n headers: string[];\n isEnabled: boolean;\n}\n\nconst AUDITED_FIELDS = ['name', 'url', 'events', 'isEnabled'] as const;\n\n/**\n * Header values are secrets, so the diff lists names only. `changed`: headers whose\n * value changed.\n */\nexport interface HeaderChanges {\n added: string[];\n removed: string[];\n changed: string[];\n}\n\nexport type WebhookChanges = Partial<{\n name: Modules.AuditLogs.FieldChange<string>;\n url: Modules.AuditLogs.FieldChange<string>;\n events: Modules.AuditLogs.FieldChange<string[]>;\n headers: HeaderChanges;\n isEnabled: Modules.AuditLogs.FieldChange<boolean>;\n}>;\n\nexport type CreateDetails = Omit<AuditedWebhook, keyof WebhookEvent>;\n\nexport interface UpdateDetails {\n changes: WebhookChanges;\n}\n\nexport type UpdateEvent = WebhookEvent & UpdateDetails;\n\nconst sortStrings = (values: string[]): string[] => [...values].sort((a, b) => a.localeCompare(b));\n\n/**\n * Scheme and host only. The rest of a webhook URL is often the credential: userinfo,\n * `?token=`, or a path segment (Slack, Netlify, Discord hooks).\n */\nexport const toAuditedUrl = (url: string): string => {\n try {\n const { protocol, host } = new URL(url);\n return `${protocol}//${host}`;\n } catch {\n return url.replace(/\\/\\/[^/@]*@/, '//').match(/^[^:]+:\\/\\/[^/?#]*/)?.[0] ?? '';\n }\n};\n\nexport const toAuditedWebhook = (webhook: Webhook): AuditedWebhook => ({\n webhookId: webhook.id,\n name: webhook.name,\n url: toAuditedUrl(webhook.url),\n events: sortStrings(webhook.events ?? []),\n headers: sortStrings(Object.keys(webhook.headers ?? {})),\n isEnabled: webhook.isEnabled,\n});\n\nconst getHeaderChanges = (\n previous: Webhook['headers'],\n next: Webhook['headers']\n): HeaderChanges | undefined => {\n const before = previous ?? {};\n const after = next ?? {};\n const names = sortStrings([...new Set([...Object.keys(before), ...Object.keys(after)])]);\n\n const has = (headers: Webhook['headers'], name: string) => Object.hasOwn(headers, name);\n\n const changes: HeaderChanges = {\n added: names.filter((name) => !has(before, name)),\n removed: names.filter((name) => !has(after, name)),\n changed: names.filter(\n (name) => has(before, name) && has(after, name) && before[name] !== after[name]\n ),\n };\n\n return Object.values(changes).some((list) => list.length > 0) ? changes : undefined;\n};\n\nexport const getWebhookChanges = (previous: Webhook, next: Webhook): WebhookChanges => {\n const before = toAuditedWebhook(previous);\n const after = toAuditedWebhook(next);\n const changes: WebhookChanges = {};\n\n for (const field of AUDITED_FIELDS) {\n // The url is compared as stored, so a change to its stripped part is recorded too.\n const changed =\n field === 'url' ? previous.url !== next.url : !isEqual(before[field], after[field]);\n\n if (changed) {\n (changes as Record<string, unknown>)[field] = { before: before[field], after: after[field] };\n }\n }\n\n const headers = getHeaderChanges(previous.headers, next.headers);\n\n if (headers) {\n changes.headers = headers;\n }\n\n return changes;\n};\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>\n ): void;\n}\n\nexport const registerWebhookAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const webhookResource = (event: WebhookEvent): Modules.AuditLogs.Resource => ({\n type: 'webhook',\n id: event.webhookId,\n name: event.name,\n });\n\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.WEBHOOK_CREATE,\n (event: AuditedWebhook) => ({\n resource: webhookResource(event),\n details: {\n url: event.url,\n events: event.events,\n headers: event.headers,\n isEnabled: event.isEnabled,\n },\n })\n );\n\n auditLogsLifecycle.registerEvent<UpdateDetails>(\n AUDITED_EVENTS.WEBHOOK_UPDATE,\n (event: UpdateEvent) => ({\n resource: webhookResource(event),\n details: { changes: event.changes },\n })\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.WEBHOOK_DELETE,\n (event: WebhookEvent) => ({\n resource: webhookResource(event),\n })\n );\n};\n"],"names":["AUDITED_EVENTS","WEBHOOK_CREATE","WEBHOOK_UPDATE","WEBHOOK_DELETE","AUDITED_FIELDS","sortStrings","values","sort","a","b","localeCompare","toAuditedUrl","url","protocol","host","URL","replace","match","toAuditedWebhook","webhook","webhookId","id","name","events","headers","Object","keys","isEnabled","getHeaderChanges","previous","next","before","after","names","Set","has","hasOwn","changes","added","filter","removed","changed","some","list","length","undefined","getWebhookChanges","field","isEqual","registerWebhookAuditEvents","auditLogsLifecycle","webhookResource","event","type","registerEvent","resource","details"],"mappings":"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"}
@@ -0,0 +1,100 @@
1
+ import { isEqual } from 'lodash/fp';
2
+
3
+ const AUDITED_EVENTS = {
4
+ WEBHOOK_CREATE: 'webhook.create',
5
+ WEBHOOK_UPDATE: 'webhook.update',
6
+ WEBHOOK_DELETE: 'webhook.delete'
7
+ };
8
+ const AUDITED_FIELDS = [
9
+ 'name',
10
+ 'url',
11
+ 'events',
12
+ 'isEnabled'
13
+ ];
14
+ const sortStrings = (values)=>[
15
+ ...values
16
+ ].sort((a, b)=>a.localeCompare(b));
17
+ /**
18
+ * Scheme and host only. The rest of a webhook URL is often the credential: userinfo,
19
+ * `?token=`, or a path segment (Slack, Netlify, Discord hooks).
20
+ */ const toAuditedUrl = (url)=>{
21
+ try {
22
+ const { protocol, host } = new URL(url);
23
+ return `${protocol}//${host}`;
24
+ } catch {
25
+ return url.replace(/\/\/[^/@]*@/, '//').match(/^[^:]+:\/\/[^/?#]*/)?.[0] ?? '';
26
+ }
27
+ };
28
+ const toAuditedWebhook = (webhook)=>({
29
+ webhookId: webhook.id,
30
+ name: webhook.name,
31
+ url: toAuditedUrl(webhook.url),
32
+ events: sortStrings(webhook.events ?? []),
33
+ headers: sortStrings(Object.keys(webhook.headers ?? {})),
34
+ isEnabled: webhook.isEnabled
35
+ });
36
+ const getHeaderChanges = (previous, next)=>{
37
+ const before = previous ?? {};
38
+ const after = next ?? {};
39
+ const names = sortStrings([
40
+ ...new Set([
41
+ ...Object.keys(before),
42
+ ...Object.keys(after)
43
+ ])
44
+ ]);
45
+ const has = (headers, name)=>Object.hasOwn(headers, name);
46
+ const changes = {
47
+ added: names.filter((name)=>!has(before, name)),
48
+ removed: names.filter((name)=>!has(after, name)),
49
+ changed: names.filter((name)=>has(before, name) && has(after, name) && before[name] !== after[name])
50
+ };
51
+ return Object.values(changes).some((list)=>list.length > 0) ? changes : undefined;
52
+ };
53
+ const getWebhookChanges = (previous, next)=>{
54
+ const before = toAuditedWebhook(previous);
55
+ const after = toAuditedWebhook(next);
56
+ const changes = {};
57
+ for (const field of AUDITED_FIELDS){
58
+ // The url is compared as stored, so a change to its stripped part is recorded too.
59
+ const changed = field === 'url' ? previous.url !== next.url : !isEqual(before[field], after[field]);
60
+ if (changed) {
61
+ changes[field] = {
62
+ before: before[field],
63
+ after: after[field]
64
+ };
65
+ }
66
+ }
67
+ const headers = getHeaderChanges(previous.headers, next.headers);
68
+ if (headers) {
69
+ changes.headers = headers;
70
+ }
71
+ return changes;
72
+ };
73
+ const registerWebhookAuditEvents = (auditLogsLifecycle)=>{
74
+ const webhookResource = (event)=>({
75
+ type: 'webhook',
76
+ id: event.webhookId,
77
+ name: event.name
78
+ });
79
+ auditLogsLifecycle.registerEvent(AUDITED_EVENTS.WEBHOOK_CREATE, (event)=>({
80
+ resource: webhookResource(event),
81
+ details: {
82
+ url: event.url,
83
+ events: event.events,
84
+ headers: event.headers,
85
+ isEnabled: event.isEnabled
86
+ }
87
+ }));
88
+ auditLogsLifecycle.registerEvent(AUDITED_EVENTS.WEBHOOK_UPDATE, (event)=>({
89
+ resource: webhookResource(event),
90
+ details: {
91
+ changes: event.changes
92
+ }
93
+ }));
94
+ auditLogsLifecycle.registerEvent(AUDITED_EVENTS.WEBHOOK_DELETE, (event)=>({
95
+ resource: webhookResource(event)
96
+ }));
97
+ };
98
+
99
+ export { AUDITED_EVENTS, getWebhookChanges, registerWebhookAuditEvents, toAuditedUrl, toAuditedWebhook };
100
+ //# sourceMappingURL=webhooks.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.mjs","sources":["../../../../../server/src/audit-logs/webhooks.ts"],"sourcesContent":["import { isEqual } from 'lodash/fp';\nimport type { Modules } from '@strapi/types';\n\nexport const AUDITED_EVENTS = {\n WEBHOOK_CREATE: 'webhook.create',\n WEBHOOK_UPDATE: 'webhook.update',\n WEBHOOK_DELETE: 'webhook.delete',\n} as const;\n\ntype Webhook = Modules.WebhookStore.Webhook;\n\nexport interface WebhookEvent {\n webhookId: string;\n name: string;\n}\n\n/**\n * The webhook as it may enter a payload: header names only, sorted. Header values\n * carry `Authorization` tokens and are never recorded, not even on the event hub.\n */\nexport interface AuditedWebhook extends WebhookEvent {\n url: string;\n events: string[];\n headers: string[];\n isEnabled: boolean;\n}\n\nconst AUDITED_FIELDS = ['name', 'url', 'events', 'isEnabled'] as const;\n\n/**\n * Header values are secrets, so the diff lists names only. `changed`: headers whose\n * value changed.\n */\nexport interface HeaderChanges {\n added: string[];\n removed: string[];\n changed: string[];\n}\n\nexport type WebhookChanges = Partial<{\n name: Modules.AuditLogs.FieldChange<string>;\n url: Modules.AuditLogs.FieldChange<string>;\n events: Modules.AuditLogs.FieldChange<string[]>;\n headers: HeaderChanges;\n isEnabled: Modules.AuditLogs.FieldChange<boolean>;\n}>;\n\nexport type CreateDetails = Omit<AuditedWebhook, keyof WebhookEvent>;\n\nexport interface UpdateDetails {\n changes: WebhookChanges;\n}\n\nexport type UpdateEvent = WebhookEvent & UpdateDetails;\n\nconst sortStrings = (values: string[]): string[] => [...values].sort((a, b) => a.localeCompare(b));\n\n/**\n * Scheme and host only. The rest of a webhook URL is often the credential: userinfo,\n * `?token=`, or a path segment (Slack, Netlify, Discord hooks).\n */\nexport const toAuditedUrl = (url: string): string => {\n try {\n const { protocol, host } = new URL(url);\n return `${protocol}//${host}`;\n } catch {\n return url.replace(/\\/\\/[^/@]*@/, '//').match(/^[^:]+:\\/\\/[^/?#]*/)?.[0] ?? '';\n }\n};\n\nexport const toAuditedWebhook = (webhook: Webhook): AuditedWebhook => ({\n webhookId: webhook.id,\n name: webhook.name,\n url: toAuditedUrl(webhook.url),\n events: sortStrings(webhook.events ?? []),\n headers: sortStrings(Object.keys(webhook.headers ?? {})),\n isEnabled: webhook.isEnabled,\n});\n\nconst getHeaderChanges = (\n previous: Webhook['headers'],\n next: Webhook['headers']\n): HeaderChanges | undefined => {\n const before = previous ?? {};\n const after = next ?? {};\n const names = sortStrings([...new Set([...Object.keys(before), ...Object.keys(after)])]);\n\n const has = (headers: Webhook['headers'], name: string) => Object.hasOwn(headers, name);\n\n const changes: HeaderChanges = {\n added: names.filter((name) => !has(before, name)),\n removed: names.filter((name) => !has(after, name)),\n changed: names.filter(\n (name) => has(before, name) && has(after, name) && before[name] !== after[name]\n ),\n };\n\n return Object.values(changes).some((list) => list.length > 0) ? changes : undefined;\n};\n\nexport const getWebhookChanges = (previous: Webhook, next: Webhook): WebhookChanges => {\n const before = toAuditedWebhook(previous);\n const after = toAuditedWebhook(next);\n const changes: WebhookChanges = {};\n\n for (const field of AUDITED_FIELDS) {\n // The url is compared as stored, so a change to its stripped part is recorded too.\n const changed =\n field === 'url' ? previous.url !== next.url : !isEqual(before[field], after[field]);\n\n if (changed) {\n (changes as Record<string, unknown>)[field] = { before: before[field], after: after[field] };\n }\n }\n\n const headers = getHeaderChanges(previous.headers, next.headers);\n\n if (headers) {\n changes.headers = headers;\n }\n\n return changes;\n};\n\n/**\n * The part of the audit-logs lifecycle service used here.\n * The full service type lives in the Admin EE package.\n */\ninterface AuditLogsLifecycle {\n registerEvent<TDetails>(\n name: string,\n transform: Modules.AuditLogs.EventTransformer<TDetails>\n ): void;\n}\n\nexport const registerWebhookAuditEvents = (auditLogsLifecycle: AuditLogsLifecycle) => {\n const webhookResource = (event: WebhookEvent): Modules.AuditLogs.Resource => ({\n type: 'webhook',\n id: event.webhookId,\n name: event.name,\n });\n\n auditLogsLifecycle.registerEvent<CreateDetails>(\n AUDITED_EVENTS.WEBHOOK_CREATE,\n (event: AuditedWebhook) => ({\n resource: webhookResource(event),\n details: {\n url: event.url,\n events: event.events,\n headers: event.headers,\n isEnabled: event.isEnabled,\n },\n })\n );\n\n auditLogsLifecycle.registerEvent<UpdateDetails>(\n AUDITED_EVENTS.WEBHOOK_UPDATE,\n (event: UpdateEvent) => ({\n resource: webhookResource(event),\n details: { changes: event.changes },\n })\n );\n\n auditLogsLifecycle.registerEvent<undefined>(\n AUDITED_EVENTS.WEBHOOK_DELETE,\n (event: WebhookEvent) => ({\n resource: webhookResource(event),\n })\n );\n};\n"],"names":["AUDITED_EVENTS","WEBHOOK_CREATE","WEBHOOK_UPDATE","WEBHOOK_DELETE","AUDITED_FIELDS","sortStrings","values","sort","a","b","localeCompare","toAuditedUrl","url","protocol","host","URL","replace","match","toAuditedWebhook","webhook","webhookId","id","name","events","headers","Object","keys","isEnabled","getHeaderChanges","previous","next","before","after","names","Set","has","hasOwn","changes","added","filter","removed","changed","some","list","length","undefined","getWebhookChanges","field","isEqual","registerWebhookAuditEvents","auditLogsLifecycle","webhookResource","event","type","registerEvent","resource","details"],"mappings":"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"}
@@ -34,6 +34,7 @@ const isUsingTypeScript = (...args)=>{
34
34
  return {
35
35
  data: {
36
36
  isEE: false,
37
+ isTrial: false,
37
38
  features: [],
38
39
  flags,
39
40
  ai: {
@@ -1 +1 @@
1
- {"version":3,"file":"admin.js","sources":["../../../../../server/src/controllers/admin.ts"],"sourcesContent":["import type { Context } from 'koa';\n\nimport path from 'path';\n\nimport { map, values, sumBy, pipe, flatMap, propEq } from 'lodash/fp';\nimport _ from 'lodash';\nimport { exists } from 'fs-extra';\nimport { env } from '@strapi/utils';\nimport {\n validateUpdateProjectSettings,\n validateUpdateProjectSettingsFiles,\n validateUpdateProjectSettingsImagesDimensions,\n} from '../validation/project-settings';\nimport { getService } from '../utils';\n\nimport type {\n Init,\n GetProjectSettings,\n Information,\n Plugins,\n TelemetryProperties,\n UpdateProjectSettings,\n GetGuidedTourMeta,\n} from '../../../shared/contracts/admin';\n\n// Lazy: only resolved on first GET /admin/project-type request\ntype TsUtilsModule = typeof import('@strapi/typescript-utils');\nlet lazyTsUtils: TsUtilsModule | undefined;\nconst isUsingTypeScript: TsUtilsModule['isUsingTypeScript'] = (\n ...args: Parameters<TsUtilsModule['isUsingTypeScript']>\n) => {\n if (!lazyTsUtils) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n lazyTsUtils = require('@strapi/typescript-utils');\n }\n return (lazyTsUtils as TsUtilsModule).isUsingTypeScript(...args);\n};\n\n/**\n * A set of functions called \"actions\" for `Admin`\n */\nexport default {\n // TODO very temporary to check the switch ee/ce\n // When removing this we need to update the /admin/src/index.js file\n // whe,re we set the strapi.window.isEE value\n\n // NOTE: admin/ee/server overrides this controller, and adds the EE features\n // This returns an empty feature list for CE\n async getProjectType() {\n const flags = strapi.config.get('admin.flags', {});\n return { data: { isEE: false, features: [], flags, ai: { enabled: false } } };\n },\n\n async init() {\n let uuid = strapi.config.get('uuid', false);\n const hasAdmin = await getService('user').exists();\n const { menuLogo, authLogo } = await getService('project-settings').getProjectSettings();\n // set to null if telemetryDisabled flag not avaialble in package.json\n const telemetryDisabled: boolean | null = strapi.config.get(\n 'packageJsonStrapi.telemetryDisabled',\n null\n );\n\n if (telemetryDisabled !== null && telemetryDisabled === true) {\n uuid = false;\n }\n\n return {\n data: {\n uuid,\n hasAdmin,\n menuLogo: menuLogo ? menuLogo.url : null,\n authLogo: authLogo ? authLogo.url : null,\n },\n } satisfies Init.Response;\n },\n\n async getProjectSettings() {\n return getService(\n 'project-settings'\n ).getProjectSettings() satisfies Promise<GetProjectSettings.Response>;\n },\n\n async updateProjectSettings(ctx: Context) {\n const {\n request: { files, body },\n } = ctx as { request: UpdateProjectSettings.Request };\n\n const projectSettingsService = getService('project-settings');\n\n await validateUpdateProjectSettings(body);\n await validateUpdateProjectSettingsFiles(files);\n\n const formatedFiles = await projectSettingsService.parseFilesData(files);\n await validateUpdateProjectSettingsImagesDimensions(formatedFiles);\n\n return projectSettingsService.updateProjectSettings({\n ...body,\n ...formatedFiles,\n }) satisfies Promise<UpdateProjectSettings.Response>;\n },\n\n async telemetryProperties(ctx: Context) {\n // If the telemetry is disabled, ignore the request and return early\n if (strapi.telemetry.isDisabled) {\n ctx.status = 204;\n return;\n }\n\n const useTypescriptOnServer = await isUsingTypeScript(strapi.dirs.app.root);\n const useTypescriptOnAdmin = await isUsingTypeScript(\n path.join(strapi.dirs.app.root, 'src', 'admin')\n );\n const isHostedOnStrapiCloud = env('STRAPI_HOSTING', null) === 'strapi.cloud';\n\n const numberOfAllContentTypes = _.size(strapi.contentTypes);\n const numberOfComponents = _.size(strapi.components);\n\n const getNumberOfDynamicZones = () => {\n return pipe(\n map('attributes'),\n flatMap(values),\n // @ts-expect-error lodash types\n sumBy(propEq('type', 'dynamiczone'))\n )(strapi.contentTypes as any);\n };\n\n const getNumberOfFolders = async (): Promise<number> => {\n try {\n const contentStructure = strapi.get('content-structure') as\n | { countGroups?: () => Promise<number> }\n | undefined;\n\n return (await contentStructure?.countGroups?.()) ?? 0;\n } catch {\n return 0;\n }\n };\n\n return {\n data: {\n useTypescriptOnServer,\n useTypescriptOnAdmin,\n isHostedOnStrapiCloud,\n numberOfAllContentTypes, // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.\n numberOfComponents,\n numberOfDynamicZones: getNumberOfDynamicZones(),\n numberOfContentTypeFolders: await getNumberOfFolders(),\n },\n } satisfies TelemetryProperties.Response;\n },\n\n async information() {\n const currentEnvironment: string = strapi.config.get('environment');\n const autoReload = strapi.config.get('autoReload', false);\n const strapiVersion = strapi.config.get('info.strapi', null);\n const dependencies = strapi.config.get('info.dependencies', {});\n const projectId = strapi.config.get('uuid', null);\n const nodeVersion = process.version;\n const communityEdition = !strapi.EE;\n const useYarn: boolean = await exists(path.join(process.cwd(), 'yarn.lock'));\n\n return {\n data: {\n currentEnvironment,\n autoReload,\n strapiVersion,\n dependencies,\n projectId,\n nodeVersion,\n communityEdition,\n useYarn,\n },\n } satisfies Information.Response;\n },\n\n async plugins(ctx: Context) {\n const enabledPlugins = strapi.config.get('enabledPlugins') as any;\n\n // List of core plugins that are always enabled,\n // and so it's not necessary to display them in the plugins list\n const CORE_PLUGINS = [\n 'content-manager',\n 'content-type-builder',\n 'email',\n 'upload',\n 'i18n',\n 'content-releases',\n 'review-workflows',\n ];\n\n const plugins = Object.entries(enabledPlugins)\n .filter(([key]: any) => !CORE_PLUGINS.includes(key))\n .map(([key, plugin]: any) => ({\n name: plugin.info.name || key,\n displayName: plugin.info.displayName || plugin.info.name || key,\n description: plugin.info.description || '',\n packageName: plugin.info.packageName,\n }));\n\n ctx.send({ plugins } satisfies Plugins.Response);\n },\n\n async licenseTrialTimeLeft() {\n const data = await strapi.ee.getTrialEndDate({\n strapi,\n });\n\n return data;\n },\n\n async getGuidedTourMeta(ctx: Context) {\n const isFirstSuperAdminUser = await getService('user').isFirstSuperAdminUser(ctx.state.user.id);\n\n return {\n data: {\n isFirstSuperAdminUser,\n schemas: strapi.contentTypes,\n },\n } satisfies GetGuidedTourMeta.Response;\n },\n};\n"],"names":["lazyTsUtils","isUsingTypeScript","args","require","getProjectType","flags","strapi","config","get","data","isEE","features","ai","enabled","init","uuid","hasAdmin","getService","exists","menuLogo","authLogo","getProjectSettings","telemetryDisabled","url","updateProjectSettings","ctx","request","files","body","projectSettingsService","validateUpdateProjectSettings","validateUpdateProjectSettingsFiles","formatedFiles","parseFilesData","validateUpdateProjectSettingsImagesDimensions","telemetryProperties","telemetry","isDisabled","status","useTypescriptOnServer","dirs","app","root","useTypescriptOnAdmin","path","join","isHostedOnStrapiCloud","env","numberOfAllContentTypes","_","size","contentTypes","numberOfComponents","components","getNumberOfDynamicZones","pipe","map","flatMap","values","sumBy","propEq","getNumberOfFolders","contentStructure","countGroups","numberOfDynamicZones","numberOfContentTypeFolders","information","currentEnvironment","autoReload","strapiVersion","dependencies","projectId","nodeVersion","process","version","communityEdition","EE","useYarn","cwd","plugins","enabledPlugins","CORE_PLUGINS","Object","entries","filter","key","includes","plugin","name","info","displayName","description","packageName","send","licenseTrialTimeLeft","ee","getTrialEndDate","getGuidedTourMeta","isFirstSuperAdminUser","state","user","id","schemas"],"mappings":"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"}
1
+ {"version":3,"file":"admin.js","sources":["../../../../../server/src/controllers/admin.ts"],"sourcesContent":["import type { Context } from 'koa';\n\nimport path from 'path';\n\nimport { map, values, sumBy, pipe, flatMap, propEq } from 'lodash/fp';\nimport _ from 'lodash';\nimport { exists } from 'fs-extra';\nimport { env } from '@strapi/utils';\nimport {\n validateUpdateProjectSettings,\n validateUpdateProjectSettingsFiles,\n validateUpdateProjectSettingsImagesDimensions,\n} from '../validation/project-settings';\nimport { getService } from '../utils';\n\nimport type {\n Init,\n GetProjectSettings,\n GetProjectType,\n Information,\n Plugins,\n TelemetryProperties,\n UpdateProjectSettings,\n GetGuidedTourMeta,\n} from '../../../shared/contracts/admin';\n\n// Lazy: only resolved on first GET /admin/project-type request\ntype TsUtilsModule = typeof import('@strapi/typescript-utils');\nlet lazyTsUtils: TsUtilsModule | undefined;\nconst isUsingTypeScript: TsUtilsModule['isUsingTypeScript'] = (\n ...args: Parameters<TsUtilsModule['isUsingTypeScript']>\n) => {\n if (!lazyTsUtils) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n lazyTsUtils = require('@strapi/typescript-utils');\n }\n return (lazyTsUtils as TsUtilsModule).isUsingTypeScript(...args);\n};\n\n/**\n * A set of functions called \"actions\" for `Admin`\n */\nexport default {\n // TODO very temporary to check the switch ee/ce\n // When removing this we need to update the /admin/src/index.js file\n // whe,re we set the strapi.window.isEE value\n\n // NOTE: admin/ee/server overrides this controller, and adds the EE features\n // This returns an empty feature list for CE\n async getProjectType(): Promise<GetProjectType.Response> {\n const flags = strapi.config.get('admin.flags', {});\n return { data: { isEE: false, isTrial: false, features: [], flags, ai: { enabled: false } } };\n },\n\n async init() {\n let uuid = strapi.config.get('uuid', false);\n const hasAdmin = await getService('user').exists();\n const { menuLogo, authLogo } = await getService('project-settings').getProjectSettings();\n // set to null if telemetryDisabled flag not avaialble in package.json\n const telemetryDisabled: boolean | null = strapi.config.get(\n 'packageJsonStrapi.telemetryDisabled',\n null\n );\n\n if (telemetryDisabled !== null && telemetryDisabled === true) {\n uuid = false;\n }\n\n return {\n data: {\n uuid,\n hasAdmin,\n menuLogo: menuLogo ? menuLogo.url : null,\n authLogo: authLogo ? authLogo.url : null,\n },\n } satisfies Init.Response;\n },\n\n async getProjectSettings() {\n return getService(\n 'project-settings'\n ).getProjectSettings() satisfies Promise<GetProjectSettings.Response>;\n },\n\n async updateProjectSettings(ctx: Context) {\n const {\n request: { files, body },\n } = ctx as { request: UpdateProjectSettings.Request };\n\n const projectSettingsService = getService('project-settings');\n\n await validateUpdateProjectSettings(body);\n await validateUpdateProjectSettingsFiles(files);\n\n const formatedFiles = await projectSettingsService.parseFilesData(files);\n await validateUpdateProjectSettingsImagesDimensions(formatedFiles);\n\n return projectSettingsService.updateProjectSettings({\n ...body,\n ...formatedFiles,\n }) satisfies Promise<UpdateProjectSettings.Response>;\n },\n\n async telemetryProperties(ctx: Context) {\n // If the telemetry is disabled, ignore the request and return early\n if (strapi.telemetry.isDisabled) {\n ctx.status = 204;\n return;\n }\n\n const useTypescriptOnServer = await isUsingTypeScript(strapi.dirs.app.root);\n const useTypescriptOnAdmin = await isUsingTypeScript(\n path.join(strapi.dirs.app.root, 'src', 'admin')\n );\n const isHostedOnStrapiCloud = env('STRAPI_HOSTING', null) === 'strapi.cloud';\n\n const numberOfAllContentTypes = _.size(strapi.contentTypes);\n const numberOfComponents = _.size(strapi.components);\n\n const getNumberOfDynamicZones = () => {\n return pipe(\n map('attributes'),\n flatMap(values),\n // @ts-expect-error lodash types\n sumBy(propEq('type', 'dynamiczone'))\n )(strapi.contentTypes as any);\n };\n\n const getNumberOfFolders = async (): Promise<number> => {\n try {\n const contentStructure = strapi.get('content-structure') as\n | { countGroups?: () => Promise<number> }\n | undefined;\n\n return (await contentStructure?.countGroups?.()) ?? 0;\n } catch {\n return 0;\n }\n };\n\n return {\n data: {\n useTypescriptOnServer,\n useTypescriptOnAdmin,\n isHostedOnStrapiCloud,\n numberOfAllContentTypes, // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.\n numberOfComponents,\n numberOfDynamicZones: getNumberOfDynamicZones(),\n numberOfContentTypeFolders: await getNumberOfFolders(),\n },\n } satisfies TelemetryProperties.Response;\n },\n\n async information() {\n const currentEnvironment: string = strapi.config.get('environment');\n const autoReload = strapi.config.get('autoReload', false);\n const strapiVersion = strapi.config.get('info.strapi', null);\n const dependencies = strapi.config.get('info.dependencies', {});\n const projectId = strapi.config.get('uuid', null);\n const nodeVersion = process.version;\n const communityEdition = !strapi.EE;\n const useYarn: boolean = await exists(path.join(process.cwd(), 'yarn.lock'));\n\n return {\n data: {\n currentEnvironment,\n autoReload,\n strapiVersion,\n dependencies,\n projectId,\n nodeVersion,\n communityEdition,\n useYarn,\n },\n } satisfies Information.Response;\n },\n\n async plugins(ctx: Context) {\n const enabledPlugins = strapi.config.get('enabledPlugins') as any;\n\n // List of core plugins that are always enabled,\n // and so it's not necessary to display them in the plugins list\n const CORE_PLUGINS = [\n 'content-manager',\n 'content-type-builder',\n 'email',\n 'upload',\n 'i18n',\n 'content-releases',\n 'review-workflows',\n ];\n\n const plugins = Object.entries(enabledPlugins)\n .filter(([key]: any) => !CORE_PLUGINS.includes(key))\n .map(([key, plugin]: any) => ({\n name: plugin.info.name || key,\n displayName: plugin.info.displayName || plugin.info.name || key,\n description: plugin.info.description || '',\n packageName: plugin.info.packageName,\n }));\n\n ctx.send({ plugins } satisfies Plugins.Response);\n },\n\n async licenseTrialTimeLeft() {\n const data = await strapi.ee.getTrialEndDate({\n strapi,\n });\n\n return data;\n },\n\n async getGuidedTourMeta(ctx: Context) {\n const isFirstSuperAdminUser = await getService('user').isFirstSuperAdminUser(ctx.state.user.id);\n\n return {\n data: {\n isFirstSuperAdminUser,\n schemas: strapi.contentTypes,\n },\n } satisfies GetGuidedTourMeta.Response;\n },\n};\n"],"names":["lazyTsUtils","isUsingTypeScript","args","require","getProjectType","flags","strapi","config","get","data","isEE","isTrial","features","ai","enabled","init","uuid","hasAdmin","getService","exists","menuLogo","authLogo","getProjectSettings","telemetryDisabled","url","updateProjectSettings","ctx","request","files","body","projectSettingsService","validateUpdateProjectSettings","validateUpdateProjectSettingsFiles","formatedFiles","parseFilesData","validateUpdateProjectSettingsImagesDimensions","telemetryProperties","telemetry","isDisabled","status","useTypescriptOnServer","dirs","app","root","useTypescriptOnAdmin","path","join","isHostedOnStrapiCloud","env","numberOfAllContentTypes","_","size","contentTypes","numberOfComponents","components","getNumberOfDynamicZones","pipe","map","flatMap","values","sumBy","propEq","getNumberOfFolders","contentStructure","countGroups","numberOfDynamicZones","numberOfContentTypeFolders","information","currentEnvironment","autoReload","strapiVersion","dependencies","projectId","nodeVersion","process","version","communityEdition","EE","useYarn","cwd","plugins","enabledPlugins","CORE_PLUGINS","Object","entries","filter","key","includes","plugin","name","info","displayName","description","packageName","send","licenseTrialTimeLeft","ee","getTrialEndDate","getGuidedTourMeta","isFirstSuperAdminUser","state","user","id","schemas"],"mappings":";;;;;;;;;;;;;;;AA4BA,IAAIA,WAAAA;AACJ,MAAMC,iBAAAA,GAAwD,CAC5D,GAAGC,IAAAA,GAAAA;AAEH,IAAA,IAAI,CAACF,WAAAA,EAAa;;AAEhBA,QAAAA,WAAAA,GAAcG,OAAAA,CAAQ,0BAAA,CAAA;AACxB,IAAA;IACA,OAAQH,WAAAA,CAA8BC,iBAAiB,CAAA,GAAIC,IAAAA,CAAAA;AAC7D,CAAA;AAEA;;AAEC,IACD,YAAe;;;;;;IAOb,MAAME,cAAAA,CAAAA,GAAAA;AACJ,QAAA,MAAMC,QAAQC,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,eAAe,EAAC,CAAA;QAChD,OAAO;YAAEC,IAAAA,EAAM;gBAAEC,IAAAA,EAAM,KAAA;gBAAOC,OAAAA,EAAS,KAAA;AAAOC,gBAAAA,QAAAA,EAAU,EAAE;AAAEP,gBAAAA,KAAAA;gBAAOQ,EAAAA,EAAI;oBAAEC,OAAAA,EAAS;AAAM;AAAE;AAAE,SAAA;AAC9F,IAAA,CAAA;IAEA,MAAMC,IAAAA,CAAAA,GAAAA;AACJ,QAAA,IAAIC,OAAOV,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,MAAA,EAAQ,KAAA,CAAA;AACrC,QAAA,MAAMS,QAAAA,GAAW,MAAMC,gBAAAA,CAAW,MAAA,CAAA,CAAQC,MAAM,EAAA;QAChD,MAAM,EAAEC,QAAQ,EAAEC,QAAQ,EAAE,GAAG,MAAMH,gBAAAA,CAAW,kBAAA,CAAA,CAAoBI,kBAAkB,EAAA;;AAEtF,QAAA,MAAMC,oBAAoCjB,MAAAA,CAAOC,MAAM,CAACC,GAAG,CACzD,qCAAA,EACA,IAAA,CAAA;QAGF,IAAIe,iBAAAA,KAAsB,IAAA,IAAQA,iBAAAA,KAAsB,IAAA,EAAM;YAC5DP,IAAAA,GAAO,KAAA;AACT,QAAA;QAEA,OAAO;YACLP,IAAAA,EAAM;AACJO,gBAAAA,IAAAA;AACAC,gBAAAA,QAAAA;gBACAG,QAAAA,EAAUA,QAAAA,GAAWA,QAAAA,CAASI,GAAG,GAAG,IAAA;gBACpCH,QAAAA,EAAUA,QAAAA,GAAWA,QAAAA,CAASG,GAAG,GAAG;AACtC;AACF,SAAA;AACF,IAAA,CAAA;IAEA,MAAMF,kBAAAA,CAAAA,GAAAA;QACJ,OAAOJ,gBAAAA,CACL,oBACAI,kBAAkB,EAAA;AACtB,IAAA,CAAA;AAEA,IAAA,MAAMG,uBAAsBC,GAAY,EAAA;QACtC,MAAM,EACJC,SAAS,EAAEC,KAAK,EAAEC,IAAI,EAAE,EACzB,GAAGH,GAAAA;AAEJ,QAAA,MAAMI,yBAAyBZ,gBAAAA,CAAW,kBAAA,CAAA;AAE1C,QAAA,MAAMa,6CAAAA,CAA8BF,IAAAA,CAAAA;AACpC,QAAA,MAAMG,kDAAAA,CAAmCJ,KAAAA,CAAAA;AAEzC,QAAA,MAAMK,aAAAA,GAAgB,MAAMH,sBAAAA,CAAuBI,cAAc,CAACN,KAAAA,CAAAA;AAClE,QAAA,MAAMO,6DAAAA,CAA8CF,aAAAA,CAAAA;QAEpD,OAAOH,sBAAAA,CAAuBL,qBAAqB,CAAC;AAClD,YAAA,GAAGI,IAAI;AACP,YAAA,GAAGI;AACL,SAAA,CAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAMG,qBAAoBV,GAAY,EAAA;;AAEpC,QAAA,IAAIpB,MAAAA,CAAO+B,SAAS,CAACC,UAAU,EAAE;AAC/BZ,YAAAA,GAAAA,CAAIa,MAAM,GAAG,GAAA;AACb,YAAA;AACF,QAAA;QAEA,MAAMC,qBAAAA,GAAwB,MAAMvC,iBAAAA,CAAkBK,MAAAA,CAAOmC,IAAI,CAACC,GAAG,CAACC,IAAI,CAAA;AAC1E,QAAA,MAAMC,oBAAAA,GAAuB,MAAM3C,iBAAAA,CACjC4C,qBAAAA,CAAKC,IAAI,CAACxC,MAAAA,CAAOmC,IAAI,CAACC,GAAG,CAACC,IAAI,EAAE,KAAA,EAAO,OAAA,CAAA,CAAA;QAEzC,MAAMI,qBAAAA,GAAwBC,SAAAA,CAAI,gBAAA,EAAkB,IAAA,CAAA,KAAU,cAAA;AAE9D,QAAA,MAAMC,uBAAAA,GAA0BC,kBAAAA,CAAEC,IAAI,CAAC7C,OAAO8C,YAAY,CAAA;AAC1D,QAAA,MAAMC,kBAAAA,GAAqBH,kBAAAA,CAAEC,IAAI,CAAC7C,OAAOgD,UAAU,CAAA;AAEnD,QAAA,MAAMC,uBAAAA,GAA0B,IAAA;AAC9B,YAAA,OAAOC,OAAAA,CACLC,MAAAA,CAAI,YAAA,CAAA,EACJC,UAAAA,CAAQC;AAERC,YAAAA,QAAAA,CAAMC,SAAAA,CAAO,MAAA,EAAQ,aAAA,CAAA,CAAA,CAAA,CACrBvD,MAAAA,CAAO8C,YAAY,CAAA;AACvB,QAAA,CAAA;AAEA,QAAA,MAAMU,kBAAAA,GAAqB,UAAA;YACzB,IAAI;gBACF,MAAMC,gBAAAA,GAAmBzD,MAAAA,CAAOE,GAAG,CAAC,mBAAA,CAAA;gBAIpC,OAAQ,MAAMuD,gBAAAA,EAAkBC,WAAAA,IAAAA,IAAoB,CAAA;AACtD,YAAA,CAAA,CAAE,OAAM;gBACN,OAAO,CAAA;AACT,YAAA;AACF,QAAA,CAAA;QAEA,OAAO;YACLvD,IAAAA,EAAM;AACJ+B,gBAAAA,qBAAAA;AACAI,gBAAAA,oBAAAA;AACAG,gBAAAA,qBAAAA;AACAE,gBAAAA,uBAAAA;AACAI,gBAAAA,kBAAAA;gBACAY,oBAAAA,EAAsBV,uBAAAA,EAAAA;AACtBW,gBAAAA,0BAAAA,EAA4B,MAAMJ,kBAAAA;AACpC;AACF,SAAA;AACF,IAAA,CAAA;IAEA,MAAMK,WAAAA,CAAAA,GAAAA;AACJ,QAAA,MAAMC,kBAAAA,GAA6B9D,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,aAAA,CAAA;AACrD,QAAA,MAAM6D,aAAa/D,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,YAAA,EAAc,KAAA,CAAA;AACnD,QAAA,MAAM8D,gBAAgBhE,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,aAAA,EAAe,IAAA,CAAA;AACvD,QAAA,MAAM+D,eAAejE,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,qBAAqB,EAAC,CAAA;AAC7D,QAAA,MAAMgE,YAAYlE,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,MAAA,EAAQ,IAAA,CAAA;QAC5C,MAAMiE,WAAAA,GAAcC,QAAQC,OAAO;QACnC,MAAMC,gBAAAA,GAAmB,CAACtE,MAAAA,CAAOuE,EAAE;QACnC,MAAMC,OAAAA,GAAmB,MAAM3D,UAAAA,CAAO0B,qBAAAA,CAAKC,IAAI,CAAC4B,OAAAA,CAAQK,GAAG,EAAA,EAAI,WAAA,CAAA,CAAA;QAE/D,OAAO;YACLtE,IAAAA,EAAM;AACJ2D,gBAAAA,kBAAAA;AACAC,gBAAAA,UAAAA;AACAC,gBAAAA,aAAAA;AACAC,gBAAAA,YAAAA;AACAC,gBAAAA,SAAAA;AACAC,gBAAAA,WAAAA;AACAG,gBAAAA,gBAAAA;AACAE,gBAAAA;AACF;AACF,SAAA;AACF,IAAA,CAAA;AAEA,IAAA,MAAME,SAAQtD,GAAY,EAAA;AACxB,QAAA,MAAMuD,cAAAA,GAAiB3E,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,gBAAA,CAAA;;;AAIzC,QAAA,MAAM0E,YAAAA,GAAe;AACnB,YAAA,iBAAA;AACA,YAAA,sBAAA;AACA,YAAA,OAAA;AACA,YAAA,QAAA;AACA,YAAA,MAAA;AACA,YAAA,kBAAA;AACA,YAAA;AACD,SAAA;QAED,MAAMF,OAAAA,GAAUG,OAAOC,OAAO,CAACH,gBAC5BI,MAAM,CAAC,CAAC,CAACC,GAAAA,CAAS,GAAK,CAACJ,YAAAA,CAAaK,QAAQ,CAACD,GAAAA,CAAAA,CAAAA,CAC9C7B,GAAG,CAAC,CAAC,CAAC6B,GAAAA,EAAKE,MAAAA,CAAY,IAAM;AAC5BC,gBAAAA,IAAAA,EAAMD,MAAAA,CAAOE,IAAI,CAACD,IAAI,IAAIH,GAAAA;gBAC1BK,WAAAA,EAAaH,MAAAA,CAAOE,IAAI,CAACC,WAAW,IAAIH,MAAAA,CAAOE,IAAI,CAACD,IAAI,IAAIH,GAAAA;AAC5DM,gBAAAA,WAAAA,EAAaJ,MAAAA,CAAOE,IAAI,CAACE,WAAW,IAAI,EAAA;gBACxCC,WAAAA,EAAaL,MAAAA,CAAOE,IAAI,CAACG;aAC3B,CAAA,CAAA;AAEFnE,QAAAA,GAAAA,CAAIoE,IAAI,CAAC;AAAEd,YAAAA;AAAQ,SAAA,CAAA;AACrB,IAAA,CAAA;IAEA,MAAMe,oBAAAA,CAAAA,GAAAA;AACJ,QAAA,MAAMtF,OAAO,MAAMH,MAAAA,CAAO0F,EAAE,CAACC,eAAe,CAAC;AAC3C3F,YAAAA;AACF,SAAA,CAAA;QAEA,OAAOG,IAAAA;AACT,IAAA,CAAA;AAEA,IAAA,MAAMyF,mBAAkBxE,GAAY,EAAA;QAClC,MAAMyE,qBAAAA,GAAwB,MAAMjF,gBAAAA,CAAW,MAAA,CAAA,CAAQiF,qBAAqB,CAACzE,GAAAA,CAAI0E,KAAK,CAACC,IAAI,CAACC,EAAE,CAAA;QAE9F,OAAO;YACL7F,IAAAA,EAAM;AACJ0F,gBAAAA,qBAAAA;AACAI,gBAAAA,OAAAA,EAASjG,OAAO8C;AAClB;AACF,SAAA;AACF,IAAA;AACF,CAAA;;;;"}
@@ -27,6 +27,7 @@ const isUsingTypeScript = (...args)=>{
27
27
  return {
28
28
  data: {
29
29
  isEE: false,
30
+ isTrial: false,
30
31
  features: [],
31
32
  flags,
32
33
  ai: {
@@ -1 +1 @@
1
- {"version":3,"file":"admin.mjs","sources":["../../../../../server/src/controllers/admin.ts"],"sourcesContent":["import type { Context } from 'koa';\n\nimport path from 'path';\n\nimport { map, values, sumBy, pipe, flatMap, propEq } from 'lodash/fp';\nimport _ from 'lodash';\nimport { exists } from 'fs-extra';\nimport { env } from '@strapi/utils';\nimport {\n validateUpdateProjectSettings,\n validateUpdateProjectSettingsFiles,\n validateUpdateProjectSettingsImagesDimensions,\n} from '../validation/project-settings';\nimport { getService } from '../utils';\n\nimport type {\n Init,\n GetProjectSettings,\n Information,\n Plugins,\n TelemetryProperties,\n UpdateProjectSettings,\n GetGuidedTourMeta,\n} from '../../../shared/contracts/admin';\n\n// Lazy: only resolved on first GET /admin/project-type request\ntype TsUtilsModule = typeof import('@strapi/typescript-utils');\nlet lazyTsUtils: TsUtilsModule | undefined;\nconst isUsingTypeScript: TsUtilsModule['isUsingTypeScript'] = (\n ...args: Parameters<TsUtilsModule['isUsingTypeScript']>\n) => {\n if (!lazyTsUtils) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n lazyTsUtils = require('@strapi/typescript-utils');\n }\n return (lazyTsUtils as TsUtilsModule).isUsingTypeScript(...args);\n};\n\n/**\n * A set of functions called \"actions\" for `Admin`\n */\nexport default {\n // TODO very temporary to check the switch ee/ce\n // When removing this we need to update the /admin/src/index.js file\n // whe,re we set the strapi.window.isEE value\n\n // NOTE: admin/ee/server overrides this controller, and adds the EE features\n // This returns an empty feature list for CE\n async getProjectType() {\n const flags = strapi.config.get('admin.flags', {});\n return { data: { isEE: false, features: [], flags, ai: { enabled: false } } };\n },\n\n async init() {\n let uuid = strapi.config.get('uuid', false);\n const hasAdmin = await getService('user').exists();\n const { menuLogo, authLogo } = await getService('project-settings').getProjectSettings();\n // set to null if telemetryDisabled flag not avaialble in package.json\n const telemetryDisabled: boolean | null = strapi.config.get(\n 'packageJsonStrapi.telemetryDisabled',\n null\n );\n\n if (telemetryDisabled !== null && telemetryDisabled === true) {\n uuid = false;\n }\n\n return {\n data: {\n uuid,\n hasAdmin,\n menuLogo: menuLogo ? menuLogo.url : null,\n authLogo: authLogo ? authLogo.url : null,\n },\n } satisfies Init.Response;\n },\n\n async getProjectSettings() {\n return getService(\n 'project-settings'\n ).getProjectSettings() satisfies Promise<GetProjectSettings.Response>;\n },\n\n async updateProjectSettings(ctx: Context) {\n const {\n request: { files, body },\n } = ctx as { request: UpdateProjectSettings.Request };\n\n const projectSettingsService = getService('project-settings');\n\n await validateUpdateProjectSettings(body);\n await validateUpdateProjectSettingsFiles(files);\n\n const formatedFiles = await projectSettingsService.parseFilesData(files);\n await validateUpdateProjectSettingsImagesDimensions(formatedFiles);\n\n return projectSettingsService.updateProjectSettings({\n ...body,\n ...formatedFiles,\n }) satisfies Promise<UpdateProjectSettings.Response>;\n },\n\n async telemetryProperties(ctx: Context) {\n // If the telemetry is disabled, ignore the request and return early\n if (strapi.telemetry.isDisabled) {\n ctx.status = 204;\n return;\n }\n\n const useTypescriptOnServer = await isUsingTypeScript(strapi.dirs.app.root);\n const useTypescriptOnAdmin = await isUsingTypeScript(\n path.join(strapi.dirs.app.root, 'src', 'admin')\n );\n const isHostedOnStrapiCloud = env('STRAPI_HOSTING', null) === 'strapi.cloud';\n\n const numberOfAllContentTypes = _.size(strapi.contentTypes);\n const numberOfComponents = _.size(strapi.components);\n\n const getNumberOfDynamicZones = () => {\n return pipe(\n map('attributes'),\n flatMap(values),\n // @ts-expect-error lodash types\n sumBy(propEq('type', 'dynamiczone'))\n )(strapi.contentTypes as any);\n };\n\n const getNumberOfFolders = async (): Promise<number> => {\n try {\n const contentStructure = strapi.get('content-structure') as\n | { countGroups?: () => Promise<number> }\n | undefined;\n\n return (await contentStructure?.countGroups?.()) ?? 0;\n } catch {\n return 0;\n }\n };\n\n return {\n data: {\n useTypescriptOnServer,\n useTypescriptOnAdmin,\n isHostedOnStrapiCloud,\n numberOfAllContentTypes, // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.\n numberOfComponents,\n numberOfDynamicZones: getNumberOfDynamicZones(),\n numberOfContentTypeFolders: await getNumberOfFolders(),\n },\n } satisfies TelemetryProperties.Response;\n },\n\n async information() {\n const currentEnvironment: string = strapi.config.get('environment');\n const autoReload = strapi.config.get('autoReload', false);\n const strapiVersion = strapi.config.get('info.strapi', null);\n const dependencies = strapi.config.get('info.dependencies', {});\n const projectId = strapi.config.get('uuid', null);\n const nodeVersion = process.version;\n const communityEdition = !strapi.EE;\n const useYarn: boolean = await exists(path.join(process.cwd(), 'yarn.lock'));\n\n return {\n data: {\n currentEnvironment,\n autoReload,\n strapiVersion,\n dependencies,\n projectId,\n nodeVersion,\n communityEdition,\n useYarn,\n },\n } satisfies Information.Response;\n },\n\n async plugins(ctx: Context) {\n const enabledPlugins = strapi.config.get('enabledPlugins') as any;\n\n // List of core plugins that are always enabled,\n // and so it's not necessary to display them in the plugins list\n const CORE_PLUGINS = [\n 'content-manager',\n 'content-type-builder',\n 'email',\n 'upload',\n 'i18n',\n 'content-releases',\n 'review-workflows',\n ];\n\n const plugins = Object.entries(enabledPlugins)\n .filter(([key]: any) => !CORE_PLUGINS.includes(key))\n .map(([key, plugin]: any) => ({\n name: plugin.info.name || key,\n displayName: plugin.info.displayName || plugin.info.name || key,\n description: plugin.info.description || '',\n packageName: plugin.info.packageName,\n }));\n\n ctx.send({ plugins } satisfies Plugins.Response);\n },\n\n async licenseTrialTimeLeft() {\n const data = await strapi.ee.getTrialEndDate({\n strapi,\n });\n\n return data;\n },\n\n async getGuidedTourMeta(ctx: Context) {\n const isFirstSuperAdminUser = await getService('user').isFirstSuperAdminUser(ctx.state.user.id);\n\n return {\n data: {\n isFirstSuperAdminUser,\n schemas: strapi.contentTypes,\n },\n } satisfies GetGuidedTourMeta.Response;\n },\n};\n"],"names":["lazyTsUtils","isUsingTypeScript","args","require","getProjectType","flags","strapi","config","get","data","isEE","features","ai","enabled","init","uuid","hasAdmin","getService","exists","menuLogo","authLogo","getProjectSettings","telemetryDisabled","url","updateProjectSettings","ctx","request","files","body","projectSettingsService","validateUpdateProjectSettings","validateUpdateProjectSettingsFiles","formatedFiles","parseFilesData","validateUpdateProjectSettingsImagesDimensions","telemetryProperties","telemetry","isDisabled","status","useTypescriptOnServer","dirs","app","root","useTypescriptOnAdmin","path","join","isHostedOnStrapiCloud","env","numberOfAllContentTypes","_","size","contentTypes","numberOfComponents","components","getNumberOfDynamicZones","pipe","map","flatMap","values","sumBy","propEq","getNumberOfFolders","contentStructure","countGroups","numberOfDynamicZones","numberOfContentTypeFolders","information","currentEnvironment","autoReload","strapiVersion","dependencies","projectId","nodeVersion","process","version","communityEdition","EE","useYarn","cwd","plugins","enabledPlugins","CORE_PLUGINS","Object","entries","filter","key","includes","plugin","name","info","displayName","description","packageName","send","licenseTrialTimeLeft","ee","getTrialEndDate","getGuidedTourMeta","isFirstSuperAdminUser","state","user","id","schemas"],"mappings":"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"}
1
+ {"version":3,"file":"admin.mjs","sources":["../../../../../server/src/controllers/admin.ts"],"sourcesContent":["import type { Context } from 'koa';\n\nimport path from 'path';\n\nimport { map, values, sumBy, pipe, flatMap, propEq } from 'lodash/fp';\nimport _ from 'lodash';\nimport { exists } from 'fs-extra';\nimport { env } from '@strapi/utils';\nimport {\n validateUpdateProjectSettings,\n validateUpdateProjectSettingsFiles,\n validateUpdateProjectSettingsImagesDimensions,\n} from '../validation/project-settings';\nimport { getService } from '../utils';\n\nimport type {\n Init,\n GetProjectSettings,\n GetProjectType,\n Information,\n Plugins,\n TelemetryProperties,\n UpdateProjectSettings,\n GetGuidedTourMeta,\n} from '../../../shared/contracts/admin';\n\n// Lazy: only resolved on first GET /admin/project-type request\ntype TsUtilsModule = typeof import('@strapi/typescript-utils');\nlet lazyTsUtils: TsUtilsModule | undefined;\nconst isUsingTypeScript: TsUtilsModule['isUsingTypeScript'] = (\n ...args: Parameters<TsUtilsModule['isUsingTypeScript']>\n) => {\n if (!lazyTsUtils) {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n lazyTsUtils = require('@strapi/typescript-utils');\n }\n return (lazyTsUtils as TsUtilsModule).isUsingTypeScript(...args);\n};\n\n/**\n * A set of functions called \"actions\" for `Admin`\n */\nexport default {\n // TODO very temporary to check the switch ee/ce\n // When removing this we need to update the /admin/src/index.js file\n // whe,re we set the strapi.window.isEE value\n\n // NOTE: admin/ee/server overrides this controller, and adds the EE features\n // This returns an empty feature list for CE\n async getProjectType(): Promise<GetProjectType.Response> {\n const flags = strapi.config.get('admin.flags', {});\n return { data: { isEE: false, isTrial: false, features: [], flags, ai: { enabled: false } } };\n },\n\n async init() {\n let uuid = strapi.config.get('uuid', false);\n const hasAdmin = await getService('user').exists();\n const { menuLogo, authLogo } = await getService('project-settings').getProjectSettings();\n // set to null if telemetryDisabled flag not avaialble in package.json\n const telemetryDisabled: boolean | null = strapi.config.get(\n 'packageJsonStrapi.telemetryDisabled',\n null\n );\n\n if (telemetryDisabled !== null && telemetryDisabled === true) {\n uuid = false;\n }\n\n return {\n data: {\n uuid,\n hasAdmin,\n menuLogo: menuLogo ? menuLogo.url : null,\n authLogo: authLogo ? authLogo.url : null,\n },\n } satisfies Init.Response;\n },\n\n async getProjectSettings() {\n return getService(\n 'project-settings'\n ).getProjectSettings() satisfies Promise<GetProjectSettings.Response>;\n },\n\n async updateProjectSettings(ctx: Context) {\n const {\n request: { files, body },\n } = ctx as { request: UpdateProjectSettings.Request };\n\n const projectSettingsService = getService('project-settings');\n\n await validateUpdateProjectSettings(body);\n await validateUpdateProjectSettingsFiles(files);\n\n const formatedFiles = await projectSettingsService.parseFilesData(files);\n await validateUpdateProjectSettingsImagesDimensions(formatedFiles);\n\n return projectSettingsService.updateProjectSettings({\n ...body,\n ...formatedFiles,\n }) satisfies Promise<UpdateProjectSettings.Response>;\n },\n\n async telemetryProperties(ctx: Context) {\n // If the telemetry is disabled, ignore the request and return early\n if (strapi.telemetry.isDisabled) {\n ctx.status = 204;\n return;\n }\n\n const useTypescriptOnServer = await isUsingTypeScript(strapi.dirs.app.root);\n const useTypescriptOnAdmin = await isUsingTypeScript(\n path.join(strapi.dirs.app.root, 'src', 'admin')\n );\n const isHostedOnStrapiCloud = env('STRAPI_HOSTING', null) === 'strapi.cloud';\n\n const numberOfAllContentTypes = _.size(strapi.contentTypes);\n const numberOfComponents = _.size(strapi.components);\n\n const getNumberOfDynamicZones = () => {\n return pipe(\n map('attributes'),\n flatMap(values),\n // @ts-expect-error lodash types\n sumBy(propEq('type', 'dynamiczone'))\n )(strapi.contentTypes as any);\n };\n\n const getNumberOfFolders = async (): Promise<number> => {\n try {\n const contentStructure = strapi.get('content-structure') as\n | { countGroups?: () => Promise<number> }\n | undefined;\n\n return (await contentStructure?.countGroups?.()) ?? 0;\n } catch {\n return 0;\n }\n };\n\n return {\n data: {\n useTypescriptOnServer,\n useTypescriptOnAdmin,\n isHostedOnStrapiCloud,\n numberOfAllContentTypes, // TODO: V5: This event should be renamed numberOfContentTypes in V5 as the name is already taken to describe the number of content types using i18n.\n numberOfComponents,\n numberOfDynamicZones: getNumberOfDynamicZones(),\n numberOfContentTypeFolders: await getNumberOfFolders(),\n },\n } satisfies TelemetryProperties.Response;\n },\n\n async information() {\n const currentEnvironment: string = strapi.config.get('environment');\n const autoReload = strapi.config.get('autoReload', false);\n const strapiVersion = strapi.config.get('info.strapi', null);\n const dependencies = strapi.config.get('info.dependencies', {});\n const projectId = strapi.config.get('uuid', null);\n const nodeVersion = process.version;\n const communityEdition = !strapi.EE;\n const useYarn: boolean = await exists(path.join(process.cwd(), 'yarn.lock'));\n\n return {\n data: {\n currentEnvironment,\n autoReload,\n strapiVersion,\n dependencies,\n projectId,\n nodeVersion,\n communityEdition,\n useYarn,\n },\n } satisfies Information.Response;\n },\n\n async plugins(ctx: Context) {\n const enabledPlugins = strapi.config.get('enabledPlugins') as any;\n\n // List of core plugins that are always enabled,\n // and so it's not necessary to display them in the plugins list\n const CORE_PLUGINS = [\n 'content-manager',\n 'content-type-builder',\n 'email',\n 'upload',\n 'i18n',\n 'content-releases',\n 'review-workflows',\n ];\n\n const plugins = Object.entries(enabledPlugins)\n .filter(([key]: any) => !CORE_PLUGINS.includes(key))\n .map(([key, plugin]: any) => ({\n name: plugin.info.name || key,\n displayName: plugin.info.displayName || plugin.info.name || key,\n description: plugin.info.description || '',\n packageName: plugin.info.packageName,\n }));\n\n ctx.send({ plugins } satisfies Plugins.Response);\n },\n\n async licenseTrialTimeLeft() {\n const data = await strapi.ee.getTrialEndDate({\n strapi,\n });\n\n return data;\n },\n\n async getGuidedTourMeta(ctx: Context) {\n const isFirstSuperAdminUser = await getService('user').isFirstSuperAdminUser(ctx.state.user.id);\n\n return {\n data: {\n isFirstSuperAdminUser,\n schemas: strapi.contentTypes,\n },\n } satisfies GetGuidedTourMeta.Response;\n },\n};\n"],"names":["lazyTsUtils","isUsingTypeScript","args","require","getProjectType","flags","strapi","config","get","data","isEE","isTrial","features","ai","enabled","init","uuid","hasAdmin","getService","exists","menuLogo","authLogo","getProjectSettings","telemetryDisabled","url","updateProjectSettings","ctx","request","files","body","projectSettingsService","validateUpdateProjectSettings","validateUpdateProjectSettingsFiles","formatedFiles","parseFilesData","validateUpdateProjectSettingsImagesDimensions","telemetryProperties","telemetry","isDisabled","status","useTypescriptOnServer","dirs","app","root","useTypescriptOnAdmin","path","join","isHostedOnStrapiCloud","env","numberOfAllContentTypes","_","size","contentTypes","numberOfComponents","components","getNumberOfDynamicZones","pipe","map","flatMap","values","sumBy","propEq","getNumberOfFolders","contentStructure","countGroups","numberOfDynamicZones","numberOfContentTypeFolders","information","currentEnvironment","autoReload","strapiVersion","dependencies","projectId","nodeVersion","process","version","communityEdition","EE","useYarn","cwd","plugins","enabledPlugins","CORE_PLUGINS","Object","entries","filter","key","includes","plugin","name","info","displayName","description","packageName","send","licenseTrialTimeLeft","ee","getTrialEndDate","getGuidedTourMeta","isFirstSuperAdminUser","state","user","id","schemas"],"mappings":"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"}
@@ -172,7 +172,14 @@ var authentication = {
172
172
  async forgotPassword (ctx) {
173
173
  const input = ctx.request.body;
174
174
  await forgotPassword(input);
175
- index.getService('auth').forgotPassword(input);
175
+ // Not awaited: the response must not reveal whether the email exists. The call runs
176
+ // synchronously so a broken service still surfaces as a 500; only a rejection of the
177
+ // returned promise is caught here, since nothing else would handle it.
178
+ Promise.resolve(index.getService('auth').forgotPassword(input)).catch((error)=>{
179
+ strapi.log.error('Failed to process the forgot-password request', {
180
+ error
181
+ });
182
+ });
176
183
  ctx.status = 204;
177
184
  },
178
185
  async resetPassword (ctx) {
@@ -1 +1 @@
1
- {"version":3,"file":"authentication.js","sources":["../../../../../server/src/controllers/authentication.ts"],"sourcesContent":["import type { Context, Next } from 'koa';\nimport passport from 'koa-passport';\nimport compose from 'koa-compose';\nimport '@strapi/types';\nimport { errors } from '@strapi/utils';\nimport { getService } from '../utils';\nimport {\n REFRESH_COOKIE_NAME,\n buildCookieOptionsWithExpiry,\n buildSessionMetadataFromContext,\n getSessionManager,\n extractDeviceParams,\n generateDeviceId,\n getRefreshCookieOptions,\n resolveLogoutDeviceId,\n} from '../../../shared/utils/session-auth';\n\nimport {\n validateRegistrationInput,\n validateAdminRegistrationInput,\n validateRegistrationInfoQuery,\n validateForgotPasswordInput,\n validateResetPasswordInput,\n validateLoginSessionInput,\n} from '../validation/authentication';\n\nimport type {\n ForgotPassword,\n Login,\n Register,\n RegisterAdmin,\n RegistrationInfo,\n ResetPassword,\n} from '../../../shared/contracts/authentication';\nimport { AdminUser } from '../../../shared/contracts/shared';\n\nconst { ApplicationError, ValidationError } = errors;\n\nexport default {\n login: compose([\n async (ctx: Context, next: Next) => {\n await validateLoginSessionInput(ctx.request.body ?? {});\n return next();\n },\n (ctx: Context, next: Next) => {\n return passport.authenticate('local', { session: false }, (err, user, info) => {\n if (err) {\n strapi.eventHub.emit('admin.auth.error', { error: err, provider: 'local' });\n // if this is a recognized error, allow it to bubble up to user\n if (err.details?.code === 'LOGIN_NOT_ALLOWED') {\n throw err;\n }\n\n // for all other errors throw a generic error to prevent leaking info\n return ctx.notImplemented();\n }\n\n if (!user) {\n strapi.eventHub.emit('admin.auth.error', {\n error: new Error(info.message),\n provider: 'local',\n });\n throw new ApplicationError(info.message);\n }\n\n const query = ctx.state as Login.Request['query'];\n query.user = user;\n\n const sanitizedUser = getService('user').sanitizeUser(user);\n strapi.eventHub.emit('admin.auth.success', { user: sanitizedUser, provider: 'local' });\n\n return next();\n })(ctx, next);\n },\n async (ctx: Context) => {\n const { user } = ctx.state as { user: AdminUser };\n\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n const userId = String(user.id);\n const { deviceId, rememberMe } = extractDeviceParams(ctx.request.body);\n\n const { token: refreshToken, absoluteExpiresAt } = await sessionManager(\n 'admin'\n ).generateRefreshToken(userId, deviceId, {\n type: rememberMe ? 'refresh' : 'session',\n metadata: buildSessionMetadataFromContext(ctx),\n });\n\n const cookieOptions = buildCookieOptionsWithExpiry(\n rememberMe ? 'refresh' : 'session',\n absoluteExpiresAt,\n ctx.request.secure\n );\n ctx.cookies.set(REFRESH_COOKIE_NAME, refreshToken, cookieOptions);\n\n const accessResult = await sessionManager('admin').generateAccessToken(refreshToken);\n if ('error' in accessResult) {\n return ctx.internalServerError();\n }\n\n const { token: accessToken } = accessResult;\n\n ctx.body = {\n data: {\n token: accessToken,\n accessToken,\n user: getService('user').sanitizeUser(ctx.state.user),\n },\n } satisfies Login.Response;\n } catch (error) {\n strapi.log.error('Failed to create admin refresh session', error);\n return ctx.internalServerError();\n }\n },\n ]),\n\n async registrationInfo(ctx: Context) {\n await validateRegistrationInfoQuery(ctx.request.query);\n\n const { registrationToken } = ctx.request.query as RegistrationInfo.Request['query'];\n\n const registrationInfo = await getService('user').findRegistrationInfo(registrationToken);\n\n if (!registrationInfo) {\n throw new ValidationError('Invalid registrationToken');\n }\n\n ctx.body = { data: registrationInfo } satisfies RegistrationInfo.Response;\n },\n\n async register(ctx: Context) {\n const input = ctx.request.body as Register.Request['body'];\n\n await validateRegistrationInput(input);\n\n const user = await getService('user').register(input);\n\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n const userId = String(user.id);\n const { deviceId, rememberMe } = extractDeviceParams(ctx.request.body);\n\n const { token: refreshToken, absoluteExpiresAt } = await sessionManager(\n 'admin'\n ).generateRefreshToken(userId, deviceId, {\n type: rememberMe ? 'refresh' : 'session',\n metadata: buildSessionMetadataFromContext(ctx),\n });\n\n const cookieOptions = buildCookieOptionsWithExpiry(\n rememberMe ? 'refresh' : 'session',\n absoluteExpiresAt,\n ctx.request.secure\n );\n ctx.cookies.set(REFRESH_COOKIE_NAME, refreshToken, cookieOptions);\n\n const accessResult = await sessionManager('admin').generateAccessToken(refreshToken);\n if ('error' in accessResult) {\n return ctx.internalServerError();\n }\n\n const { token: accessToken } = accessResult;\n\n ctx.body = {\n data: {\n token: accessToken,\n accessToken,\n user: getService('user').sanitizeUser(user),\n },\n } satisfies Register.Response;\n } catch (error) {\n strapi.log.error('Failed to create admin refresh session during register', error);\n return ctx.internalServerError();\n }\n },\n\n async registerAdmin(ctx: Context) {\n const input = ctx.request.body as RegisterAdmin.Request['body'];\n\n await validateAdminRegistrationInput(input);\n\n const user = await getService('user').createFirstAdmin(input);\n\n strapi.telemetry.send('didCreateFirstAdmin');\n\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n const userId = String(user.id);\n const { deviceId, rememberMe } = extractDeviceParams(ctx.request.body);\n\n const { token: refreshToken, absoluteExpiresAt } = await sessionManager(\n 'admin'\n ).generateRefreshToken(userId, deviceId, {\n type: rememberMe ? 'refresh' : 'session',\n metadata: buildSessionMetadataFromContext(ctx),\n });\n\n const cookieOptions = buildCookieOptionsWithExpiry(\n rememberMe ? 'refresh' : 'session',\n absoluteExpiresAt,\n ctx.request.secure\n );\n ctx.cookies.set(REFRESH_COOKIE_NAME, refreshToken, cookieOptions);\n\n const accessResult = await sessionManager('admin').generateAccessToken(refreshToken);\n if ('error' in accessResult) {\n return ctx.internalServerError();\n }\n\n const { token: accessToken } = accessResult;\n\n ctx.body = {\n data: {\n token: accessToken,\n accessToken,\n user: getService('user').sanitizeUser(user),\n },\n } satisfies RegisterAdmin.Response;\n } catch (error) {\n strapi.log.error('Failed to create admin refresh session during register-admin', error);\n return ctx.internalServerError();\n }\n },\n\n async forgotPassword(ctx: Context) {\n const input = ctx.request.body as ForgotPassword.Request['body'];\n\n await validateForgotPasswordInput(input);\n\n getService('auth').forgotPassword(input);\n\n ctx.status = 204;\n },\n\n async resetPassword(ctx: Context) {\n const input = ctx.request.body as ResetPassword.Request['body'];\n\n await validateResetPasswordInput(input);\n\n const user = await getService('auth').resetPassword(input);\n\n // Issue a new admin refresh session and access token after password reset.\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n\n const userId = String(user.id);\n const deviceId = generateDeviceId();\n\n // Invalidate all existing sessions before creating a new one\n await sessionManager('admin').invalidateRefreshToken(userId);\n\n const { token: refreshToken, absoluteExpiresAt } = await sessionManager(\n 'admin'\n ).generateRefreshToken(userId, deviceId, {\n type: 'session',\n metadata: buildSessionMetadataFromContext(ctx),\n });\n\n // No rememberMe flow here; expire with session by default (session cookie)\n const cookieOptions = buildCookieOptionsWithExpiry(\n 'session',\n absoluteExpiresAt,\n ctx.request.secure\n );\n ctx.cookies.set(REFRESH_COOKIE_NAME, refreshToken, cookieOptions);\n\n const accessResult = await sessionManager('admin').generateAccessToken(refreshToken);\n if ('error' in accessResult) {\n return ctx.internalServerError();\n }\n\n const { token } = accessResult;\n\n ctx.body = {\n data: {\n token,\n user: getService('user').sanitizeUser(user),\n },\n } satisfies ResetPassword.Response;\n } catch (err) {\n strapi.log.error('Failed to create admin refresh session during reset-password', err as any);\n return ctx.internalServerError();\n }\n },\n\n async accessToken(ctx: Context) {\n const refreshToken = ctx.cookies.get(REFRESH_COOKIE_NAME);\n\n if (!refreshToken) {\n return ctx.unauthorized('Missing refresh token');\n }\n\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n\n // Single-use renewal: rotate on access exchange, then create access token\n // from the new refresh token\n const rotation = await sessionManager('admin').rotateRefreshToken(refreshToken);\n if ('error' in rotation) {\n return ctx.unauthorized('Invalid refresh token');\n }\n\n const result = await sessionManager('admin').generateAccessToken(rotation.token);\n if ('error' in result) {\n return ctx.unauthorized('Invalid refresh token');\n }\n\n const { token } = result;\n // Preserve session-vs-remember mode using rotation.type and rotation.absoluteExpiresAt\n const opts = buildCookieOptionsWithExpiry(\n rotation.type,\n rotation.absoluteExpiresAt,\n ctx.request.secure\n );\n\n ctx.cookies.set(REFRESH_COOKIE_NAME, rotation.token, opts);\n ctx.body = { data: { token } };\n } catch (err) {\n strapi.log.error('Failed to generate access token from refresh token', err as any);\n return ctx.internalServerError();\n }\n },\n\n async logout(ctx: Context) {\n const sanitizedUser = getService('user').sanitizeUser(ctx.state.user);\n strapi.eventHub.emit('admin.logout', { user: sanitizedUser });\n\n // Clear cookie regardless of token validity\n ctx.cookies.set(REFRESH_COOKIE_NAME, '', {\n ...getRefreshCookieOptions(ctx.request.secure),\n expires: new Date(0),\n });\n\n try {\n const sessionManager = getSessionManager();\n if (sessionManager) {\n const userId = String(ctx.state.user.id);\n const bodyDeviceId = (ctx.request.body as { deviceId?: string } | undefined)?.deviceId;\n const sessionId = (ctx.state.session as { id?: string } | undefined)?.id;\n\n if (typeof bodyDeviceId === 'string' && bodyDeviceId.length > 0) {\n const deviceId = await resolveLogoutDeviceId(userId, sessionId, bodyDeviceId);\n await sessionManager('admin').invalidateRefreshToken(userId, deviceId);\n } else {\n await sessionManager('admin').invalidateRefreshToken(userId);\n }\n }\n } catch (err) {\n strapi.log.error('Failed to revoke admin sessions during logout', err as any);\n }\n\n ctx.body = { data: {} };\n },\n};\n"],"names":["ApplicationError","ValidationError","errors","login","compose","ctx","next","validateLoginSessionInput","request","body","passport","authenticate","session","err","user","info","strapi","eventHub","emit","error","provider","details","code","notImplemented","Error","message","query","state","sanitizedUser","getService","sanitizeUser","sessionManager","getSessionManager","internalServerError","userId","String","id","deviceId","rememberMe","extractDeviceParams","token","refreshToken","absoluteExpiresAt","generateRefreshToken","type","metadata","buildSessionMetadataFromContext","cookieOptions","buildCookieOptionsWithExpiry","secure","cookies","set","REFRESH_COOKIE_NAME","accessResult","generateAccessToken","accessToken","data","log","registrationInfo","validateRegistrationInfoQuery","registrationToken","findRegistrationInfo","register","input","validateRegistrationInput","registerAdmin","validateAdminRegistrationInput","createFirstAdmin","telemetry","send","forgotPassword","validateForgotPasswordInput","status","resetPassword","validateResetPasswordInput","generateDeviceId","invalidateRefreshToken","get","unauthorized","rotation","rotateRefreshToken","result","opts","logout","getRefreshCookieOptions","expires","Date","bodyDeviceId","sessionId","length","resolveLogoutDeviceId"],"mappings":"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"}
1
+ {"version":3,"file":"authentication.js","sources":["../../../../../server/src/controllers/authentication.ts"],"sourcesContent":["import type { Context, Next } from 'koa';\nimport passport from 'koa-passport';\nimport compose from 'koa-compose';\nimport '@strapi/types';\nimport { errors } from '@strapi/utils';\nimport { getService } from '../utils';\nimport {\n REFRESH_COOKIE_NAME,\n buildCookieOptionsWithExpiry,\n buildSessionMetadataFromContext,\n getSessionManager,\n extractDeviceParams,\n generateDeviceId,\n getRefreshCookieOptions,\n resolveLogoutDeviceId,\n} from '../../../shared/utils/session-auth';\n\nimport {\n validateRegistrationInput,\n validateAdminRegistrationInput,\n validateRegistrationInfoQuery,\n validateForgotPasswordInput,\n validateResetPasswordInput,\n validateLoginSessionInput,\n} from '../validation/authentication';\n\nimport type {\n ForgotPassword,\n Login,\n Register,\n RegisterAdmin,\n RegistrationInfo,\n ResetPassword,\n} from '../../../shared/contracts/authentication';\nimport { AdminUser } from '../../../shared/contracts/shared';\n\nconst { ApplicationError, ValidationError } = errors;\n\nexport default {\n login: compose([\n async (ctx: Context, next: Next) => {\n await validateLoginSessionInput(ctx.request.body ?? {});\n return next();\n },\n (ctx: Context, next: Next) => {\n return passport.authenticate('local', { session: false }, (err, user, info) => {\n if (err) {\n strapi.eventHub.emit('admin.auth.error', { error: err, provider: 'local' });\n // if this is a recognized error, allow it to bubble up to user\n if (err.details?.code === 'LOGIN_NOT_ALLOWED') {\n throw err;\n }\n\n // for all other errors throw a generic error to prevent leaking info\n return ctx.notImplemented();\n }\n\n if (!user) {\n strapi.eventHub.emit('admin.auth.error', {\n error: new Error(info.message),\n provider: 'local',\n });\n throw new ApplicationError(info.message);\n }\n\n const query = ctx.state as Login.Request['query'];\n query.user = user;\n\n const sanitizedUser = getService('user').sanitizeUser(user);\n strapi.eventHub.emit('admin.auth.success', { user: sanitizedUser, provider: 'local' });\n\n return next();\n })(ctx, next);\n },\n async (ctx: Context) => {\n const { user } = ctx.state as { user: AdminUser };\n\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n const userId = String(user.id);\n const { deviceId, rememberMe } = extractDeviceParams(ctx.request.body);\n\n const { token: refreshToken, absoluteExpiresAt } = await sessionManager(\n 'admin'\n ).generateRefreshToken(userId, deviceId, {\n type: rememberMe ? 'refresh' : 'session',\n metadata: buildSessionMetadataFromContext(ctx),\n });\n\n const cookieOptions = buildCookieOptionsWithExpiry(\n rememberMe ? 'refresh' : 'session',\n absoluteExpiresAt,\n ctx.request.secure\n );\n ctx.cookies.set(REFRESH_COOKIE_NAME, refreshToken, cookieOptions);\n\n const accessResult = await sessionManager('admin').generateAccessToken(refreshToken);\n if ('error' in accessResult) {\n return ctx.internalServerError();\n }\n\n const { token: accessToken } = accessResult;\n\n ctx.body = {\n data: {\n token: accessToken,\n accessToken,\n user: getService('user').sanitizeUser(ctx.state.user),\n },\n } satisfies Login.Response;\n } catch (error) {\n strapi.log.error('Failed to create admin refresh session', error);\n return ctx.internalServerError();\n }\n },\n ]),\n\n async registrationInfo(ctx: Context) {\n await validateRegistrationInfoQuery(ctx.request.query);\n\n const { registrationToken } = ctx.request.query as RegistrationInfo.Request['query'];\n\n const registrationInfo = await getService('user').findRegistrationInfo(registrationToken);\n\n if (!registrationInfo) {\n throw new ValidationError('Invalid registrationToken');\n }\n\n ctx.body = { data: registrationInfo } satisfies RegistrationInfo.Response;\n },\n\n async register(ctx: Context) {\n const input = ctx.request.body as Register.Request['body'];\n\n await validateRegistrationInput(input);\n\n const user = await getService('user').register(input);\n\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n const userId = String(user.id);\n const { deviceId, rememberMe } = extractDeviceParams(ctx.request.body);\n\n const { token: refreshToken, absoluteExpiresAt } = await sessionManager(\n 'admin'\n ).generateRefreshToken(userId, deviceId, {\n type: rememberMe ? 'refresh' : 'session',\n metadata: buildSessionMetadataFromContext(ctx),\n });\n\n const cookieOptions = buildCookieOptionsWithExpiry(\n rememberMe ? 'refresh' : 'session',\n absoluteExpiresAt,\n ctx.request.secure\n );\n ctx.cookies.set(REFRESH_COOKIE_NAME, refreshToken, cookieOptions);\n\n const accessResult = await sessionManager('admin').generateAccessToken(refreshToken);\n if ('error' in accessResult) {\n return ctx.internalServerError();\n }\n\n const { token: accessToken } = accessResult;\n\n ctx.body = {\n data: {\n token: accessToken,\n accessToken,\n user: getService('user').sanitizeUser(user),\n },\n } satisfies Register.Response;\n } catch (error) {\n strapi.log.error('Failed to create admin refresh session during register', error);\n return ctx.internalServerError();\n }\n },\n\n async registerAdmin(ctx: Context) {\n const input = ctx.request.body as RegisterAdmin.Request['body'];\n\n await validateAdminRegistrationInput(input);\n\n const user = await getService('user').createFirstAdmin(input);\n\n strapi.telemetry.send('didCreateFirstAdmin');\n\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n const userId = String(user.id);\n const { deviceId, rememberMe } = extractDeviceParams(ctx.request.body);\n\n const { token: refreshToken, absoluteExpiresAt } = await sessionManager(\n 'admin'\n ).generateRefreshToken(userId, deviceId, {\n type: rememberMe ? 'refresh' : 'session',\n metadata: buildSessionMetadataFromContext(ctx),\n });\n\n const cookieOptions = buildCookieOptionsWithExpiry(\n rememberMe ? 'refresh' : 'session',\n absoluteExpiresAt,\n ctx.request.secure\n );\n ctx.cookies.set(REFRESH_COOKIE_NAME, refreshToken, cookieOptions);\n\n const accessResult = await sessionManager('admin').generateAccessToken(refreshToken);\n if ('error' in accessResult) {\n return ctx.internalServerError();\n }\n\n const { token: accessToken } = accessResult;\n\n ctx.body = {\n data: {\n token: accessToken,\n accessToken,\n user: getService('user').sanitizeUser(user),\n },\n } satisfies RegisterAdmin.Response;\n } catch (error) {\n strapi.log.error('Failed to create admin refresh session during register-admin', error);\n return ctx.internalServerError();\n }\n },\n\n async forgotPassword(ctx: Context) {\n const input = ctx.request.body as ForgotPassword.Request['body'];\n\n await validateForgotPasswordInput(input);\n\n // Not awaited: the response must not reveal whether the email exists. The call runs\n // synchronously so a broken service still surfaces as a 500; only a rejection of the\n // returned promise is caught here, since nothing else would handle it.\n Promise.resolve(getService('auth').forgotPassword(input)).catch((error: unknown) => {\n strapi.log.error('Failed to process the forgot-password request', { error });\n });\n\n ctx.status = 204;\n },\n\n async resetPassword(ctx: Context) {\n const input = ctx.request.body as ResetPassword.Request['body'];\n\n await validateResetPasswordInput(input);\n\n const user = await getService('auth').resetPassword(input);\n\n // Issue a new admin refresh session and access token after password reset.\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n\n const userId = String(user.id);\n const deviceId = generateDeviceId();\n\n // Invalidate all existing sessions before creating a new one\n await sessionManager('admin').invalidateRefreshToken(userId);\n\n const { token: refreshToken, absoluteExpiresAt } = await sessionManager(\n 'admin'\n ).generateRefreshToken(userId, deviceId, {\n type: 'session',\n metadata: buildSessionMetadataFromContext(ctx),\n });\n\n // No rememberMe flow here; expire with session by default (session cookie)\n const cookieOptions = buildCookieOptionsWithExpiry(\n 'session',\n absoluteExpiresAt,\n ctx.request.secure\n );\n ctx.cookies.set(REFRESH_COOKIE_NAME, refreshToken, cookieOptions);\n\n const accessResult = await sessionManager('admin').generateAccessToken(refreshToken);\n if ('error' in accessResult) {\n return ctx.internalServerError();\n }\n\n const { token } = accessResult;\n\n ctx.body = {\n data: {\n token,\n user: getService('user').sanitizeUser(user),\n },\n } satisfies ResetPassword.Response;\n } catch (err) {\n strapi.log.error('Failed to create admin refresh session during reset-password', err as any);\n return ctx.internalServerError();\n }\n },\n\n async accessToken(ctx: Context) {\n const refreshToken = ctx.cookies.get(REFRESH_COOKIE_NAME);\n\n if (!refreshToken) {\n return ctx.unauthorized('Missing refresh token');\n }\n\n try {\n const sessionManager = getSessionManager();\n if (!sessionManager) {\n return ctx.internalServerError();\n }\n\n // Single-use renewal: rotate on access exchange, then create access token\n // from the new refresh token\n const rotation = await sessionManager('admin').rotateRefreshToken(refreshToken);\n if ('error' in rotation) {\n return ctx.unauthorized('Invalid refresh token');\n }\n\n const result = await sessionManager('admin').generateAccessToken(rotation.token);\n if ('error' in result) {\n return ctx.unauthorized('Invalid refresh token');\n }\n\n const { token } = result;\n // Preserve session-vs-remember mode using rotation.type and rotation.absoluteExpiresAt\n const opts = buildCookieOptionsWithExpiry(\n rotation.type,\n rotation.absoluteExpiresAt,\n ctx.request.secure\n );\n\n ctx.cookies.set(REFRESH_COOKIE_NAME, rotation.token, opts);\n ctx.body = { data: { token } };\n } catch (err) {\n strapi.log.error('Failed to generate access token from refresh token', err as any);\n return ctx.internalServerError();\n }\n },\n\n async logout(ctx: Context) {\n const sanitizedUser = getService('user').sanitizeUser(ctx.state.user);\n strapi.eventHub.emit('admin.logout', { user: sanitizedUser });\n\n // Clear cookie regardless of token validity\n ctx.cookies.set(REFRESH_COOKIE_NAME, '', {\n ...getRefreshCookieOptions(ctx.request.secure),\n expires: new Date(0),\n });\n\n try {\n const sessionManager = getSessionManager();\n if (sessionManager) {\n const userId = String(ctx.state.user.id);\n const bodyDeviceId = (ctx.request.body as { deviceId?: string } | undefined)?.deviceId;\n const sessionId = (ctx.state.session as { id?: string } | undefined)?.id;\n\n if (typeof bodyDeviceId === 'string' && bodyDeviceId.length > 0) {\n const deviceId = await resolveLogoutDeviceId(userId, sessionId, bodyDeviceId);\n await sessionManager('admin').invalidateRefreshToken(userId, deviceId);\n } else {\n await sessionManager('admin').invalidateRefreshToken(userId);\n }\n }\n } catch (err) {\n strapi.log.error('Failed to revoke admin sessions during logout', err as any);\n }\n\n ctx.body = { data: {} };\n },\n};\n"],"names":["ApplicationError","ValidationError","errors","login","compose","ctx","next","validateLoginSessionInput","request","body","passport","authenticate","session","err","user","info","strapi","eventHub","emit","error","provider","details","code","notImplemented","Error","message","query","state","sanitizedUser","getService","sanitizeUser","sessionManager","getSessionManager","internalServerError","userId","String","id","deviceId","rememberMe","extractDeviceParams","token","refreshToken","absoluteExpiresAt","generateRefreshToken","type","metadata","buildSessionMetadataFromContext","cookieOptions","buildCookieOptionsWithExpiry","secure","cookies","set","REFRESH_COOKIE_NAME","accessResult","generateAccessToken","accessToken","data","log","registrationInfo","validateRegistrationInfoQuery","registrationToken","findRegistrationInfo","register","input","validateRegistrationInput","registerAdmin","validateAdminRegistrationInput","createFirstAdmin","telemetry","send","forgotPassword","validateForgotPasswordInput","Promise","resolve","catch","status","resetPassword","validateResetPasswordInput","generateDeviceId","invalidateRefreshToken","get","unauthorized","rotation","rotateRefreshToken","result","opts","logout","getRefreshCookieOptions","expires","Date","bodyDeviceId","sessionId","length","resolveLogoutDeviceId"],"mappings":"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"}
@@ -165,7 +165,14 @@ var authentication = {
165
165
  async forgotPassword (ctx) {
166
166
  const input = ctx.request.body;
167
167
  await validateForgotPasswordInput(input);
168
- getService('auth').forgotPassword(input);
168
+ // Not awaited: the response must not reveal whether the email exists. The call runs
169
+ // synchronously so a broken service still surfaces as a 500; only a rejection of the
170
+ // returned promise is caught here, since nothing else would handle it.
171
+ Promise.resolve(getService('auth').forgotPassword(input)).catch((error)=>{
172
+ strapi.log.error('Failed to process the forgot-password request', {
173
+ error
174
+ });
175
+ });
169
176
  ctx.status = 204;
170
177
  },
171
178
  async resetPassword (ctx) {