UNPKG

better-auth

Version:

The most comprehensive authentication framework for TypeScript.

1 lines • 39.7 kB
{"version":3,"file":"update-user.mjs","names":["account","token","url"],"sources":["../../../src/api/routes/update-user.ts"],"sourcesContent":["import type { BetterAuthOptions } from \"@better-auth/core\";\nimport { createAuthEndpoint } from \"@better-auth/core/api\";\nimport { BASE_ERROR_CODES } from \"@better-auth/core/error\";\nimport { APIError } from \"better-call\";\nimport * as z from \"zod\";\nimport { deleteSessionCookie, setSessionCookie } from \"../../cookies\";\nimport { generateRandomString } from \"../../crypto\";\nimport { parseUserInput } from \"../../db/schema\";\nimport type { AdditionalUserFieldsInput } from \"../../types\";\nimport { originCheck } from \"../middlewares\";\nimport { createEmailVerificationToken } from \"./email-verification\";\nimport {\n\tgetSessionFromCtx,\n\tsensitiveSessionMiddleware,\n\tsessionMiddleware,\n} from \"./session\";\n\nconst updateUserBodySchema = z.record(\n\tz.string().meta({\n\t\tdescription: \"Field name must be a string\",\n\t}),\n\tz.any(),\n);\n\nexport const updateUser = <O extends BetterAuthOptions>() =>\n\tcreateAuthEndpoint(\n\t\t\"/update-user\",\n\t\t{\n\t\t\tmethod: \"POST\",\n\t\t\toperationId: \"updateUser\",\n\t\t\tbody: updateUserBodySchema,\n\t\t\tuse: [sessionMiddleware],\n\t\t\tmetadata: {\n\t\t\t\t$Infer: {\n\t\t\t\t\tbody: {} as Partial<AdditionalUserFieldsInput<O>> & {\n\t\t\t\t\t\tname?: string | undefined;\n\t\t\t\t\t\timage?: string | undefined | null;\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\topenapi: {\n\t\t\t\t\toperationId: \"updateUser\",\n\t\t\t\t\tdescription: \"Update the current user\",\n\t\t\t\t\trequestBody: {\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tname: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"The image of the user\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\tresponses: {\n\t\t\t\t\t\t\"200\": {\n\t\t\t\t\t\t\tdescription: \"Success\",\n\t\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t\tasync (ctx) => {\n\t\t\tconst body = ctx.body as {\n\t\t\t\tname?: string | undefined;\n\t\t\t\timage?: string | undefined;\n\t\t\t\t[key: string]: any;\n\t\t\t};\n\n\t\t\tif (typeof body !== \"object\" || Array.isArray(body)) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"Body must be an object\",\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (body.email) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: BASE_ERROR_CODES.EMAIL_CAN_NOT_BE_UPDATED,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst { name, image, ...rest } = body;\n\t\t\tconst session = ctx.context.session;\n\t\t\tconst additionalFields = parseUserInput(\n\t\t\t\tctx.context.options,\n\t\t\t\trest,\n\t\t\t\t\"update\",\n\t\t\t);\n\t\t\tif (\n\t\t\t\timage === undefined &&\n\t\t\t\tname === undefined &&\n\t\t\t\tObject.keys(additionalFields).length === 0\n\t\t\t) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: \"No fields to update\",\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst user = await ctx.context.internalAdapter.updateUser(\n\t\t\t\tsession.user.id,\n\t\t\t\t{\n\t\t\t\t\tname,\n\t\t\t\t\timage,\n\t\t\t\t\t...additionalFields,\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst updatedUser = user ?? {\n\t\t\t\t...session.user,\n\t\t\t\t...(name !== undefined && { name }),\n\t\t\t\t...(image !== undefined && { image }),\n\t\t\t\t...additionalFields,\n\t\t\t};\n\t\t\t/**\n\t\t\t * Update the session cookie with the new user data\n\t\t\t */\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: session.session,\n\t\t\t\tuser: updatedUser,\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t},\n\t);\n\nexport const changePassword = createAuthEndpoint(\n\t\"/change-password\",\n\t{\n\t\tmethod: \"POST\",\n\t\toperationId: \"changePassword\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The new password to set\n\t\t\t */\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * The current password of the user\n\t\t\t */\n\t\t\tcurrentPassword: z.string().meta({\n\t\t\t\tdescription: \"The current password is required\",\n\t\t\t}),\n\t\t\t/**\n\t\t\t * revoke all sessions that are not the\n\t\t\t * current one logged in by the user\n\t\t\t */\n\t\t\trevokeOtherSessions: z\n\t\t\t\t.boolean()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"Must be a boolean value\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"changePassword\",\n\t\t\t\tdescription: \"Change the password of the user\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Password successfully changed\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true, // Only present if revokeOtherSessions is true\n\t\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\t\"New session token if other sessions were revoked\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\t\t\tid: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The unique identifier of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\temail: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The email address of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tname: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The name of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\timage: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"uri\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"The profile image URL of the user\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\temailVerified: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"Whether the email has been verified\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tcreatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was created\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t\tupdatedAt: {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tformat: \"date-time\",\n\t\t\t\t\t\t\t\t\t\t\t\t\tdescription: \"When the user was last updated\",\n\t\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\t\trequired: [\n\t\t\t\t\t\t\t\t\t\t\t\t\"id\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"email\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"name\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"emailVerified\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"createdAt\",\n\t\t\t\t\t\t\t\t\t\t\t\t\"updatedAt\",\n\t\t\t\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"user\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tconst { newPassword, currentPassword, revokeOtherSessions } = ctx.body;\n\t\tconst session = ctx.context.session;\n\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\tif (newPassword.length < minPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.PASSWORD_TOO_SHORT,\n\t\t\t});\n\t\t}\n\n\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\n\t\tif (newPassword.length > maxPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.PASSWORD_TOO_LONG,\n\t\t\t});\n\t\t}\n\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst account = accounts.find(\n\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t);\n\t\tif (!account || !account.password) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND,\n\t\t\t});\n\t\t}\n\t\tconst passwordHash = await ctx.context.password.hash(newPassword);\n\t\tconst verify = await ctx.context.password.verify({\n\t\t\thash: account.password,\n\t\t\tpassword: currentPassword,\n\t\t});\n\t\tif (!verify) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.INVALID_PASSWORD,\n\t\t\t});\n\t\t}\n\t\tawait ctx.context.internalAdapter.updateAccount(account.id, {\n\t\t\tpassword: passwordHash,\n\t\t});\n\t\tlet token = null;\n\t\tif (revokeOtherSessions) {\n\t\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\t\tconst newSession = await ctx.context.internalAdapter.createSession(\n\t\t\t\tsession.user.id,\n\t\t\t);\n\t\t\tif (!newSession) {\n\t\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\t\tmessage: BASE_ERROR_CODES.FAILED_TO_GET_SESSION,\n\t\t\t\t});\n\t\t\t}\n\t\t\t// set the new session cookie\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: newSession,\n\t\t\t\tuser: session.user,\n\t\t\t});\n\t\t\ttoken = newSession.token;\n\t\t}\n\n\t\treturn ctx.json({\n\t\t\ttoken,\n\t\t\tuser: {\n\t\t\t\tid: session.user.id,\n\t\t\t\temail: session.user.email,\n\t\t\t\tname: session.user.name,\n\t\t\t\timage: session.user.image,\n\t\t\t\temailVerified: session.user.emailVerified,\n\t\t\t\tcreatedAt: session.user.createdAt,\n\t\t\t\tupdatedAt: session.user.updatedAt,\n\t\t\t},\n\t\t});\n\t},\n);\n\nexport const setPassword = createAuthEndpoint(\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The new password to set\n\t\t\t */\n\t\t\tnewPassword: z.string().meta({\n\t\t\t\tdescription: \"The new password to set is required\",\n\t\t\t}),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t},\n\tasync (ctx) => {\n\t\tconst { newPassword } = ctx.body;\n\t\tconst session = ctx.context.session;\n\t\tconst minPasswordLength = ctx.context.password.config.minPasswordLength;\n\t\tif (newPassword.length < minPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too short\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.PASSWORD_TOO_SHORT,\n\t\t\t});\n\t\t}\n\n\t\tconst maxPasswordLength = ctx.context.password.config.maxPasswordLength;\n\n\t\tif (newPassword.length > maxPasswordLength) {\n\t\t\tctx.context.logger.error(\"Password is too long\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.PASSWORD_TOO_LONG,\n\t\t\t});\n\t\t}\n\n\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\tsession.user.id,\n\t\t);\n\t\tconst account = accounts.find(\n\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t);\n\t\tconst passwordHash = await ctx.context.password.hash(newPassword);\n\t\tif (!account) {\n\t\t\tawait ctx.context.internalAdapter.linkAccount({\n\t\t\t\tuserId: session.user.id,\n\t\t\t\tproviderId: \"credential\",\n\t\t\t\taccountId: session.user.id,\n\t\t\t\tpassword: passwordHash,\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\tmessage: \"user already has a password\",\n\t\t});\n\t},\n);\n\nexport const deleteUser = createAuthEndpoint(\n\t\"/delete-user\",\n\t{\n\t\tmethod: \"POST\",\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tbody: z.object({\n\t\t\t/**\n\t\t\t * The callback URL to redirect to after the user is deleted\n\t\t\t * this is only used on delete user callback\n\t\t\t */\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The callback URL to redirect to after the user is deleted\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * The password of the user. If the password isn't provided, session freshness\n\t\t\t * will be checked.\n\t\t\t */\n\t\t\tpassword: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"The password of the user is required to delete the user\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t\t/**\n\t\t\t * The token to delete the user. If the token is provided, the user will be deleted\n\t\t\t */\n\t\t\ttoken: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The token to delete the user is required\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"deleteUser\",\n\t\t\t\tdescription: \"Delete the user\",\n\t\t\t\trequestBody: {\n\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\tcallbackURL: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\"The callback URL to redirect to after the user is deleted\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\tpassword: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\t\t\t\t\"The user's password. Required if session is not fresh\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\ttoken: {\n\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\tdescription: \"The deletion verification token\",\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"User deletion processed successfully\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tsuccess: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the operation was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"User deleted\", \"Verification email sent\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Status message of the deletion process\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"success\", \"message\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.deleteUser?.enabled) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Delete user is disabled. Enable it in the options\",\n\t\t\t);\n\t\t\tthrow new APIError(\"NOT_FOUND\");\n\t\t}\n\t\tconst session = ctx.context.session;\n\n\t\tif (ctx.body.password) {\n\t\t\tconst accounts = await ctx.context.internalAdapter.findAccounts(\n\t\t\t\tsession.user.id,\n\t\t\t);\n\t\t\tconst account = accounts.find(\n\t\t\t\t(account) => account.providerId === \"credential\" && account.password,\n\t\t\t);\n\t\t\tif (!account || !account.password) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: BASE_ERROR_CODES.CREDENTIAL_ACCOUNT_NOT_FOUND,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst verify = await ctx.context.password.verify({\n\t\t\t\thash: account.password,\n\t\t\t\tpassword: ctx.body.password,\n\t\t\t});\n\t\t\tif (!verify) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: BASE_ERROR_CODES.INVALID_PASSWORD,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (ctx.body.token) {\n\t\t\t//@ts-expect-error\n\t\t\tawait deleteUserCallback({\n\t\t\t\t...ctx,\n\t\t\t\tquery: {\n\t\t\t\t\ttoken: ctx.body.token,\n\t\t\t\t},\n\t\t\t});\n\t\t\treturn ctx.json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: \"User deleted\",\n\t\t\t});\n\t\t}\n\n\t\tif (ctx.context.options.user.deleteUser?.sendDeleteAccountVerification) {\n\t\t\tconst token = generateRandomString(32, \"0-9\", \"a-z\");\n\t\t\tawait ctx.context.internalAdapter.createVerificationValue({\n\t\t\t\tvalue: session.user.id,\n\t\t\t\tidentifier: `delete-account-${token}`,\n\t\t\t\texpiresAt: new Date(\n\t\t\t\t\tDate.now() +\n\t\t\t\t\t\t(ctx.context.options.user.deleteUser?.deleteTokenExpiresIn ||\n\t\t\t\t\t\t\t60 * 60 * 24) *\n\t\t\t\t\t\t\t1000,\n\t\t\t\t),\n\t\t\t});\n\t\t\tconst url = `${\n\t\t\t\tctx.context.baseURL\n\t\t\t}/delete-user/callback?token=${token}&callbackURL=${\n\t\t\t\tctx.body.callbackURL || \"/\"\n\t\t\t}`;\n\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\tctx.context.options.user.deleteUser.sendDeleteAccountVerification(\n\t\t\t\t\t{\n\t\t\t\t\t\tuser: session.user,\n\t\t\t\t\t\turl,\n\t\t\t\t\t\ttoken,\n\t\t\t\t\t},\n\t\t\t\t\tctx.request,\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn ctx.json({\n\t\t\t\tsuccess: true,\n\t\t\t\tmessage: \"Verification email sent\",\n\t\t\t});\n\t\t}\n\n\t\tif (!ctx.body.password && ctx.context.sessionConfig.freshAge !== 0) {\n\t\t\tconst currentAge = new Date(session.session.createdAt).getTime();\n\t\t\tconst freshAge = ctx.context.sessionConfig.freshAge * 1000;\n\t\t\tconst now = Date.now();\n\t\t\tif (now - currentAge > freshAge * 1000) {\n\t\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\t\tmessage: BASE_ERROR_CODES.SESSION_EXPIRED,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;\n\t\tif (beforeDelete) {\n\t\t\tawait beforeDelete(session.user, ctx.request);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteUser(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\tdeleteSessionCookie(ctx);\n\t\tconst afterDelete = ctx.context.options.user.deleteUser?.afterDelete;\n\t\tif (afterDelete) {\n\t\t\tawait afterDelete(session.user, ctx.request);\n\t\t}\n\t\treturn ctx.json({\n\t\t\tsuccess: true,\n\t\t\tmessage: \"User deleted\",\n\t\t});\n\t},\n);\n\nexport const deleteUserCallback = createAuthEndpoint(\n\t\"/delete-user/callback\",\n\t{\n\t\tmethod: \"GET\",\n\t\tquery: z.object({\n\t\t\ttoken: z.string().meta({\n\t\t\t\tdescription: \"The token to verify the deletion request\",\n\t\t\t}),\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The URL to redirect to after deletion\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [originCheck((ctx) => ctx.query.callbackURL)],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\tdescription:\n\t\t\t\t\t\"Callback to complete user deletion with verification token\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"User successfully deleted\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tsuccess: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the deletion was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"User deleted\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Confirmation message\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"success\", \"message\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.deleteUser?.enabled) {\n\t\t\tctx.context.logger.error(\n\t\t\t\t\"Delete user is disabled. Enable it in the options\",\n\t\t\t);\n\t\t\tthrow new APIError(\"NOT_FOUND\");\n\t\t}\n\t\tconst session = await getSessionFromCtx(ctx);\n\t\tif (!session) {\n\t\t\tthrow new APIError(\"NOT_FOUND\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.FAILED_TO_GET_USER_INFO,\n\t\t\t});\n\t\t}\n\t\tconst token = await ctx.context.internalAdapter.findVerificationValue(\n\t\t\t`delete-account-${ctx.query.token}`,\n\t\t);\n\t\tif (!token || token.expiresAt < new Date()) {\n\t\t\tthrow new APIError(\"NOT_FOUND\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.INVALID_TOKEN,\n\t\t\t});\n\t\t}\n\t\tif (token.value !== session.user.id) {\n\t\t\tthrow new APIError(\"NOT_FOUND\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.INVALID_TOKEN,\n\t\t\t});\n\t\t}\n\t\tconst beforeDelete = ctx.context.options.user.deleteUser?.beforeDelete;\n\t\tif (beforeDelete) {\n\t\t\tawait beforeDelete(session.user, ctx.request);\n\t\t}\n\t\tawait ctx.context.internalAdapter.deleteUser(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteSessions(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteAccounts(session.user.id);\n\t\tawait ctx.context.internalAdapter.deleteVerificationValue(token.id);\n\n\t\tdeleteSessionCookie(ctx);\n\n\t\tconst afterDelete = ctx.context.options.user.deleteUser?.afterDelete;\n\t\tif (afterDelete) {\n\t\t\tawait afterDelete(session.user, ctx.request);\n\t\t}\n\t\tif (ctx.query.callbackURL) {\n\t\t\tthrow ctx.redirect(ctx.query.callbackURL || \"/\");\n\t\t}\n\t\treturn ctx.json({\n\t\t\tsuccess: true,\n\t\t\tmessage: \"User deleted\",\n\t\t});\n\t},\n);\n\nexport const changeEmail = createAuthEndpoint(\n\t\"/change-email\",\n\t{\n\t\tmethod: \"POST\",\n\t\tbody: z.object({\n\t\t\tnewEmail: z.email().meta({\n\t\t\t\tdescription:\n\t\t\t\t\t\"The new email address to set must be a valid email address\",\n\t\t\t}),\n\t\t\tcallbackURL: z\n\t\t\t\t.string()\n\t\t\t\t.meta({\n\t\t\t\t\tdescription: \"The URL to redirect to after email verification\",\n\t\t\t\t})\n\t\t\t\t.optional(),\n\t\t}),\n\t\tuse: [sensitiveSessionMiddleware],\n\t\tmetadata: {\n\t\t\topenapi: {\n\t\t\t\toperationId: \"changeEmail\",\n\t\t\t\tresponses: {\n\t\t\t\t\t\"200\": {\n\t\t\t\t\t\tdescription: \"Email change request processed successfully\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\t\t\t$ref: \"#/components/schemas/User\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tstatus: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"boolean\",\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Indicates if the request was successful\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t\tenum: [\"Email updated\", \"Verification email sent\"],\n\t\t\t\t\t\t\t\t\t\t\tdescription: \"Status message of the email change process\",\n\t\t\t\t\t\t\t\t\t\t\tnullable: true,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\trequired: [\"status\"],\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t\t\"422\": {\n\t\t\t\t\t\tdescription: \"Unprocessable Entity. Email already exists\",\n\t\t\t\t\t\tcontent: {\n\t\t\t\t\t\t\t\"application/json\": {\n\t\t\t\t\t\t\t\tschema: {\n\t\t\t\t\t\t\t\t\ttype: \"object\",\n\t\t\t\t\t\t\t\t\tproperties: {\n\t\t\t\t\t\t\t\t\t\tmessage: {\n\t\t\t\t\t\t\t\t\t\t\ttype: \"string\",\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t},\n\t},\n\tasync (ctx) => {\n\t\tif (!ctx.context.options.user?.changeEmail?.enabled) {\n\t\t\tctx.context.logger.error(\"Change email is disabled.\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Change email is disabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst newEmail = ctx.body.newEmail.toLowerCase();\n\n\t\tif (newEmail === ctx.context.session.user.email) {\n\t\t\tctx.context.logger.error(\"Email is the same\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Email is the same\",\n\t\t\t});\n\t\t}\n\t\tconst existingUser =\n\t\t\tawait ctx.context.internalAdapter.findUserByEmail(newEmail);\n\t\tif (existingUser) {\n\t\t\tctx.context.logger.error(\"Email already exists\");\n\t\t\tthrow new APIError(\"UNPROCESSABLE_ENTITY\", {\n\t\t\t\tmessage: BASE_ERROR_CODES.USER_ALREADY_EXISTS_USE_ANOTHER_EMAIL,\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * If the email is not verified, we can update the email if the option is enabled\n\t\t */\n\t\tif (\n\t\t\tctx.context.session.user.emailVerified !== true &&\n\t\t\tctx.context.options.user.changeEmail.updateEmailWithoutVerification\n\t\t) {\n\t\t\tawait ctx.context.internalAdapter.updateUserByEmail(\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\t{\n\t\t\t\t\temail: newEmail,\n\t\t\t\t},\n\t\t\t);\n\t\t\tawait setSessionCookie(ctx, {\n\t\t\t\tsession: ctx.context.session.session,\n\t\t\t\tuser: {\n\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\temail: newEmail,\n\t\t\t\t},\n\t\t\t});\n\t\t\tif (ctx.context.options.emailVerification?.sendVerificationEmail) {\n\t\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\t\tctx.context.secret,\n\t\t\t\t\tnewEmail,\n\t\t\t\t\tundefined,\n\t\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t);\n\t\t\t\tconst url = `${\n\t\t\t\t\tctx.context.baseURL\n\t\t\t\t}/verify-email?token=${token}&callbackURL=${\n\t\t\t\t\tctx.body.callbackURL || \"/\"\n\t\t\t\t}`;\n\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\tctx.context.options.emailVerification.sendVerificationEmail(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuser: {\n\t\t\t\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\t\t\t\temail: newEmail,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx.request,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\n\t\t/**\n\t\t * If the email is verified, we need to send a verification email\n\t\t */\n\t\tconst sendConfirmationToOldEmail =\n\t\t\tctx.context.session.user.emailVerified &&\n\t\t\t(ctx.context.options.user.changeEmail.sendChangeEmailConfirmation ||\n\t\t\t\tctx.context.options.user.changeEmail.sendChangeEmailVerification);\n\n\t\tif (sendConfirmationToOldEmail) {\n\t\t\tconst token = await createEmailVerificationToken(\n\t\t\t\tctx.context.secret,\n\t\t\t\tctx.context.session.user.email,\n\t\t\t\tnewEmail,\n\t\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t\t{\n\t\t\t\t\trequestType: \"change-email-confirmation\",\n\t\t\t\t},\n\t\t\t);\n\t\t\tconst url = `${\n\t\t\t\tctx.context.baseURL\n\t\t\t}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || \"/\"}`;\n\t\t\tconst sendFn =\n\t\t\t\tctx.context.options.user.changeEmail.sendChangeEmailConfirmation ||\n\t\t\t\tctx.context.options.user.changeEmail.sendChangeEmailVerification;\n\t\t\tif (sendFn) {\n\t\t\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\t\t\tsendFn(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tuser: ctx.context.session.user,\n\t\t\t\t\t\t\tnewEmail: newEmail,\n\t\t\t\t\t\t\turl,\n\t\t\t\t\t\t\ttoken,\n\t\t\t\t\t\t},\n\t\t\t\t\t\tctx.request,\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn ctx.json({\n\t\t\t\tstatus: true,\n\t\t\t});\n\t\t}\n\n\t\tif (!ctx.context.options.emailVerification?.sendVerificationEmail) {\n\t\t\tctx.context.logger.error(\"Verification email isn't enabled.\");\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: \"Verification email isn't enabled\",\n\t\t\t});\n\t\t}\n\n\t\tconst token = await createEmailVerificationToken(\n\t\t\tctx.context.secret,\n\t\t\tctx.context.session.user.email,\n\t\t\tnewEmail,\n\t\t\tctx.context.options.emailVerification?.expiresIn,\n\t\t\t{\n\t\t\t\trequestType: \"change-email-verification\",\n\t\t\t},\n\t\t);\n\t\tconst url = `${\n\t\t\tctx.context.baseURL\n\t\t}/verify-email?token=${token}&callbackURL=${ctx.body.callbackURL || \"/\"}`;\n\t\tawait ctx.context.runInBackgroundOrAwait(\n\t\t\tctx.context.options.emailVerification.sendVerificationEmail(\n\t\t\t\t{\n\t\t\t\t\tuser: {\n\t\t\t\t\t\t...ctx.context.session.user,\n\t\t\t\t\t\temail: newEmail,\n\t\t\t\t\t},\n\t\t\t\t\turl,\n\t\t\t\t\ttoken,\n\t\t\t\t},\n\t\t\t\tctx.request,\n\t\t\t),\n\t\t);\n\t\treturn ctx.json({\n\t\t\tstatus: true,\n\t\t});\n\t},\n);\n"],"mappings":"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"}