@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.
- package/dist/admin/admin/src/components/UpsellBanner.js +9 -16
- package/dist/admin/admin/src/components/UpsellBanner.js.map +1 -1
- package/dist/admin/admin/src/components/UpsellBanner.mjs +11 -18
- package/dist/admin/admin/src/components/UpsellBanner.mjs.map +1 -1
- package/dist/admin/admin/src/render.js +4 -69
- package/dist/admin/admin/src/render.js.map +1 -1
- package/dist/admin/admin/src/render.mjs +4 -69
- package/dist/admin/admin/src/render.mjs.map +1 -1
- package/dist/admin/admin/src/translations/en.json.js +10 -0
- package/dist/admin/admin/src/translations/en.json.js.map +1 -1
- package/dist/admin/admin/src/translations/en.json.mjs +10 -0
- package/dist/admin/admin/src/translations/en.json.mjs.map +1 -1
- package/dist/admin/admin/src/utils/browserStrapi.js +93 -0
- package/dist/admin/admin/src/utils/browserStrapi.js.map +1 -0
- package/dist/admin/admin/src/utils/browserStrapi.mjs +91 -0
- package/dist/admin/admin/src/utils/browserStrapi.mjs.map +1 -0
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/hooks/useExportAuditLogs.js +2 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/hooks/useExportAuditLogs.js.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/hooks/useExportAuditLogs.mjs +2 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/hooks/useExportAuditLogs.mjs.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js +11 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.js.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs +11 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.mjs.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getDisplayedFilters.js +3 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getDisplayedFilters.js.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getDisplayedFilters.mjs +3 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getDisplayedFilters.mjs.map +1 -1
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.js +64 -0
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.js.map +1 -0
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.mjs +60 -0
- package/dist/admin/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.mjs.map +1 -0
- package/dist/admin/ee/admin/src/services/auditLogs.js +2 -1
- package/dist/admin/ee/admin/src/services/auditLogs.js.map +1 -1
- package/dist/admin/ee/admin/src/services/auditLogs.mjs +2 -1
- package/dist/admin/ee/admin/src/services/auditLogs.mjs.map +1 -1
- package/dist/admin/src/components/SubNav.d.ts +2 -2
- package/dist/admin/src/utils/browserStrapi.d.ts +11 -0
- package/dist/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/getActionTypesDefaultMessages.d.ts +10 -0
- package/dist/ee/admin/src/pages/SettingsPage/pages/AuditLogs/utils/legacyActions.d.ts +14 -0
- package/dist/ee/server/src/audit-logs/services/lifecycles.d.ts +10 -1
- package/dist/ee/server/src/audit-logs/services/lifecycles.d.ts.map +1 -1
- package/dist/ee/server/src/controllers/admin.d.ts +2 -28
- package/dist/ee/server/src/controllers/admin.d.ts.map +1 -1
- package/dist/ee/server/src/controllers/index.d.ts +1 -28
- package/dist/ee/server/src/controllers/index.d.ts.map +1 -1
- package/dist/ee/server/src/index.d.ts +2 -29
- package/dist/ee/server/src/index.d.ts.map +1 -1
- package/dist/ee/server/src/services/auth.d.ts +1 -1
- package/dist/ee/server/src/services/auth.d.ts.map +1 -1
- package/dist/ee/server/src/services/index.d.ts +1 -1
- package/dist/ee/server/src/services/user.d.ts.map +1 -1
- package/dist/server/ee/server/src/audit-logs/services/lifecycles.js +37 -21
- package/dist/server/ee/server/src/audit-logs/services/lifecycles.js.map +1 -1
- package/dist/server/ee/server/src/audit-logs/services/lifecycles.mjs +37 -21
- package/dist/server/ee/server/src/audit-logs/services/lifecycles.mjs.map +1 -1
- package/dist/server/ee/server/src/controllers/admin.js +5 -3
- package/dist/server/ee/server/src/controllers/admin.js.map +1 -1
- package/dist/server/ee/server/src/controllers/admin.mjs +5 -3
- package/dist/server/ee/server/src/controllers/admin.mjs.map +1 -1
- package/dist/server/ee/server/src/index.js +4 -0
- package/dist/server/ee/server/src/index.js.map +1 -1
- package/dist/server/ee/server/src/index.mjs +4 -0
- package/dist/server/ee/server/src/index.mjs.map +1 -1
- package/dist/server/ee/server/src/services/auth.js +1 -6
- package/dist/server/ee/server/src/services/auth.js.map +1 -1
- package/dist/server/ee/server/src/services/auth.mjs +2 -7
- package/dist/server/ee/server/src/services/auth.mjs.map +1 -1
- package/dist/server/ee/server/src/services/user.js +36 -4
- package/dist/server/ee/server/src/services/user.js.map +1 -1
- package/dist/server/ee/server/src/services/user.mjs +36 -4
- package/dist/server/ee/server/src/services/user.mjs.map +1 -1
- package/dist/server/server/src/audit-logs/admin-users.js +169 -0
- package/dist/server/server/src/audit-logs/admin-users.js.map +1 -0
- package/dist/server/server/src/audit-logs/admin-users.mjs +157 -0
- package/dist/server/server/src/audit-logs/admin-users.mjs.map +1 -0
- package/dist/server/server/src/audit-logs/webhooks.js +106 -0
- package/dist/server/server/src/audit-logs/webhooks.js.map +1 -0
- package/dist/server/server/src/audit-logs/webhooks.mjs +100 -0
- package/dist/server/server/src/audit-logs/webhooks.mjs.map +1 -0
- package/dist/server/server/src/controllers/admin.js +1 -0
- package/dist/server/server/src/controllers/admin.js.map +1 -1
- package/dist/server/server/src/controllers/admin.mjs +1 -0
- package/dist/server/server/src/controllers/admin.mjs.map +1 -1
- package/dist/server/server/src/controllers/authentication.js +8 -1
- package/dist/server/server/src/controllers/authentication.js.map +1 -1
- package/dist/server/server/src/controllers/authentication.mjs +8 -1
- package/dist/server/server/src/controllers/authentication.mjs.map +1 -1
- package/dist/server/server/src/controllers/webhooks.js +26 -0
- package/dist/server/server/src/controllers/webhooks.js.map +1 -1
- package/dist/server/server/src/controllers/webhooks.mjs +27 -1
- package/dist/server/server/src/controllers/webhooks.mjs.map +1 -1
- package/dist/server/server/src/services/auth.js +27 -6
- package/dist/server/server/src/services/auth.js.map +1 -1
- package/dist/server/server/src/services/auth.mjs +28 -8
- package/dist/server/server/src/services/auth.mjs.map +1 -1
- package/dist/server/server/src/services/user.js +48 -9
- package/dist/server/server/src/services/user.js.map +1 -1
- package/dist/server/server/src/services/user.mjs +49 -10
- package/dist/server/server/src/services/user.mjs.map +1 -1
- package/dist/server/src/audit-logs/admin-users.d.ts +119 -0
- package/dist/server/src/audit-logs/admin-users.d.ts.map +1 -0
- package/dist/server/src/audit-logs/webhooks.d.ts +59 -0
- package/dist/server/src/audit-logs/webhooks.d.ts.map +1 -0
- package/dist/server/src/controllers/admin.d.ts +2 -11
- package/dist/server/src/controllers/admin.d.ts.map +1 -1
- package/dist/server/src/controllers/authentication.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts +1 -10
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/controllers/webhooks.d.ts.map +1 -1
- package/dist/server/src/domain/user.d.ts +2 -2
- package/dist/server/src/index.d.ts +1 -10
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/services/auth.d.ts +6 -1
- package/dist/server/src/services/auth.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/user.d.ts.map +1 -1
- package/dist/shared/contracts/admin.d.ts +36 -2
- package/dist/shared/contracts/admin.d.ts.map +1 -1
- package/package.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authentication.mjs","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.mjs","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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"}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var isLocalhostIp = require('is-localhost-ip');
|
|
4
4
|
var _ = require('lodash');
|
|
5
5
|
var utils = require('@strapi/utils');
|
|
6
|
+
var webhooks$1 = require('../audit-logs/webhooks.js');
|
|
6
7
|
|
|
7
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
9
|
|
|
@@ -60,6 +61,9 @@ var webhooks = {
|
|
|
60
61
|
await utils.validateYupSchema(webhookValidator)(body);
|
|
61
62
|
const webhook = await strapi.get('webhookStore').createWebhook(body);
|
|
62
63
|
strapi.get('webhookRunner').add(webhook);
|
|
64
|
+
await utils.emitAudit({
|
|
65
|
+
strapi
|
|
66
|
+
}, webhooks$1.AUDITED_EVENTS.WEBHOOK_CREATE, webhooks$1.toAuditedWebhook(webhook));
|
|
63
67
|
ctx.created({
|
|
64
68
|
data: webhook
|
|
65
69
|
});
|
|
@@ -80,6 +84,16 @@ var webhooks = {
|
|
|
80
84
|
return ctx.notFound('webhook.notFound');
|
|
81
85
|
}
|
|
82
86
|
strapi.get('webhookRunner').update(updatedWebhook);
|
|
87
|
+
const changes = webhooks$1.getWebhookChanges(webhook, updatedWebhook);
|
|
88
|
+
if (!___default.default.isEmpty(changes)) {
|
|
89
|
+
await utils.emitAudit({
|
|
90
|
+
strapi
|
|
91
|
+
}, webhooks$1.AUDITED_EVENTS.WEBHOOK_UPDATE, {
|
|
92
|
+
webhookId: updatedWebhook.id,
|
|
93
|
+
name: updatedWebhook.name,
|
|
94
|
+
changes
|
|
95
|
+
});
|
|
96
|
+
}
|
|
83
97
|
ctx.send({
|
|
84
98
|
data: updatedWebhook
|
|
85
99
|
});
|
|
@@ -92,6 +106,12 @@ var webhooks = {
|
|
|
92
106
|
}
|
|
93
107
|
await strapi.get('webhookStore').deleteWebhook(id);
|
|
94
108
|
strapi.get('webhookRunner').remove(webhook);
|
|
109
|
+
await utils.emitAudit({
|
|
110
|
+
strapi
|
|
111
|
+
}, webhooks$1.AUDITED_EVENTS.WEBHOOK_DELETE, {
|
|
112
|
+
webhookId: webhook.id,
|
|
113
|
+
name: webhook.name
|
|
114
|
+
});
|
|
95
115
|
ctx.body = {
|
|
96
116
|
data: webhook
|
|
97
117
|
};
|
|
@@ -106,6 +126,12 @@ var webhooks = {
|
|
|
106
126
|
if (webhook) {
|
|
107
127
|
await strapi.get('webhookStore').deleteWebhook(id);
|
|
108
128
|
strapi.get('webhookRunner').remove(webhook);
|
|
129
|
+
await utils.emitAudit({
|
|
130
|
+
strapi
|
|
131
|
+
}, webhooks$1.AUDITED_EVENTS.WEBHOOK_DELETE, {
|
|
132
|
+
webhookId: webhook.id,
|
|
133
|
+
name: webhook.name
|
|
134
|
+
});
|
|
109
135
|
}
|
|
110
136
|
}
|
|
111
137
|
ctx.send({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.js","sources":["../../../../../server/src/controllers/webhooks.ts"],"sourcesContent":["import isLocalhostIp from 'is-localhost-ip';\nimport type { Context } from 'koa';\nimport _ from 'lodash';\n\nimport { yup, validateYupSchema } from '@strapi/utils';\n\nimport type { Modules } from '@strapi/types';\n\nimport {\n CreateWebhook,\n DeleteWebhook,\n DeleteWebhooks,\n GetWebhook,\n UpdateWebhook,\n TriggerWebhook,\n GetWebhooks,\n} from '../../../shared/contracts/webhooks';\n\nconst urlRegex =\n /^(?:([a-z0-9+.-]+):\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9_]-*)*[a-z\\u00a1-\\uffff0-9_]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9_]-*)*[a-z\\u00a1-\\uffff0-9_]+)*\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$/;\n\nconst webhookValidator = yup\n .object({\n name: yup.string().required(),\n url: yup\n .string()\n .matches(urlRegex, 'url must be a valid URL')\n .required()\n .test(\n 'is-public-url',\n \"Url is not supported because it isn't reachable over the public internet\",\n async (url) => {\n if (process.env.NODE_ENV !== 'production') {\n return true;\n }\n\n try {\n const parsedUrl = new URL(url!);\n const isLocalUrl = await isLocalhostIp(parsedUrl.hostname);\n return !isLocalUrl;\n } catch {\n return false;\n }\n }\n ),\n headers: yup.lazy((data) => {\n if (typeof data !== 'object') {\n return yup.object().required();\n }\n\n return yup\n .object(\n // @ts-expect-error lodash types\n _.mapValues(data, () => {\n yup.string().min(1).required();\n })\n )\n .required();\n }),\n events: yup.array().of(yup.string()).required(),\n })\n .noUnknown();\n\nconst updateWebhookValidator = webhookValidator.shape({\n isEnabled: yup.boolean(),\n});\n\nexport default {\n async listWebhooks(ctx: Context) {\n const webhooks = await strapi.get('webhookStore').findWebhooks();\n ctx.send({ data: webhooks } satisfies GetWebhooks.Response);\n },\n\n async getWebhook(ctx: Context) {\n const { id } = ctx.params;\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n ctx.send({ data: webhook } satisfies GetWebhook.Response);\n },\n\n async createWebhook(ctx: Context) {\n const { body } = ctx.request as CreateWebhook.Request;\n\n await validateYupSchema(webhookValidator)(body);\n\n const webhook = await strapi.get('webhookStore').createWebhook(body);\n\n strapi.get('webhookRunner').add(webhook);\n\n ctx.created({ data: webhook } satisfies CreateWebhook.Response);\n },\n\n async updateWebhook(ctx: Context) {\n const { id } = ctx.params as UpdateWebhook.Params;\n const { body } = ctx.request as UpdateWebhook.Request;\n\n await validateYupSchema(updateWebhookValidator)(body);\n\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n const updatedWebhook = await strapi.get('webhookStore').updateWebhook(id, {\n ...webhook,\n ...body,\n });\n\n if (!updatedWebhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n strapi.get('webhookRunner').update(updatedWebhook);\n\n ctx.send({ data: updatedWebhook } satisfies UpdateWebhook.Response);\n },\n\n async deleteWebhook(ctx: Context) {\n const { id } = ctx.params;\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n await strapi.get('webhookStore').deleteWebhook(id);\n\n strapi.get('webhookRunner').remove(webhook);\n\n ctx.body = { data: webhook } satisfies DeleteWebhook.Response;\n },\n\n async deleteWebhooks(ctx: Context) {\n const { ids } = ctx.request.body as DeleteWebhooks.Request['body'];\n\n if (!Array.isArray(ids) || ids.length === 0) {\n return ctx.badRequest('ids must be an array of id');\n }\n\n for (const id of ids) {\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (webhook) {\n await strapi.get('webhookStore').deleteWebhook(id);\n strapi.get('webhookRunner').remove(webhook);\n }\n }\n\n ctx.send({ data: ids } satisfies DeleteWebhooks.Response);\n },\n\n async triggerWebhook(ctx: Context) {\n const { id } = ctx.params;\n\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n const response = await strapi\n .get('webhookRunner')\n .run(webhook as Modules.WebhookStore.Webhook, 'trigger-test', {});\n\n ctx.body = { data: response } satisfies TriggerWebhook.Response;\n },\n};\n"],"names":["urlRegex","webhookValidator","yup","object","name","string","required","url","matches","test","process","env","NODE_ENV","parsedUrl","URL","isLocalUrl","isLocalhostIp","hostname","headers","lazy","data","_","mapValues","min","events","array","of","noUnknown","updateWebhookValidator","shape","isEnabled","boolean","listWebhooks","ctx","webhooks","strapi","get","findWebhooks","send","getWebhook","id","params","webhook","findWebhook","notFound","createWebhook","body","request","validateYupSchema","add","created","updateWebhook","updatedWebhook","update","deleteWebhook","remove","deleteWebhooks","ids","Array","isArray","length","badRequest","triggerWebhook","response","run"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"webhooks.js","sources":["../../../../../server/src/controllers/webhooks.ts"],"sourcesContent":["import isLocalhostIp from 'is-localhost-ip';\nimport type { Context } from 'koa';\nimport _ from 'lodash';\n\nimport { yup, validateYupSchema, emitAudit } from '@strapi/utils';\n\nimport type { Modules } from '@strapi/types';\n\nimport { AUDITED_EVENTS, getWebhookChanges, toAuditedWebhook } from '../audit-logs/webhooks';\n\nimport {\n CreateWebhook,\n DeleteWebhook,\n DeleteWebhooks,\n GetWebhook,\n UpdateWebhook,\n TriggerWebhook,\n GetWebhooks,\n} from '../../../shared/contracts/webhooks';\n\nconst urlRegex =\n /^(?:([a-z0-9+.-]+):\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9_]-*)*[a-z\\u00a1-\\uffff0-9_]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9_]-*)*[a-z\\u00a1-\\uffff0-9_]+)*\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$/;\n\nconst webhookValidator = yup\n .object({\n name: yup.string().required(),\n url: yup\n .string()\n .matches(urlRegex, 'url must be a valid URL')\n .required()\n .test(\n 'is-public-url',\n \"Url is not supported because it isn't reachable over the public internet\",\n async (url) => {\n if (process.env.NODE_ENV !== 'production') {\n return true;\n }\n\n try {\n const parsedUrl = new URL(url!);\n const isLocalUrl = await isLocalhostIp(parsedUrl.hostname);\n return !isLocalUrl;\n } catch {\n return false;\n }\n }\n ),\n headers: yup.lazy((data) => {\n if (typeof data !== 'object') {\n return yup.object().required();\n }\n\n return yup\n .object(\n // @ts-expect-error lodash types\n _.mapValues(data, () => {\n yup.string().min(1).required();\n })\n )\n .required();\n }),\n events: yup.array().of(yup.string()).required(),\n })\n .noUnknown();\n\nconst updateWebhookValidator = webhookValidator.shape({\n isEnabled: yup.boolean(),\n});\n\nexport default {\n async listWebhooks(ctx: Context) {\n const webhooks = await strapi.get('webhookStore').findWebhooks();\n ctx.send({ data: webhooks } satisfies GetWebhooks.Response);\n },\n\n async getWebhook(ctx: Context) {\n const { id } = ctx.params;\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n ctx.send({ data: webhook } satisfies GetWebhook.Response);\n },\n\n async createWebhook(ctx: Context) {\n const { body } = ctx.request as CreateWebhook.Request;\n\n await validateYupSchema(webhookValidator)(body);\n\n const webhook = await strapi.get('webhookStore').createWebhook(body);\n\n strapi.get('webhookRunner').add(webhook);\n\n await emitAudit({ strapi }, AUDITED_EVENTS.WEBHOOK_CREATE, toAuditedWebhook(webhook));\n\n ctx.created({ data: webhook } satisfies CreateWebhook.Response);\n },\n\n async updateWebhook(ctx: Context) {\n const { id } = ctx.params as UpdateWebhook.Params;\n const { body } = ctx.request as UpdateWebhook.Request;\n\n await validateYupSchema(updateWebhookValidator)(body);\n\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n const updatedWebhook = await strapi.get('webhookStore').updateWebhook(id, {\n ...webhook,\n ...body,\n });\n\n if (!updatedWebhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n strapi.get('webhookRunner').update(updatedWebhook);\n\n const changes = getWebhookChanges(webhook, updatedWebhook);\n\n if (!_.isEmpty(changes)) {\n await emitAudit({ strapi }, AUDITED_EVENTS.WEBHOOK_UPDATE, {\n webhookId: updatedWebhook.id,\n name: updatedWebhook.name,\n changes,\n });\n }\n\n ctx.send({ data: updatedWebhook } satisfies UpdateWebhook.Response);\n },\n\n async deleteWebhook(ctx: Context) {\n const { id } = ctx.params;\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n await strapi.get('webhookStore').deleteWebhook(id);\n\n strapi.get('webhookRunner').remove(webhook);\n\n await emitAudit({ strapi }, AUDITED_EVENTS.WEBHOOK_DELETE, {\n webhookId: webhook.id,\n name: webhook.name,\n });\n\n ctx.body = { data: webhook } satisfies DeleteWebhook.Response;\n },\n\n async deleteWebhooks(ctx: Context) {\n const { ids } = ctx.request.body as DeleteWebhooks.Request['body'];\n\n if (!Array.isArray(ids) || ids.length === 0) {\n return ctx.badRequest('ids must be an array of id');\n }\n\n for (const id of ids) {\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (webhook) {\n await strapi.get('webhookStore').deleteWebhook(id);\n strapi.get('webhookRunner').remove(webhook);\n\n await emitAudit({ strapi }, AUDITED_EVENTS.WEBHOOK_DELETE, {\n webhookId: webhook.id,\n name: webhook.name,\n });\n }\n }\n\n ctx.send({ data: ids } satisfies DeleteWebhooks.Response);\n },\n\n async triggerWebhook(ctx: Context) {\n const { id } = ctx.params;\n\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n const response = await strapi\n .get('webhookRunner')\n .run(webhook as Modules.WebhookStore.Webhook, 'trigger-test', {});\n\n ctx.body = { data: response } satisfies TriggerWebhook.Response;\n },\n};\n"],"names":["urlRegex","webhookValidator","yup","object","name","string","required","url","matches","test","process","env","NODE_ENV","parsedUrl","URL","isLocalUrl","isLocalhostIp","hostname","headers","lazy","data","_","mapValues","min","events","array","of","noUnknown","updateWebhookValidator","shape","isEnabled","boolean","listWebhooks","ctx","webhooks","strapi","get","findWebhooks","send","getWebhook","id","params","webhook","findWebhook","notFound","createWebhook","body","request","validateYupSchema","add","emitAudit","AUDITED_EVENTS","WEBHOOK_CREATE","toAuditedWebhook","created","updateWebhook","updatedWebhook","update","changes","getWebhookChanges","isEmpty","WEBHOOK_UPDATE","webhookId","deleteWebhook","remove","WEBHOOK_DELETE","deleteWebhooks","ids","Array","isArray","length","badRequest","triggerWebhook","response","run"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import isLocalhostIp from 'is-localhost-ip';
|
|
2
2
|
import ___default from 'lodash';
|
|
3
|
-
import { yup, validateYupSchema } from '@strapi/utils';
|
|
3
|
+
import { yup, emitAudit, validateYupSchema } from '@strapi/utils';
|
|
4
|
+
import { AUDITED_EVENTS, getWebhookChanges, toAuditedWebhook } from '../audit-logs/webhooks.mjs';
|
|
4
5
|
|
|
5
6
|
const urlRegex = /^(?:([a-z0-9+.-]+):\/\/)(?:\S+(?::\S*)?@)?(?:(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)(?:\.(?:[a-z\u00a1-\uffff0-9_]-*)*[a-z\u00a1-\uffff0-9_]+)*\.?)(?::\d{2,5})?(?:[/?#]\S*)?$/;
|
|
6
7
|
const webhookValidator = yup.object({
|
|
@@ -53,6 +54,9 @@ var webhooks = {
|
|
|
53
54
|
await validateYupSchema(webhookValidator)(body);
|
|
54
55
|
const webhook = await strapi.get('webhookStore').createWebhook(body);
|
|
55
56
|
strapi.get('webhookRunner').add(webhook);
|
|
57
|
+
await emitAudit({
|
|
58
|
+
strapi
|
|
59
|
+
}, AUDITED_EVENTS.WEBHOOK_CREATE, toAuditedWebhook(webhook));
|
|
56
60
|
ctx.created({
|
|
57
61
|
data: webhook
|
|
58
62
|
});
|
|
@@ -73,6 +77,16 @@ var webhooks = {
|
|
|
73
77
|
return ctx.notFound('webhook.notFound');
|
|
74
78
|
}
|
|
75
79
|
strapi.get('webhookRunner').update(updatedWebhook);
|
|
80
|
+
const changes = getWebhookChanges(webhook, updatedWebhook);
|
|
81
|
+
if (!___default.isEmpty(changes)) {
|
|
82
|
+
await emitAudit({
|
|
83
|
+
strapi
|
|
84
|
+
}, AUDITED_EVENTS.WEBHOOK_UPDATE, {
|
|
85
|
+
webhookId: updatedWebhook.id,
|
|
86
|
+
name: updatedWebhook.name,
|
|
87
|
+
changes
|
|
88
|
+
});
|
|
89
|
+
}
|
|
76
90
|
ctx.send({
|
|
77
91
|
data: updatedWebhook
|
|
78
92
|
});
|
|
@@ -85,6 +99,12 @@ var webhooks = {
|
|
|
85
99
|
}
|
|
86
100
|
await strapi.get('webhookStore').deleteWebhook(id);
|
|
87
101
|
strapi.get('webhookRunner').remove(webhook);
|
|
102
|
+
await emitAudit({
|
|
103
|
+
strapi
|
|
104
|
+
}, AUDITED_EVENTS.WEBHOOK_DELETE, {
|
|
105
|
+
webhookId: webhook.id,
|
|
106
|
+
name: webhook.name
|
|
107
|
+
});
|
|
88
108
|
ctx.body = {
|
|
89
109
|
data: webhook
|
|
90
110
|
};
|
|
@@ -99,6 +119,12 @@ var webhooks = {
|
|
|
99
119
|
if (webhook) {
|
|
100
120
|
await strapi.get('webhookStore').deleteWebhook(id);
|
|
101
121
|
strapi.get('webhookRunner').remove(webhook);
|
|
122
|
+
await emitAudit({
|
|
123
|
+
strapi
|
|
124
|
+
}, AUDITED_EVENTS.WEBHOOK_DELETE, {
|
|
125
|
+
webhookId: webhook.id,
|
|
126
|
+
name: webhook.name
|
|
127
|
+
});
|
|
102
128
|
}
|
|
103
129
|
}
|
|
104
130
|
ctx.send({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"webhooks.mjs","sources":["../../../../../server/src/controllers/webhooks.ts"],"sourcesContent":["import isLocalhostIp from 'is-localhost-ip';\nimport type { Context } from 'koa';\nimport _ from 'lodash';\n\nimport { yup, validateYupSchema } from '@strapi/utils';\n\nimport type { Modules } from '@strapi/types';\n\nimport {\n CreateWebhook,\n DeleteWebhook,\n DeleteWebhooks,\n GetWebhook,\n UpdateWebhook,\n TriggerWebhook,\n GetWebhooks,\n} from '../../../shared/contracts/webhooks';\n\nconst urlRegex =\n /^(?:([a-z0-9+.-]+):\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9_]-*)*[a-z\\u00a1-\\uffff0-9_]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9_]-*)*[a-z\\u00a1-\\uffff0-9_]+)*\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$/;\n\nconst webhookValidator = yup\n .object({\n name: yup.string().required(),\n url: yup\n .string()\n .matches(urlRegex, 'url must be a valid URL')\n .required()\n .test(\n 'is-public-url',\n \"Url is not supported because it isn't reachable over the public internet\",\n async (url) => {\n if (process.env.NODE_ENV !== 'production') {\n return true;\n }\n\n try {\n const parsedUrl = new URL(url!);\n const isLocalUrl = await isLocalhostIp(parsedUrl.hostname);\n return !isLocalUrl;\n } catch {\n return false;\n }\n }\n ),\n headers: yup.lazy((data) => {\n if (typeof data !== 'object') {\n return yup.object().required();\n }\n\n return yup\n .object(\n // @ts-expect-error lodash types\n _.mapValues(data, () => {\n yup.string().min(1).required();\n })\n )\n .required();\n }),\n events: yup.array().of(yup.string()).required(),\n })\n .noUnknown();\n\nconst updateWebhookValidator = webhookValidator.shape({\n isEnabled: yup.boolean(),\n});\n\nexport default {\n async listWebhooks(ctx: Context) {\n const webhooks = await strapi.get('webhookStore').findWebhooks();\n ctx.send({ data: webhooks } satisfies GetWebhooks.Response);\n },\n\n async getWebhook(ctx: Context) {\n const { id } = ctx.params;\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n ctx.send({ data: webhook } satisfies GetWebhook.Response);\n },\n\n async createWebhook(ctx: Context) {\n const { body } = ctx.request as CreateWebhook.Request;\n\n await validateYupSchema(webhookValidator)(body);\n\n const webhook = await strapi.get('webhookStore').createWebhook(body);\n\n strapi.get('webhookRunner').add(webhook);\n\n ctx.created({ data: webhook } satisfies CreateWebhook.Response);\n },\n\n async updateWebhook(ctx: Context) {\n const { id } = ctx.params as UpdateWebhook.Params;\n const { body } = ctx.request as UpdateWebhook.Request;\n\n await validateYupSchema(updateWebhookValidator)(body);\n\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n const updatedWebhook = await strapi.get('webhookStore').updateWebhook(id, {\n ...webhook,\n ...body,\n });\n\n if (!updatedWebhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n strapi.get('webhookRunner').update(updatedWebhook);\n\n ctx.send({ data: updatedWebhook } satisfies UpdateWebhook.Response);\n },\n\n async deleteWebhook(ctx: Context) {\n const { id } = ctx.params;\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n await strapi.get('webhookStore').deleteWebhook(id);\n\n strapi.get('webhookRunner').remove(webhook);\n\n ctx.body = { data: webhook } satisfies DeleteWebhook.Response;\n },\n\n async deleteWebhooks(ctx: Context) {\n const { ids } = ctx.request.body as DeleteWebhooks.Request['body'];\n\n if (!Array.isArray(ids) || ids.length === 0) {\n return ctx.badRequest('ids must be an array of id');\n }\n\n for (const id of ids) {\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (webhook) {\n await strapi.get('webhookStore').deleteWebhook(id);\n strapi.get('webhookRunner').remove(webhook);\n }\n }\n\n ctx.send({ data: ids } satisfies DeleteWebhooks.Response);\n },\n\n async triggerWebhook(ctx: Context) {\n const { id } = ctx.params;\n\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n const response = await strapi\n .get('webhookRunner')\n .run(webhook as Modules.WebhookStore.Webhook, 'trigger-test', {});\n\n ctx.body = { data: response } satisfies TriggerWebhook.Response;\n },\n};\n"],"names":["urlRegex","webhookValidator","yup","object","name","string","required","url","matches","test","process","env","NODE_ENV","parsedUrl","URL","isLocalUrl","isLocalhostIp","hostname","headers","lazy","data","_","mapValues","min","events","array","of","noUnknown","updateWebhookValidator","shape","isEnabled","boolean","listWebhooks","ctx","webhooks","strapi","get","findWebhooks","send","getWebhook","id","params","webhook","findWebhook","notFound","createWebhook","body","request","validateYupSchema","add","created","updateWebhook","updatedWebhook","update","deleteWebhook","remove","deleteWebhooks","ids","Array","isArray","length","badRequest","triggerWebhook","response","run"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"webhooks.mjs","sources":["../../../../../server/src/controllers/webhooks.ts"],"sourcesContent":["import isLocalhostIp from 'is-localhost-ip';\nimport type { Context } from 'koa';\nimport _ from 'lodash';\n\nimport { yup, validateYupSchema, emitAudit } from '@strapi/utils';\n\nimport type { Modules } from '@strapi/types';\n\nimport { AUDITED_EVENTS, getWebhookChanges, toAuditedWebhook } from '../audit-logs/webhooks';\n\nimport {\n CreateWebhook,\n DeleteWebhook,\n DeleteWebhooks,\n GetWebhook,\n UpdateWebhook,\n TriggerWebhook,\n GetWebhooks,\n} from '../../../shared/contracts/webhooks';\n\nconst urlRegex =\n /^(?:([a-z0-9+.-]+):\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z\\u00a1-\\uffff0-9_]-*)*[a-z\\u00a1-\\uffff0-9_]+)(?:\\.(?:[a-z\\u00a1-\\uffff0-9_]-*)*[a-z\\u00a1-\\uffff0-9_]+)*\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$/;\n\nconst webhookValidator = yup\n .object({\n name: yup.string().required(),\n url: yup\n .string()\n .matches(urlRegex, 'url must be a valid URL')\n .required()\n .test(\n 'is-public-url',\n \"Url is not supported because it isn't reachable over the public internet\",\n async (url) => {\n if (process.env.NODE_ENV !== 'production') {\n return true;\n }\n\n try {\n const parsedUrl = new URL(url!);\n const isLocalUrl = await isLocalhostIp(parsedUrl.hostname);\n return !isLocalUrl;\n } catch {\n return false;\n }\n }\n ),\n headers: yup.lazy((data) => {\n if (typeof data !== 'object') {\n return yup.object().required();\n }\n\n return yup\n .object(\n // @ts-expect-error lodash types\n _.mapValues(data, () => {\n yup.string().min(1).required();\n })\n )\n .required();\n }),\n events: yup.array().of(yup.string()).required(),\n })\n .noUnknown();\n\nconst updateWebhookValidator = webhookValidator.shape({\n isEnabled: yup.boolean(),\n});\n\nexport default {\n async listWebhooks(ctx: Context) {\n const webhooks = await strapi.get('webhookStore').findWebhooks();\n ctx.send({ data: webhooks } satisfies GetWebhooks.Response);\n },\n\n async getWebhook(ctx: Context) {\n const { id } = ctx.params;\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n ctx.send({ data: webhook } satisfies GetWebhook.Response);\n },\n\n async createWebhook(ctx: Context) {\n const { body } = ctx.request as CreateWebhook.Request;\n\n await validateYupSchema(webhookValidator)(body);\n\n const webhook = await strapi.get('webhookStore').createWebhook(body);\n\n strapi.get('webhookRunner').add(webhook);\n\n await emitAudit({ strapi }, AUDITED_EVENTS.WEBHOOK_CREATE, toAuditedWebhook(webhook));\n\n ctx.created({ data: webhook } satisfies CreateWebhook.Response);\n },\n\n async updateWebhook(ctx: Context) {\n const { id } = ctx.params as UpdateWebhook.Params;\n const { body } = ctx.request as UpdateWebhook.Request;\n\n await validateYupSchema(updateWebhookValidator)(body);\n\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n const updatedWebhook = await strapi.get('webhookStore').updateWebhook(id, {\n ...webhook,\n ...body,\n });\n\n if (!updatedWebhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n strapi.get('webhookRunner').update(updatedWebhook);\n\n const changes = getWebhookChanges(webhook, updatedWebhook);\n\n if (!_.isEmpty(changes)) {\n await emitAudit({ strapi }, AUDITED_EVENTS.WEBHOOK_UPDATE, {\n webhookId: updatedWebhook.id,\n name: updatedWebhook.name,\n changes,\n });\n }\n\n ctx.send({ data: updatedWebhook } satisfies UpdateWebhook.Response);\n },\n\n async deleteWebhook(ctx: Context) {\n const { id } = ctx.params;\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (!webhook) {\n return ctx.notFound('webhook.notFound');\n }\n\n await strapi.get('webhookStore').deleteWebhook(id);\n\n strapi.get('webhookRunner').remove(webhook);\n\n await emitAudit({ strapi }, AUDITED_EVENTS.WEBHOOK_DELETE, {\n webhookId: webhook.id,\n name: webhook.name,\n });\n\n ctx.body = { data: webhook } satisfies DeleteWebhook.Response;\n },\n\n async deleteWebhooks(ctx: Context) {\n const { ids } = ctx.request.body as DeleteWebhooks.Request['body'];\n\n if (!Array.isArray(ids) || ids.length === 0) {\n return ctx.badRequest('ids must be an array of id');\n }\n\n for (const id of ids) {\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n if (webhook) {\n await strapi.get('webhookStore').deleteWebhook(id);\n strapi.get('webhookRunner').remove(webhook);\n\n await emitAudit({ strapi }, AUDITED_EVENTS.WEBHOOK_DELETE, {\n webhookId: webhook.id,\n name: webhook.name,\n });\n }\n }\n\n ctx.send({ data: ids } satisfies DeleteWebhooks.Response);\n },\n\n async triggerWebhook(ctx: Context) {\n const { id } = ctx.params;\n\n const webhook = await strapi.get('webhookStore').findWebhook(id);\n\n const response = await strapi\n .get('webhookRunner')\n .run(webhook as Modules.WebhookStore.Webhook, 'trigger-test', {});\n\n ctx.body = { data: response } satisfies TriggerWebhook.Response;\n },\n};\n"],"names":["urlRegex","webhookValidator","yup","object","name","string","required","url","matches","test","process","env","NODE_ENV","parsedUrl","URL","isLocalUrl","isLocalhostIp","hostname","headers","lazy","data","_","mapValues","min","events","array","of","noUnknown","updateWebhookValidator","shape","isEnabled","boolean","listWebhooks","ctx","webhooks","strapi","get","findWebhooks","send","getWebhook","id","params","webhook","findWebhook","notFound","createWebhook","body","request","validateYupSchema","add","emitAudit","AUDITED_EVENTS","WEBHOOK_CREATE","toAuditedWebhook","created","updateWebhook","updatedWebhook","update","changes","getWebhookChanges","isEmpty","WEBHOOK_UPDATE","webhookId","deleteWebhook","remove","WEBHOOK_DELETE","deleteWebhooks","ids","Array","isArray","length","badRequest","triggerWebhook","response","run"],"mappings":"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"}
|
|
@@ -7,6 +7,7 @@ var _ = require('lodash');
|
|
|
7
7
|
var utils = require('@strapi/utils');
|
|
8
8
|
var index = require('../utils/index.js');
|
|
9
9
|
var token = require('./token.js');
|
|
10
|
+
var adminUsers = require('../audit-logs/admin-users.js');
|
|
10
11
|
require('@strapi/types');
|
|
11
12
|
|
|
12
13
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -33,12 +34,35 @@ const DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN = '1h';
|
|
|
33
34
|
*/ const assignResetPasswordToken = async (userId)=>{
|
|
34
35
|
const resetPasswordToken = index.getService('token').createToken();
|
|
35
36
|
const resetPasswordTokenExpiresAt = new Date(Date.now() + getResetPasswordTokenTTL());
|
|
36
|
-
await index.getService('user').updateById(userId, {
|
|
37
|
+
const user = await index.getService('user').updateById(userId, {
|
|
37
38
|
resetPasswordToken,
|
|
38
39
|
resetPasswordTokenExpiresAt
|
|
39
40
|
});
|
|
41
|
+
// null when the account was deleted between the caller's lookup and this write
|
|
42
|
+
if (user) {
|
|
43
|
+
await utils.emitAudit({
|
|
44
|
+
strapi
|
|
45
|
+
}, adminUsers.AUDITED_EVENTS.PASSWORD_RESET_CREATE, {
|
|
46
|
+
...adminUsers.toAdminUserEvent(user),
|
|
47
|
+
expiresAt: user.resetPasswordTokenExpiresAt
|
|
48
|
+
});
|
|
49
|
+
}
|
|
40
50
|
return resetPasswordToken;
|
|
41
51
|
};
|
|
52
|
+
/**
|
|
53
|
+
* Set the new password and consume the reset token. Shared by the CE and EE auth
|
|
54
|
+
* services, after each has validated the token.
|
|
55
|
+
*/ const completePasswordReset = async (user, password)=>{
|
|
56
|
+
const updatedUser = await index.getService('user').updateById(user.id, {
|
|
57
|
+
password,
|
|
58
|
+
resetPasswordToken: null,
|
|
59
|
+
resetPasswordTokenExpiresAt: null
|
|
60
|
+
});
|
|
61
|
+
await utils.emitAudit({
|
|
62
|
+
strapi
|
|
63
|
+
}, adminUsers.AUDITED_EVENTS.PASSWORD_RESET_CONFIRM, adminUsers.toAdminUserEvent(updatedUser));
|
|
64
|
+
return updatedUser;
|
|
65
|
+
};
|
|
42
66
|
/**
|
|
43
67
|
* Reject a reset-password token that has expired — or that has no expiry at all
|
|
44
68
|
* (tokens issued before this was introduced) — clearing the stale token so it
|
|
@@ -157,11 +181,7 @@ const DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN = '1h';
|
|
|
157
181
|
throw new ApplicationError();
|
|
158
182
|
}
|
|
159
183
|
await assertResetPasswordTokenIsValid(matchingUser);
|
|
160
|
-
return
|
|
161
|
-
password,
|
|
162
|
-
resetPasswordToken: null,
|
|
163
|
-
resetPasswordTokenExpiresAt: null
|
|
164
|
-
});
|
|
184
|
+
return completePasswordReset(matchingUser, password);
|
|
165
185
|
};
|
|
166
186
|
var auth = {
|
|
167
187
|
checkCredentials,
|
|
@@ -173,6 +193,7 @@ var auth = {
|
|
|
173
193
|
|
|
174
194
|
exports.assertResetPasswordTokenIsValid = assertResetPasswordTokenIsValid;
|
|
175
195
|
exports.assignResetPasswordToken = assignResetPasswordToken;
|
|
196
|
+
exports.completePasswordReset = completePasswordReset;
|
|
176
197
|
exports.default = auth;
|
|
177
198
|
exports.getResetPasswordTokenTTL = getResetPasswordTokenTTL;
|
|
178
199
|
//# sourceMappingURL=auth.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sources":["../../../../../server/src/services/auth.ts"],"sourcesContent":["import bcrypt from 'bcryptjs';\nimport _ from 'lodash';\nimport { errors } from '@strapi/utils';\nimport { getService } from '../utils';\nimport { expiresInToSeconds } from './token';\nimport type { AdminUser } from '../../../shared/contracts/shared';\nimport '@strapi/types';\n\nconst { ApplicationError } = errors;\n\n// Default lifetime of an admin reset-password token. Overridable via\n// `admin.forgotPassword.expiresIn` (number of seconds or a shorthand like '15m', '1h').\nconst DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN = '1h';\n\n/**\n * Resolve the reset-password token lifetime, in milliseconds, from config.\n * Falls back to {@link DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN} for unset/invalid values.\n */\nconst getResetPasswordTokenTTL = (): number => {\n const configured = strapi.config.get(\n 'admin.forgotPassword.expiresIn',\n DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN\n );\n const seconds =\n expiresInToSeconds(configured) ??\n (expiresInToSeconds(DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN) as number);\n return seconds * 1000;\n};\n\n/**\n * Create a reset-password token with an expiry and persist it on the user.\n * Shared by the CE and EE auth services so the expiry behaviour can't drift.\n * @returns the generated reset-password token\n */\nconst assignResetPasswordToken = async (userId: AdminUser['id']): Promise<string> => {\n const resetPasswordToken = getService('token').createToken();\n const resetPasswordTokenExpiresAt = new Date(Date.now() + getResetPasswordTokenTTL());\n\n await getService('user').updateById(userId, {\n resetPasswordToken,\n resetPasswordTokenExpiresAt,\n });\n\n return resetPasswordToken;\n};\n\n/**\n * Reject a reset-password token that has expired — or that has no expiry at all\n * (tokens issued before this was introduced) — clearing the stale token so it\n * cannot be retried. Shared by the CE and EE auth services. (GH#25711)\n */\nconst assertResetPasswordTokenIsValid = async (user: AdminUser): Promise<void> => {\n const { resetPasswordTokenExpiresAt } = user;\n const isExpired =\n !resetPasswordTokenExpiresAt || new Date(resetPasswordTokenExpiresAt).getTime() <= Date.now();\n\n if (isExpired) {\n // Clear the stale token so it can no longer be retried.\n await getService('user').updateById(user.id, {\n resetPasswordToken: null,\n resetPasswordTokenExpiresAt: null,\n });\n throw new ApplicationError('This reset password token has expired');\n }\n};\n\n/**\n * hashes a password\n * @param password - password to hash\n * @returns hashed password\n */\nconst hashPassword = (password: string) => bcrypt.hash(password, 10);\n\n/**\n * Validate a password\n * @param password\n * @param hash\n * @returns {Promise<boolean>} is the password valid\n */\nconst validatePassword = (password: string, hash: string) => bcrypt.compare(password, hash);\n\n/**\n * Check login credentials\n * @param email the users email address\n * @param password the users password\n */\nconst checkCredentials = async ({ email, password }: { email: string; password: string }) => {\n const user: AdminUser = await strapi.db.query('admin::user').findOne({ where: { email } });\n\n if (!user || !user.password) {\n return [null, false, { message: 'Invalid credentials' }];\n }\n\n const isValid = await validatePassword(password, user.password);\n\n if (!isValid) {\n return [null, false, { message: 'Invalid credentials' }];\n }\n\n if (!(user.isActive === true)) {\n return [null, false, { message: 'User not active' }];\n }\n\n return [null, user];\n};\n\n/**\n * Send an email to the user if it exists or do nothing\n * @param email user email for which to reset the password\n */\nconst forgotPassword = async ({ email } = {} as { email: string }) => {\n const user: AdminUser = await strapi.db\n .query('admin::user')\n .findOne({ where: { email, isActive: true } });\n if (!user) {\n return;\n }\n\n const resetPasswordToken = await assignResetPasswordToken(user.id);\n\n // Send an email to the admin.\n const url = `${strapi.config.get(\n 'admin.absoluteUrl'\n )}/auth/reset-password?code=${resetPasswordToken}`;\n\n return strapi\n .plugin('email')\n .service('email')\n .sendTemplatedEmail(\n {\n to: user.email,\n from: strapi.config.get('admin.forgotPassword.from'),\n replyTo: strapi.config.get('admin.forgotPassword.replyTo'),\n },\n strapi.config.get('admin.forgotPassword.emailTemplate'),\n {\n url,\n user: _.pick(user, ['email', 'firstname', 'lastname', 'username']),\n }\n )\n .catch((err: unknown) => {\n // log error server side but do not disclose it to the user to avoid leaking informations\n strapi.log.error(err);\n });\n};\n\n/**\n * Reset a user password\n * @param resetPasswordToken token generated to request a password reset\n * @param password new user password\n */\nconst resetPassword = async (\n { resetPasswordToken, password } = {} as { resetPasswordToken: string; password: string }\n) => {\n const matchingUser: AdminUser | undefined = await strapi.db\n .query('admin::user')\n .findOne({ where: { resetPasswordToken, isActive: true } });\n\n if (!matchingUser) {\n throw new ApplicationError();\n }\n\n await assertResetPasswordTokenIsValid(matchingUser);\n\n return getService('user').updateById(matchingUser.id, {\n password,\n resetPasswordToken: null,\n resetPasswordTokenExpiresAt: null,\n });\n};\n\nexport default { checkCredentials, validatePassword, hashPassword, forgotPassword, resetPassword };\nexport { getResetPasswordTokenTTL, assignResetPasswordToken, assertResetPasswordTokenIsValid };\n"],"names":["ApplicationError","errors","DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN","getResetPasswordTokenTTL","configured","strapi","config","get","seconds","expiresInToSeconds","assignResetPasswordToken","userId","resetPasswordToken","getService","createToken","resetPasswordTokenExpiresAt","Date","now","updateById","assertResetPasswordTokenIsValid","user","isExpired","getTime","id","hashPassword","password","bcrypt","hash","validatePassword","compare","checkCredentials","email","db","query","findOne","where","message","isValid","isActive","forgotPassword","url","plugin","service","sendTemplatedEmail","to","from","replyTo","_","pick","catch","err","log","error","resetPassword","matchingUser"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth.js","sources":["../../../../../server/src/services/auth.ts"],"sourcesContent":["import bcrypt from 'bcryptjs';\nimport _ from 'lodash';\nimport { errors, emitAudit } from '@strapi/utils';\nimport { getService } from '../utils';\nimport { expiresInToSeconds } from './token';\nimport { AUDITED_EVENTS, toAdminUserEvent } from '../audit-logs/admin-users';\nimport type { AdminUser } from '../../../shared/contracts/shared';\nimport '@strapi/types';\n\nconst { ApplicationError } = errors;\n\n// Default lifetime of an admin reset-password token. Overridable via\n// `admin.forgotPassword.expiresIn` (number of seconds or a shorthand like '15m', '1h').\nconst DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN = '1h';\n\n/**\n * Resolve the reset-password token lifetime, in milliseconds, from config.\n * Falls back to {@link DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN} for unset/invalid values.\n */\nconst getResetPasswordTokenTTL = (): number => {\n const configured = strapi.config.get(\n 'admin.forgotPassword.expiresIn',\n DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN\n );\n const seconds =\n expiresInToSeconds(configured) ??\n (expiresInToSeconds(DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN) as number);\n return seconds * 1000;\n};\n\n/**\n * Create a reset-password token with an expiry and persist it on the user.\n * Shared by the CE and EE auth services so the expiry behaviour can't drift.\n * @returns the generated reset-password token\n */\nconst assignResetPasswordToken = async (userId: AdminUser['id']): Promise<string> => {\n const resetPasswordToken = getService('token').createToken();\n const resetPasswordTokenExpiresAt = new Date(Date.now() + getResetPasswordTokenTTL());\n\n const user = await getService('user').updateById(userId, {\n resetPasswordToken,\n resetPasswordTokenExpiresAt,\n });\n\n // null when the account was deleted between the caller's lookup and this write\n if (user) {\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_RESET_CREATE, {\n ...toAdminUserEvent(user),\n expiresAt: user.resetPasswordTokenExpiresAt,\n });\n }\n\n return resetPasswordToken;\n};\n\n/**\n * Set the new password and consume the reset token. Shared by the CE and EE auth\n * services, after each has validated the token.\n */\nconst completePasswordReset = async (user: AdminUser, password: string): Promise<AdminUser> => {\n const updatedUser = await getService('user').updateById(user.id, {\n password,\n resetPasswordToken: null,\n resetPasswordTokenExpiresAt: null,\n });\n\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_RESET_CONFIRM, toAdminUserEvent(updatedUser));\n\n return updatedUser;\n};\n\n/**\n * Reject a reset-password token that has expired — or that has no expiry at all\n * (tokens issued before this was introduced) — clearing the stale token so it\n * cannot be retried. Shared by the CE and EE auth services. (GH#25711)\n */\nconst assertResetPasswordTokenIsValid = async (user: AdminUser): Promise<void> => {\n const { resetPasswordTokenExpiresAt } = user;\n const isExpired =\n !resetPasswordTokenExpiresAt || new Date(resetPasswordTokenExpiresAt).getTime() <= Date.now();\n\n if (isExpired) {\n // Clear the stale token so it can no longer be retried.\n await getService('user').updateById(user.id, {\n resetPasswordToken: null,\n resetPasswordTokenExpiresAt: null,\n });\n throw new ApplicationError('This reset password token has expired');\n }\n};\n\n/**\n * hashes a password\n * @param password - password to hash\n * @returns hashed password\n */\nconst hashPassword = (password: string) => bcrypt.hash(password, 10);\n\n/**\n * Validate a password\n * @param password\n * @param hash\n * @returns {Promise<boolean>} is the password valid\n */\nconst validatePassword = (password: string, hash: string) => bcrypt.compare(password, hash);\n\n/**\n * Check login credentials\n * @param email the users email address\n * @param password the users password\n */\nconst checkCredentials = async ({ email, password }: { email: string; password: string }) => {\n const user: AdminUser = await strapi.db.query('admin::user').findOne({ where: { email } });\n\n if (!user || !user.password) {\n return [null, false, { message: 'Invalid credentials' }];\n }\n\n const isValid = await validatePassword(password, user.password);\n\n if (!isValid) {\n return [null, false, { message: 'Invalid credentials' }];\n }\n\n if (!(user.isActive === true)) {\n return [null, false, { message: 'User not active' }];\n }\n\n return [null, user];\n};\n\n/**\n * Send an email to the user if it exists or do nothing\n * @param email user email for which to reset the password\n */\nconst forgotPassword = async ({ email } = {} as { email: string }) => {\n const user: AdminUser = await strapi.db\n .query('admin::user')\n .findOne({ where: { email, isActive: true } });\n if (!user) {\n return;\n }\n\n const resetPasswordToken = await assignResetPasswordToken(user.id);\n\n // Send an email to the admin.\n const url = `${strapi.config.get(\n 'admin.absoluteUrl'\n )}/auth/reset-password?code=${resetPasswordToken}`;\n\n return strapi\n .plugin('email')\n .service('email')\n .sendTemplatedEmail(\n {\n to: user.email,\n from: strapi.config.get('admin.forgotPassword.from'),\n replyTo: strapi.config.get('admin.forgotPassword.replyTo'),\n },\n strapi.config.get('admin.forgotPassword.emailTemplate'),\n {\n url,\n user: _.pick(user, ['email', 'firstname', 'lastname', 'username']),\n }\n )\n .catch((err: unknown) => {\n // log error server side but do not disclose it to the user to avoid leaking informations\n strapi.log.error(err);\n });\n};\n\n/**\n * Reset a user password\n * @param resetPasswordToken token generated to request a password reset\n * @param password new user password\n */\nconst resetPassword = async (\n { resetPasswordToken, password } = {} as { resetPasswordToken: string; password: string }\n) => {\n const matchingUser: AdminUser | undefined = await strapi.db\n .query('admin::user')\n .findOne({ where: { resetPasswordToken, isActive: true } });\n\n if (!matchingUser) {\n throw new ApplicationError();\n }\n\n await assertResetPasswordTokenIsValid(matchingUser);\n\n return completePasswordReset(matchingUser, password);\n};\n\nexport default { checkCredentials, validatePassword, hashPassword, forgotPassword, resetPassword };\nexport {\n getResetPasswordTokenTTL,\n assignResetPasswordToken,\n assertResetPasswordTokenIsValid,\n completePasswordReset,\n};\n"],"names":["ApplicationError","errors","DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN","getResetPasswordTokenTTL","configured","strapi","config","get","seconds","expiresInToSeconds","assignResetPasswordToken","userId","resetPasswordToken","getService","createToken","resetPasswordTokenExpiresAt","Date","now","user","updateById","emitAudit","AUDITED_EVENTS","PASSWORD_RESET_CREATE","toAdminUserEvent","expiresAt","completePasswordReset","password","updatedUser","id","PASSWORD_RESET_CONFIRM","assertResetPasswordTokenIsValid","isExpired","getTime","hashPassword","bcrypt","hash","validatePassword","compare","checkCredentials","email","db","query","findOne","where","message","isValid","isActive","forgotPassword","url","plugin","service","sendTemplatedEmail","to","from","replyTo","_","pick","catch","err","log","error","resetPassword","matchingUser"],"mappings":";;;;;;;;;;;;;;;;;AASA,MAAM,EAAEA,gBAAgB,EAAE,GAAGC,YAAAA;AAE7B;AACA;AACA,MAAMC,uCAAAA,GAA0C,IAAA;AAEhD;;;AAGC,UACKC,wBAAAA,GAA2B,IAAA;AAC/B,IAAA,MAAMC,aAAaC,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAClC,gCAAA,EACAL,uCAAAA,CAAAA;IAEF,MAAMM,OAAAA,GACJC,wBAAAA,CAAmBL,UAAAA,CAAAA,IAClBK,wBAAAA,CAAmBP,uCAAAA,CAAAA;AACtB,IAAA,OAAOM,OAAAA,GAAU,IAAA;AACnB;AAEA;;;;IAKA,MAAME,2BAA2B,OAAOC,MAAAA,GAAAA;IACtC,MAAMC,kBAAAA,GAAqBC,gBAAAA,CAAW,OAAA,CAAA,CAASC,WAAW,EAAA;AAC1D,IAAA,MAAMC,2BAAAA,GAA8B,IAAIC,IAAAA,CAAKA,IAAAA,CAAKC,GAAG,EAAA,GAAKd,wBAAAA,EAAAA,CAAAA;AAE1D,IAAA,MAAMe,OAAO,MAAML,gBAAAA,CAAW,MAAA,CAAA,CAAQM,UAAU,CAACR,MAAAA,EAAQ;AACvDC,QAAAA,kBAAAA;AACAG,QAAAA;AACF,KAAA,CAAA;;AAGA,IAAA,IAAIG,IAAAA,EAAM;AACR,QAAA,MAAME,eAAAA,CAAU;AAAEf,YAAAA;SAAO,EAAGgB,yBAAAA,CAAeC,qBAAqB,EAAE;AAChE,YAAA,GAAGC,4BAAiBL,IAAAA,CAAK;AACzBM,YAAAA,SAAAA,EAAWN,KAAKH;AAClB,SAAA,CAAA;AACF,IAAA;IAEA,OAAOH,kBAAAA;AACT;AAEA;;;IAIA,MAAMa,qBAAAA,GAAwB,OAAOP,IAAAA,EAAiBQ,QAAAA,GAAAA;IACpD,MAAMC,WAAAA,GAAc,MAAMd,gBAAAA,CAAW,MAAA,CAAA,CAAQM,UAAU,CAACD,IAAAA,CAAKU,EAAE,EAAE;AAC/DF,QAAAA,QAAAA;QACAd,kBAAAA,EAAoB,IAAA;QACpBG,2BAAAA,EAA6B;AAC/B,KAAA,CAAA;AAEA,IAAA,MAAMK,eAAAA,CAAU;AAAEf,QAAAA;KAAO,EAAGgB,yBAAAA,CAAeQ,sBAAsB,EAAEN,2BAAAA,CAAiBI,WAAAA,CAAAA,CAAAA;IAEpF,OAAOA,WAAAA;AACT;AAEA;;;;IAKA,MAAMG,kCAAkC,OAAOZ,IAAAA,GAAAA;IAC7C,MAAM,EAAEH,2BAA2B,EAAE,GAAGG,IAAAA;IACxC,MAAMa,SAAAA,GACJ,CAAChB,2BAAAA,IAA+B,IAAIC,KAAKD,2BAAAA,CAAAA,CAA6BiB,OAAO,EAAA,IAAMhB,IAAAA,CAAKC,GAAG,EAAA;AAE7F,IAAA,IAAIc,SAAAA,EAAW;;AAEb,QAAA,MAAMlB,iBAAW,MAAA,CAAA,CAAQM,UAAU,CAACD,IAAAA,CAAKU,EAAE,EAAE;YAC3ChB,kBAAAA,EAAoB,IAAA;YACpBG,2BAAAA,EAA6B;AAC/B,SAAA,CAAA;AACA,QAAA,MAAM,IAAIf,gBAAAA,CAAiB,uCAAA,CAAA;AAC7B,IAAA;AACF;AAEA;;;;AAIC,IACD,MAAMiC,YAAAA,GAAe,CAACP,WAAqBQ,uBAAAA,CAAOC,IAAI,CAACT,QAAAA,EAAU,EAAA,CAAA;AAEjE;;;;;IAMA,MAAMU,mBAAmB,CAACV,QAAAA,EAAkBS,OAAiBD,uBAAAA,CAAOG,OAAO,CAACX,QAAAA,EAAUS,IAAAA,CAAAA;AAEtF;;;;AAIC,IACD,MAAMG,gBAAAA,GAAmB,OAAO,EAAEC,KAAK,EAAEb,QAAQ,EAAuC,GAAA;IACtF,MAAMR,IAAAA,GAAkB,MAAMb,MAAAA,CAAOmC,EAAE,CAACC,KAAK,CAAC,aAAA,CAAA,CAAeC,OAAO,CAAC;QAAEC,KAAAA,EAAO;AAAEJ,YAAAA;AAAM;AAAE,KAAA,CAAA;AAExF,IAAA,IAAI,CAACrB,IAAAA,IAAQ,CAACA,IAAAA,CAAKQ,QAAQ,EAAE;QAC3B,OAAO;AAAC,YAAA,IAAA;AAAM,YAAA,KAAA;AAAO,YAAA;gBAAEkB,OAAAA,EAAS;AAAsB;AAAE,SAAA;AAC1D,IAAA;AAEA,IAAA,MAAMC,OAAAA,GAAU,MAAMT,gBAAAA,CAAiBV,QAAAA,EAAUR,KAAKQ,QAAQ,CAAA;AAE9D,IAAA,IAAI,CAACmB,OAAAA,EAAS;QACZ,OAAO;AAAC,YAAA,IAAA;AAAM,YAAA,KAAA;AAAO,YAAA;gBAAED,OAAAA,EAAS;AAAsB;AAAE,SAAA;AAC1D,IAAA;AAEA,IAAA,IAAI,EAAE1B,IAAAA,CAAK4B,QAAQ,KAAK,IAAG,CAAA,EAAI;QAC7B,OAAO;AAAC,YAAA,IAAA;AAAM,YAAA,KAAA;AAAO,YAAA;gBAAEF,OAAAA,EAAS;AAAkB;AAAE,SAAA;AACtD,IAAA;IAEA,OAAO;AAAC,QAAA,IAAA;AAAM1B,QAAAA;AAAK,KAAA;AACrB,CAAA;AAEA;;;IAIA,MAAM6B,iBAAiB,OAAO,EAAER,KAAK,EAAE,GAAG,EAAuB,GAAA;IAC/D,MAAMrB,IAAAA,GAAkB,MAAMb,MAAAA,CAAOmC,EAAE,CACpCC,KAAK,CAAC,aAAA,CAAA,CACNC,OAAO,CAAC;QAAEC,KAAAA,EAAO;AAAEJ,YAAAA,KAAAA;YAAOO,QAAAA,EAAU;AAAK;AAAE,KAAA,CAAA;AAC9C,IAAA,IAAI,CAAC5B,IAAAA,EAAM;AACT,QAAA;AACF,IAAA;AAEA,IAAA,MAAMN,kBAAAA,GAAqB,MAAMF,wBAAAA,CAAyBQ,IAAAA,CAAKU,EAAE,CAAA;;IAGjE,MAAMoB,GAAAA,GAAM,CAAA,EAAG3C,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAC9B,mBAAA,CAAA,CACA,0BAA0B,EAAEK,kBAAAA,CAAAA,CAAoB;IAElD,OAAOP,MAAAA,CACJ4C,MAAM,CAAC,OAAA,CAAA,CACPC,OAAO,CAAC,OAAA,CAAA,CACRC,kBAAkB,CACjB;AACEC,QAAAA,EAAAA,EAAIlC,KAAKqB,KAAK;AACdc,QAAAA,IAAAA,EAAMhD,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,2BAAA,CAAA;AACxB+C,QAAAA,OAAAA,EAASjD,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,8BAAA;AAC7B,KAAA,EACAF,MAAAA,CAAOC,MAAM,CAACC,GAAG,CAAC,oCAAA,CAAA,EAClB;AACEyC,QAAAA,GAAAA;QACA9B,IAAAA,EAAMqC,kBAAAA,CAAEC,IAAI,CAACtC,IAAAA,EAAM;AAAC,YAAA,OAAA;AAAS,YAAA,WAAA;AAAa,YAAA,UAAA;AAAY,YAAA;AAAW,SAAA;KACnE,CAAA,CAEDuC,KAAK,CAAC,CAACC,GAAAA,GAAAA;;QAENrD,MAAAA,CAAOsD,GAAG,CAACC,KAAK,CAACF,GAAAA,CAAAA;AACnB,IAAA,CAAA,CAAA;AACJ,CAAA;AAEA;;;;IAKA,MAAMG,aAAAA,GAAgB,OACpB,EAAEjD,kBAAkB,EAAEc,QAAQ,EAAE,GAAG,EAAsD,GAAA;IAEzF,MAAMoC,YAAAA,GAAsC,MAAMzD,MAAAA,CAAOmC,EAAE,CACxDC,KAAK,CAAC,aAAA,CAAA,CACNC,OAAO,CAAC;QAAEC,KAAAA,EAAO;AAAE/B,YAAAA,kBAAAA;YAAoBkC,QAAAA,EAAU;AAAK;AAAE,KAAA,CAAA;AAE3D,IAAA,IAAI,CAACgB,YAAAA,EAAc;AACjB,QAAA,MAAM,IAAI9D,gBAAAA,EAAAA;AACZ,IAAA;AAEA,IAAA,MAAM8B,+BAAAA,CAAgCgC,YAAAA,CAAAA;AAEtC,IAAA,OAAOrC,sBAAsBqC,YAAAA,EAAcpC,QAAAA,CAAAA;AAC7C,CAAA;AAEA,WAAe;AAAEY,IAAAA,gBAAAA;AAAkBF,IAAAA,gBAAAA;AAAkBH,IAAAA,YAAAA;AAAcc,IAAAA,cAAAA;AAAgBc,IAAAA;AAAc,CAAA;;;;;;;;"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import bcrypt from 'bcryptjs';
|
|
2
2
|
import ___default from 'lodash';
|
|
3
|
-
import { errors } from '@strapi/utils';
|
|
3
|
+
import { errors, emitAudit } from '@strapi/utils';
|
|
4
4
|
import { getService } from '../utils/index.mjs';
|
|
5
5
|
import { expiresInToSeconds } from './token.mjs';
|
|
6
|
+
import { AUDITED_EVENTS, toAdminUserEvent } from '../audit-logs/admin-users.mjs';
|
|
6
7
|
import '@strapi/types';
|
|
7
8
|
|
|
8
9
|
const { ApplicationError } = errors;
|
|
@@ -24,12 +25,35 @@ const DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN = '1h';
|
|
|
24
25
|
*/ const assignResetPasswordToken = async (userId)=>{
|
|
25
26
|
const resetPasswordToken = getService('token').createToken();
|
|
26
27
|
const resetPasswordTokenExpiresAt = new Date(Date.now() + getResetPasswordTokenTTL());
|
|
27
|
-
await getService('user').updateById(userId, {
|
|
28
|
+
const user = await getService('user').updateById(userId, {
|
|
28
29
|
resetPasswordToken,
|
|
29
30
|
resetPasswordTokenExpiresAt
|
|
30
31
|
});
|
|
32
|
+
// null when the account was deleted between the caller's lookup and this write
|
|
33
|
+
if (user) {
|
|
34
|
+
await emitAudit({
|
|
35
|
+
strapi
|
|
36
|
+
}, AUDITED_EVENTS.PASSWORD_RESET_CREATE, {
|
|
37
|
+
...toAdminUserEvent(user),
|
|
38
|
+
expiresAt: user.resetPasswordTokenExpiresAt
|
|
39
|
+
});
|
|
40
|
+
}
|
|
31
41
|
return resetPasswordToken;
|
|
32
42
|
};
|
|
43
|
+
/**
|
|
44
|
+
* Set the new password and consume the reset token. Shared by the CE and EE auth
|
|
45
|
+
* services, after each has validated the token.
|
|
46
|
+
*/ const completePasswordReset = async (user, password)=>{
|
|
47
|
+
const updatedUser = await getService('user').updateById(user.id, {
|
|
48
|
+
password,
|
|
49
|
+
resetPasswordToken: null,
|
|
50
|
+
resetPasswordTokenExpiresAt: null
|
|
51
|
+
});
|
|
52
|
+
await emitAudit({
|
|
53
|
+
strapi
|
|
54
|
+
}, AUDITED_EVENTS.PASSWORD_RESET_CONFIRM, toAdminUserEvent(updatedUser));
|
|
55
|
+
return updatedUser;
|
|
56
|
+
};
|
|
33
57
|
/**
|
|
34
58
|
* Reject a reset-password token that has expired — or that has no expiry at all
|
|
35
59
|
* (tokens issued before this was introduced) — clearing the stale token so it
|
|
@@ -148,11 +172,7 @@ const DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN = '1h';
|
|
|
148
172
|
throw new ApplicationError();
|
|
149
173
|
}
|
|
150
174
|
await assertResetPasswordTokenIsValid(matchingUser);
|
|
151
|
-
return
|
|
152
|
-
password,
|
|
153
|
-
resetPasswordToken: null,
|
|
154
|
-
resetPasswordTokenExpiresAt: null
|
|
155
|
-
});
|
|
175
|
+
return completePasswordReset(matchingUser, password);
|
|
156
176
|
};
|
|
157
177
|
var auth = {
|
|
158
178
|
checkCredentials,
|
|
@@ -162,5 +182,5 @@ var auth = {
|
|
|
162
182
|
resetPassword
|
|
163
183
|
};
|
|
164
184
|
|
|
165
|
-
export { assertResetPasswordTokenIsValid, assignResetPasswordToken, auth as default, getResetPasswordTokenTTL };
|
|
185
|
+
export { assertResetPasswordTokenIsValid, assignResetPasswordToken, completePasswordReset, auth as default, getResetPasswordTokenTTL };
|
|
166
186
|
//# sourceMappingURL=auth.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.mjs","sources":["../../../../../server/src/services/auth.ts"],"sourcesContent":["import bcrypt from 'bcryptjs';\nimport _ from 'lodash';\nimport { errors } from '@strapi/utils';\nimport { getService } from '../utils';\nimport { expiresInToSeconds } from './token';\nimport type { AdminUser } from '../../../shared/contracts/shared';\nimport '@strapi/types';\n\nconst { ApplicationError } = errors;\n\n// Default lifetime of an admin reset-password token. Overridable via\n// `admin.forgotPassword.expiresIn` (number of seconds or a shorthand like '15m', '1h').\nconst DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN = '1h';\n\n/**\n * Resolve the reset-password token lifetime, in milliseconds, from config.\n * Falls back to {@link DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN} for unset/invalid values.\n */\nconst getResetPasswordTokenTTL = (): number => {\n const configured = strapi.config.get(\n 'admin.forgotPassword.expiresIn',\n DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN\n );\n const seconds =\n expiresInToSeconds(configured) ??\n (expiresInToSeconds(DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN) as number);\n return seconds * 1000;\n};\n\n/**\n * Create a reset-password token with an expiry and persist it on the user.\n * Shared by the CE and EE auth services so the expiry behaviour can't drift.\n * @returns the generated reset-password token\n */\nconst assignResetPasswordToken = async (userId: AdminUser['id']): Promise<string> => {\n const resetPasswordToken = getService('token').createToken();\n const resetPasswordTokenExpiresAt = new Date(Date.now() + getResetPasswordTokenTTL());\n\n await getService('user').updateById(userId, {\n resetPasswordToken,\n resetPasswordTokenExpiresAt,\n });\n\n return resetPasswordToken;\n};\n\n/**\n * Reject a reset-password token that has expired — or that has no expiry at all\n * (tokens issued before this was introduced) — clearing the stale token so it\n * cannot be retried. Shared by the CE and EE auth services. (GH#25711)\n */\nconst assertResetPasswordTokenIsValid = async (user: AdminUser): Promise<void> => {\n const { resetPasswordTokenExpiresAt } = user;\n const isExpired =\n !resetPasswordTokenExpiresAt || new Date(resetPasswordTokenExpiresAt).getTime() <= Date.now();\n\n if (isExpired) {\n // Clear the stale token so it can no longer be retried.\n await getService('user').updateById(user.id, {\n resetPasswordToken: null,\n resetPasswordTokenExpiresAt: null,\n });\n throw new ApplicationError('This reset password token has expired');\n }\n};\n\n/**\n * hashes a password\n * @param password - password to hash\n * @returns hashed password\n */\nconst hashPassword = (password: string) => bcrypt.hash(password, 10);\n\n/**\n * Validate a password\n * @param password\n * @param hash\n * @returns {Promise<boolean>} is the password valid\n */\nconst validatePassword = (password: string, hash: string) => bcrypt.compare(password, hash);\n\n/**\n * Check login credentials\n * @param email the users email address\n * @param password the users password\n */\nconst checkCredentials = async ({ email, password }: { email: string; password: string }) => {\n const user: AdminUser = await strapi.db.query('admin::user').findOne({ where: { email } });\n\n if (!user || !user.password) {\n return [null, false, { message: 'Invalid credentials' }];\n }\n\n const isValid = await validatePassword(password, user.password);\n\n if (!isValid) {\n return [null, false, { message: 'Invalid credentials' }];\n }\n\n if (!(user.isActive === true)) {\n return [null, false, { message: 'User not active' }];\n }\n\n return [null, user];\n};\n\n/**\n * Send an email to the user if it exists or do nothing\n * @param email user email for which to reset the password\n */\nconst forgotPassword = async ({ email } = {} as { email: string }) => {\n const user: AdminUser = await strapi.db\n .query('admin::user')\n .findOne({ where: { email, isActive: true } });\n if (!user) {\n return;\n }\n\n const resetPasswordToken = await assignResetPasswordToken(user.id);\n\n // Send an email to the admin.\n const url = `${strapi.config.get(\n 'admin.absoluteUrl'\n )}/auth/reset-password?code=${resetPasswordToken}`;\n\n return strapi\n .plugin('email')\n .service('email')\n .sendTemplatedEmail(\n {\n to: user.email,\n from: strapi.config.get('admin.forgotPassword.from'),\n replyTo: strapi.config.get('admin.forgotPassword.replyTo'),\n },\n strapi.config.get('admin.forgotPassword.emailTemplate'),\n {\n url,\n user: _.pick(user, ['email', 'firstname', 'lastname', 'username']),\n }\n )\n .catch((err: unknown) => {\n // log error server side but do not disclose it to the user to avoid leaking informations\n strapi.log.error(err);\n });\n};\n\n/**\n * Reset a user password\n * @param resetPasswordToken token generated to request a password reset\n * @param password new user password\n */\nconst resetPassword = async (\n { resetPasswordToken, password } = {} as { resetPasswordToken: string; password: string }\n) => {\n const matchingUser: AdminUser | undefined = await strapi.db\n .query('admin::user')\n .findOne({ where: { resetPasswordToken, isActive: true } });\n\n if (!matchingUser) {\n throw new ApplicationError();\n }\n\n await assertResetPasswordTokenIsValid(matchingUser);\n\n return getService('user').updateById(matchingUser.id, {\n password,\n resetPasswordToken: null,\n resetPasswordTokenExpiresAt: null,\n });\n};\n\nexport default { checkCredentials, validatePassword, hashPassword, forgotPassword, resetPassword };\nexport { getResetPasswordTokenTTL, assignResetPasswordToken, assertResetPasswordTokenIsValid };\n"],"names":["ApplicationError","errors","DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN","getResetPasswordTokenTTL","configured","strapi","config","get","seconds","expiresInToSeconds","assignResetPasswordToken","userId","resetPasswordToken","getService","createToken","resetPasswordTokenExpiresAt","Date","now","updateById","assertResetPasswordTokenIsValid","user","isExpired","getTime","id","hashPassword","password","bcrypt","hash","validatePassword","compare","checkCredentials","email","db","query","findOne","where","message","isValid","isActive","forgotPassword","url","plugin","service","sendTemplatedEmail","to","from","replyTo","_","pick","catch","err","log","error","resetPassword","matchingUser"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"auth.mjs","sources":["../../../../../server/src/services/auth.ts"],"sourcesContent":["import bcrypt from 'bcryptjs';\nimport _ from 'lodash';\nimport { errors, emitAudit } from '@strapi/utils';\nimport { getService } from '../utils';\nimport { expiresInToSeconds } from './token';\nimport { AUDITED_EVENTS, toAdminUserEvent } from '../audit-logs/admin-users';\nimport type { AdminUser } from '../../../shared/contracts/shared';\nimport '@strapi/types';\n\nconst { ApplicationError } = errors;\n\n// Default lifetime of an admin reset-password token. Overridable via\n// `admin.forgotPassword.expiresIn` (number of seconds or a shorthand like '15m', '1h').\nconst DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN = '1h';\n\n/**\n * Resolve the reset-password token lifetime, in milliseconds, from config.\n * Falls back to {@link DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN} for unset/invalid values.\n */\nconst getResetPasswordTokenTTL = (): number => {\n const configured = strapi.config.get(\n 'admin.forgotPassword.expiresIn',\n DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN\n );\n const seconds =\n expiresInToSeconds(configured) ??\n (expiresInToSeconds(DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN) as number);\n return seconds * 1000;\n};\n\n/**\n * Create a reset-password token with an expiry and persist it on the user.\n * Shared by the CE and EE auth services so the expiry behaviour can't drift.\n * @returns the generated reset-password token\n */\nconst assignResetPasswordToken = async (userId: AdminUser['id']): Promise<string> => {\n const resetPasswordToken = getService('token').createToken();\n const resetPasswordTokenExpiresAt = new Date(Date.now() + getResetPasswordTokenTTL());\n\n const user = await getService('user').updateById(userId, {\n resetPasswordToken,\n resetPasswordTokenExpiresAt,\n });\n\n // null when the account was deleted between the caller's lookup and this write\n if (user) {\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_RESET_CREATE, {\n ...toAdminUserEvent(user),\n expiresAt: user.resetPasswordTokenExpiresAt,\n });\n }\n\n return resetPasswordToken;\n};\n\n/**\n * Set the new password and consume the reset token. Shared by the CE and EE auth\n * services, after each has validated the token.\n */\nconst completePasswordReset = async (user: AdminUser, password: string): Promise<AdminUser> => {\n const updatedUser = await getService('user').updateById(user.id, {\n password,\n resetPasswordToken: null,\n resetPasswordTokenExpiresAt: null,\n });\n\n await emitAudit({ strapi }, AUDITED_EVENTS.PASSWORD_RESET_CONFIRM, toAdminUserEvent(updatedUser));\n\n return updatedUser;\n};\n\n/**\n * Reject a reset-password token that has expired — or that has no expiry at all\n * (tokens issued before this was introduced) — clearing the stale token so it\n * cannot be retried. Shared by the CE and EE auth services. (GH#25711)\n */\nconst assertResetPasswordTokenIsValid = async (user: AdminUser): Promise<void> => {\n const { resetPasswordTokenExpiresAt } = user;\n const isExpired =\n !resetPasswordTokenExpiresAt || new Date(resetPasswordTokenExpiresAt).getTime() <= Date.now();\n\n if (isExpired) {\n // Clear the stale token so it can no longer be retried.\n await getService('user').updateById(user.id, {\n resetPasswordToken: null,\n resetPasswordTokenExpiresAt: null,\n });\n throw new ApplicationError('This reset password token has expired');\n }\n};\n\n/**\n * hashes a password\n * @param password - password to hash\n * @returns hashed password\n */\nconst hashPassword = (password: string) => bcrypt.hash(password, 10);\n\n/**\n * Validate a password\n * @param password\n * @param hash\n * @returns {Promise<boolean>} is the password valid\n */\nconst validatePassword = (password: string, hash: string) => bcrypt.compare(password, hash);\n\n/**\n * Check login credentials\n * @param email the users email address\n * @param password the users password\n */\nconst checkCredentials = async ({ email, password }: { email: string; password: string }) => {\n const user: AdminUser = await strapi.db.query('admin::user').findOne({ where: { email } });\n\n if (!user || !user.password) {\n return [null, false, { message: 'Invalid credentials' }];\n }\n\n const isValid = await validatePassword(password, user.password);\n\n if (!isValid) {\n return [null, false, { message: 'Invalid credentials' }];\n }\n\n if (!(user.isActive === true)) {\n return [null, false, { message: 'User not active' }];\n }\n\n return [null, user];\n};\n\n/**\n * Send an email to the user if it exists or do nothing\n * @param email user email for which to reset the password\n */\nconst forgotPassword = async ({ email } = {} as { email: string }) => {\n const user: AdminUser = await strapi.db\n .query('admin::user')\n .findOne({ where: { email, isActive: true } });\n if (!user) {\n return;\n }\n\n const resetPasswordToken = await assignResetPasswordToken(user.id);\n\n // Send an email to the admin.\n const url = `${strapi.config.get(\n 'admin.absoluteUrl'\n )}/auth/reset-password?code=${resetPasswordToken}`;\n\n return strapi\n .plugin('email')\n .service('email')\n .sendTemplatedEmail(\n {\n to: user.email,\n from: strapi.config.get('admin.forgotPassword.from'),\n replyTo: strapi.config.get('admin.forgotPassword.replyTo'),\n },\n strapi.config.get('admin.forgotPassword.emailTemplate'),\n {\n url,\n user: _.pick(user, ['email', 'firstname', 'lastname', 'username']),\n }\n )\n .catch((err: unknown) => {\n // log error server side but do not disclose it to the user to avoid leaking informations\n strapi.log.error(err);\n });\n};\n\n/**\n * Reset a user password\n * @param resetPasswordToken token generated to request a password reset\n * @param password new user password\n */\nconst resetPassword = async (\n { resetPasswordToken, password } = {} as { resetPasswordToken: string; password: string }\n) => {\n const matchingUser: AdminUser | undefined = await strapi.db\n .query('admin::user')\n .findOne({ where: { resetPasswordToken, isActive: true } });\n\n if (!matchingUser) {\n throw new ApplicationError();\n }\n\n await assertResetPasswordTokenIsValid(matchingUser);\n\n return completePasswordReset(matchingUser, password);\n};\n\nexport default { checkCredentials, validatePassword, hashPassword, forgotPassword, resetPassword };\nexport {\n getResetPasswordTokenTTL,\n assignResetPasswordToken,\n assertResetPasswordTokenIsValid,\n completePasswordReset,\n};\n"],"names":["ApplicationError","errors","DEFAULT_RESET_PASSWORD_TOKEN_EXPIRES_IN","getResetPasswordTokenTTL","configured","strapi","config","get","seconds","expiresInToSeconds","assignResetPasswordToken","userId","resetPasswordToken","getService","createToken","resetPasswordTokenExpiresAt","Date","now","user","updateById","emitAudit","AUDITED_EVENTS","PASSWORD_RESET_CREATE","toAdminUserEvent","expiresAt","completePasswordReset","password","updatedUser","id","PASSWORD_RESET_CONFIRM","assertResetPasswordTokenIsValid","isExpired","getTime","hashPassword","bcrypt","hash","validatePassword","compare","checkCredentials","email","db","query","findOne","where","message","isValid","isActive","forgotPassword","url","plugin","service","sendTemplatedEmail","to","from","replyTo","_","pick","catch","err","log","error","resetPassword","matchingUser"],"mappings":"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"}
|