From 5f92b0bbc1af4cf469b5af42ea3341f83e91e61f Mon Sep 17 00:00:00 2001 From: Milo Schwartz Date: Tue, 21 Jan 2025 18:36:50 -0500 Subject: [PATCH] make all emails lowercase closes #89 --- server/lib/config.ts | 6 ++- server/routers/auth/login.ts | 5 ++- server/routers/auth/requestPasswordReset.ts | 10 ++--- server/routers/auth/resetPassword.ts | 5 ++- server/routers/auth/signup.ts | 2 +- server/routers/resource/authWithWhitelist.ts | 5 ++- .../routers/resource/setResourceWhitelist.ts | 5 ++- server/routers/user/inviteUser.ts | 5 ++- server/setup/migrations.ts | 5 ++- server/setup/scripts/1.0.0-beta9.ts | 40 +++++++++++++++++++ 10 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 server/setup/scripts/1.0.0-beta9.ts diff --git a/server/lib/config.ts b/server/lib/config.ts index 49287339..53dac62e 100644 --- a/server/lib/config.ts +++ b/server/lib/config.ts @@ -37,7 +37,8 @@ const configSchema = z.object({ base_domain: hostnameSchema .optional() .transform(getEnvOrYaml("APP_BASEDOMAIN")) - .pipe(hostnameSchema), + .pipe(hostnameSchema) + .transform((url) => url.toLowerCase()), log_level: z.enum(["debug", "info", "warn", "error"]), save_logs: z.boolean() }), @@ -123,7 +124,8 @@ const configSchema = z.object({ .email() .optional() .transform(getEnvOrYaml("USERS_SERVERADMIN_EMAIL")) - .pipe(z.string().email()), + .pipe(z.string().email()) + .transform((v) => v.toLowerCase()), password: passwordSchema .optional() .transform(getEnvOrYaml("USERS_SERVERADMIN_PASSWORD")) diff --git a/server/routers/auth/login.ts b/server/routers/auth/login.ts index 328caeb9..7ee0d927 100644 --- a/server/routers/auth/login.ts +++ b/server/routers/auth/login.ts @@ -20,7 +20,10 @@ import { verifySession } from "@server/auth/sessions/verifySession"; export const loginBodySchema = z .object({ - email: z.string().email(), + email: z + .string() + .email() + .transform((v) => v.toLowerCase()), password: z.string(), code: z.string().optional() }) diff --git a/server/routers/auth/requestPasswordReset.ts b/server/routers/auth/requestPasswordReset.ts index a223e5f2..36cfed87 100644 --- a/server/routers/auth/requestPasswordReset.ts +++ b/server/routers/auth/requestPasswordReset.ts @@ -20,7 +20,10 @@ import { hashPassword } from "@server/auth/password"; export const requestPasswordResetBody = z .object({ - email: z.string().email() + email: z + .string() + .email() + .transform((v) => v.toLowerCase()) }) .strict(); @@ -63,10 +66,7 @@ export async function requestPasswordReset( ); } - const token = generateRandomString( - 8, - alphabet("0-9", "A-Z", "a-z") - ); + const token = generateRandomString(8, alphabet("0-9", "A-Z", "a-z")); await db.transaction(async (trx) => { await trx .delete(passwordResetTokens) diff --git a/server/routers/auth/resetPassword.ts b/server/routers/auth/resetPassword.ts index 6f36d006..45c8652b 100644 --- a/server/routers/auth/resetPassword.ts +++ b/server/routers/auth/resetPassword.ts @@ -19,7 +19,10 @@ import { passwordSchema } from "@server/auth/passwordSchema"; export const resetPasswordBody = z .object({ - email: z.string().email(), + email: z + .string() + .email() + .transform((v) => v.toLowerCase()), token: z.string(), // reset secret code newPassword: passwordSchema, code: z.string().optional() // 2fa code diff --git a/server/routers/auth/signup.ts b/server/routers/auth/signup.ts index 9710d858..2a4bb127 100644 --- a/server/routers/auth/signup.ts +++ b/server/routers/auth/signup.ts @@ -23,7 +23,7 @@ import { checkValidInvite } from "@server/auth/checkValidInvite"; import { passwordSchema } from "@server/auth/passwordSchema"; export const signupBodySchema = z.object({ - email: z.string().email(), + email: z.string().email().transform((v) => v.toLowerCase()), password: passwordSchema, inviteToken: z.string().optional(), inviteId: z.string().optional() diff --git a/server/routers/resource/authWithWhitelist.ts b/server/routers/resource/authWithWhitelist.ts index cc73410c..54c43f62 100644 --- a/server/routers/resource/authWithWhitelist.ts +++ b/server/routers/resource/authWithWhitelist.ts @@ -24,7 +24,10 @@ import logger from "@server/logger"; const authWithWhitelistBodySchema = z .object({ - email: z.string().email(), + email: z + .string() + .email() + .transform((v) => v.toLowerCase()), otp: z.string().optional() }) .strict(); diff --git a/server/routers/resource/setResourceWhitelist.ts b/server/routers/resource/setResourceWhitelist.ts index 5eefbd53..8931d4ff 100644 --- a/server/routers/resource/setResourceWhitelist.ts +++ b/server/routers/resource/setResourceWhitelist.ts @@ -11,7 +11,10 @@ import { and, eq } from "drizzle-orm"; const setResourceWhitelistBodySchema = z .object({ - emails: z.array(z.string().email()).max(50) + emails: z + .array(z.string().email()) + .max(50) + .transform((v) => v.map((e) => e.toLowerCase())) }) .strict(); diff --git a/server/routers/user/inviteUser.ts b/server/routers/user/inviteUser.ts index 3031e399..45240ed2 100644 --- a/server/routers/user/inviteUser.ts +++ b/server/routers/user/inviteUser.ts @@ -23,7 +23,10 @@ const inviteUserParamsSchema = z const inviteUserBodySchema = z .object({ - email: z.string().email(), + email: z + .string() + .email() + .transform((v) => v.toLowerCase()), roleId: z.number(), validHours: z.number().gt(0).lte(168), sendEmail: z.boolean().optional() diff --git a/server/setup/migrations.ts b/server/setup/migrations.ts index 0e9e4819..6d2766ee 100644 --- a/server/setup/migrations.ts +++ b/server/setup/migrations.ts @@ -11,7 +11,7 @@ import m2 from "./scripts/1.0.0-beta2"; import m3 from "./scripts/1.0.0-beta3"; import m4 from "./scripts/1.0.0-beta5"; import m5 from "./scripts/1.0.0-beta6"; -import { existsSync, mkdirSync } from "fs"; +import m6 from "./scripts/1.0.0-beta9"; // THIS CANNOT IMPORT ANYTHING FROM THE SERVER // EXCEPT FOR THE DATABASE AND THE SCHEMA @@ -22,7 +22,8 @@ const migrations = [ { version: "1.0.0-beta.2", run: m2 }, { version: "1.0.0-beta.3", run: m3 }, { version: "1.0.0-beta.5", run: m4 }, - { version: "1.0.0-beta.6", run: m5 } + { version: "1.0.0-beta.6", run: m5 }, + { version: "1.0.0-beta.9", run: m6 } // Add new migrations here as they are created ] as const; diff --git a/server/setup/scripts/1.0.0-beta9.ts b/server/setup/scripts/1.0.0-beta9.ts new file mode 100644 index 00000000..b5bd7838 --- /dev/null +++ b/server/setup/scripts/1.0.0-beta9.ts @@ -0,0 +1,40 @@ +import db from "@server/db"; +import { + emailVerificationCodes, + passwordResetTokens, + resourceOtp, + resourceWhitelist, + userInvites, + users +} from "@server/db/schema"; +import { sql } from "drizzle-orm"; + +export default async function migration() { + console.log("Running setup script 1.0.0-beta.9..."); + + try { + await db.transaction(async (trx) => { + await db.transaction(async (trx) => { + trx.run(sql`UPDATE ${users} SET email = LOWER(email);`); + trx.run( + sql`UPDATE ${emailVerificationCodes} SET email = LOWER(email);` + ); + trx.run( + sql`UPDATE ${passwordResetTokens} SET email = LOWER(email);` + ); + trx.run(sql`UPDATE ${userInvites} SET email = LOWER(email);`); + trx.run( + sql`UPDATE ${resourceWhitelist} SET email = LOWER(email);` + ); + trx.run(sql`UPDATE ${resourceOtp} SET email = LOWER(email);`); + }); + }); + } catch (error) { + console.log( + "We were unable to make all emails lower case in the database." + ); + console.error(error); + } + + console.log("Done."); +}