aegis-auth
Version:
A credentials-based auth solution for Next.js (and other Node projects) with IP rate-limiting, account lockouts, and sessions in DB.
97 lines • 3.65 kB
JavaScript
import { VerificationType } from "@prisma/client";
import { sendVerificationEmail } from "../emails";
import { ErrorCodes, } from "../types";
import { limitIpAttempts } from "../utils";
import { initiateEmailChangeSchema } from "../validations";
import { createVerification } from "./createVerification";
export async function initiateEmailChange(context, input) {
var _a;
const { prisma, config, limiters, parsedRequest } = context;
const { ipAddress } = parsedRequest !== null && parsedRequest !== void 0 ? parsedRequest : {};
try {
const validatedInput = initiateEmailChangeSchema.safeParse(input);
if (!validatedInput.success) {
config.logger.securityEvent("INVALID_INPUT", {
route: "initiateEmailChange",
ipAddress,
});
return {
success: false,
status: 400,
message: "Invalid input provided",
code: ErrorCodes.INVALID_INPUT,
};
}
const { userId, newEmail } = validatedInput.data;
if (config.rateLimiting.initiateEmailChange.enabled && ipAddress) {
const limiter = limiters.initiateEmailChange;
const limit = await limitIpAttempts({ ipAddress, limiter });
if (!limit.success) {
config.logger.securityEvent("RATE_LIMIT_EXCEEDED", {
route: "initiateEmailChange",
ipAddress,
});
return {
success: false,
status: 429,
message: "Too many attempts. Try again later.",
code: ErrorCodes.RATE_LIMIT_EXCEEDED,
};
}
}
const existingUser = (await prisma.user.findFirst({
where: {
OR: [{ email: newEmail }, { pendingEmail: newEmail }],
},
}));
if (existingUser) {
return {
success: false,
status: 400,
message: "Email is already in use",
code: ErrorCodes.EMAIL_IN_USE,
};
}
await prisma.user.update({
where: { id: userId },
data: { pendingEmail: newEmail },
});
const verification = await createVerification(context, {
userId,
type: VerificationType.EMAIL_CHANGE,
});
if (!verification.success || !((_a = verification.data) === null || _a === void 0 ? void 0 : _a.verification)) {
return {
success: false,
status: 500,
message: "Failed to create email change verification.",
code: ErrorCodes.INTERNAL_SERVER_ERROR,
};
}
const { token } = verification.data.verification;
await sendVerificationEmail({
toEmail: newEmail,
token,
config: context.config,
});
return {
success: true,
status: 200,
message: "Verification email sent to your new email address.",
};
}
catch (error) {
config.logger.error("Error initiating email change", {
error,
email: input.newEmail,
ipAddress: parsedRequest === null || parsedRequest === void 0 ? void 0 : parsedRequest.ipAddress,
});
return {
success: false,
status: 500,
message: "An unexpected error occurred.",
code: ErrorCodes.INTERNAL_SERVER_ERROR,
};
}
}
//# sourceMappingURL=initiateEmailChange.js.map