UNPKG

studiocms

Version:

Astro Native CMS for AstroDB. Built from the ground up by the Astro community.

114 lines (93 loc) 3.39 kB
import { Password } from 'studiocms:auth/lib'; import { developerConfig } from 'studiocms:config'; import { apiResponseLogger } from 'studiocms:logger'; import { Notifications } from 'studiocms:notifier'; import { SDKCore } from 'studiocms:sdk'; import { AllResponse, createEffectAPIRoutes, createJsonResponse, Effect, genLogger, OptionsResponse, readAPIContextJson, } from '../../../effect.js'; export const { POST, OPTIONS, ALL } = createEffectAPIRoutes( { POST: (ctx) => genLogger('studiocms/routes/api/dashboard/reset-password.POST')(function* () { const [notify, sdk, pass] = yield* Effect.all([Notifications, SDKCore, Password]); // Check if demo mode is enabled if (developerConfig.demoMode !== false) { return apiResponseLogger(403, 'Demo mode is enabled, this action is not allowed.'); } const { token, id, userid, password, confirm_password } = yield* readAPIContextJson<{ token: string; id: string; userid: string; password: string; confirm_password: string; }>(ctx); if (!token) { return apiResponseLogger(400, 'Invalid form data, token is required'); } if (!id) { return apiResponseLogger(400, 'Invalid form data, id is required'); } if (!userid) { return apiResponseLogger(400, 'Invalid form data, userid is required'); } if (!password) { return apiResponseLogger(400, 'Invalid form data, password is required'); } if (!confirm_password) { return apiResponseLogger(400, 'Invalid form data, confirm_password is required'); } if (password !== confirm_password) { return apiResponseLogger(400, 'Passwords do not match'); } // If the password is invalid, return an error const verifyPasswordResponse = yield* pass.verifyPasswordStrength(password); if (verifyPasswordResponse !== true) { return apiResponseLogger(400, verifyPasswordResponse); } const hashedPassword = yield* pass.hashPassword(password); // Verify the reset token and derive the userId from it const isTokenValid = yield* sdk.resetTokenBucket.check(token); if (!isTokenValid) { return apiResponseLogger(403, 'Invalid or expired reset token'); } const tokenInfo = yield* sdk.testToken(token); if (!tokenInfo || !tokenInfo.userId) { return apiResponseLogger(403, 'Invalid or expired reset token'); } const targetUserId = tokenInfo.userId as string; const userUpdate = { password: hashedPassword }; const userData = yield* sdk.GET.users.byId(targetUserId); if (!userData) { return apiResponseLogger(404, 'User not found'); } yield* sdk.AUTH.user.update(targetUserId, userUpdate); yield* Effect.all([ sdk.resetTokenBucket.delete(targetUserId), notify.sendUserNotification('account_updated', targetUserId), notify.sendAdminNotification('user_updated', userData.username), ]); return apiResponseLogger(200, 'User password updated successfully'); }).pipe(Notifications.Provide), OPTIONS: () => Effect.try(() => OptionsResponse({ allowedMethods: ['POST'] })), ALL: () => Effect.try(() => AllResponse()), }, { cors: { methods: ['POST', 'OPTIONS'] }, onError: (error) => { console.error('API Error:', error); return createJsonResponse( { error: 'Internal Server Error' }, { status: 500, } ); }, } );