From f6647cd0750decfbb31e51c3896020aa5ec00685 Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Tue, 5 May 2026 20:14:18 +0200 Subject: [PATCH] prevent duplicate email registering --- migrations/f0ckm_schema.sql | 8 ++++++++ src/inc/config.mjs | 10 +++++----- src/inc/routes/apiv2/settings.mjs | 17 +++++++++++++++-- src/inc/routes/register.mjs | 18 ++++++++++++++++-- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/migrations/f0ckm_schema.sql b/migrations/f0ckm_schema.sql index 77085f1..225bf52 100644 --- a/migrations/f0ckm_schema.sql +++ b/migrations/f0ckm_schema.sql @@ -1962,6 +1962,14 @@ ALTER TABLE ONLY public."user" ADD CONSTRAINT user_name_unique UNIQUE ("user"); +-- +-- Name: user user_email_unique; Type: CONSTRAINT; Schema: public; Owner: f0ckm +-- + +ALTER TABLE ONLY public."user" + ADD CONSTRAINT user_email_unique UNIQUE (email); + + -- -- Name: user_options user_options_user_id; Type: CONSTRAINT; Schema: public; Owner: f0ckm -- diff --git a/src/inc/config.mjs b/src/inc/config.mjs index fb238a2..561ee54 100644 --- a/src/inc/config.mjs +++ b/src/inc/config.mjs @@ -6,11 +6,11 @@ import { fileURLToPath } from "url"; let config = JSON.parse(JSON.stringify(_config)); // Environment variable overrides for database connection -if (process.env.DB_HOST) config.sql.host = process.env.DB_HOST; -if (process.env.DB_PORT) config.sql.port = parseInt(process.env.DB_PORT, 10); -if (process.env.DB_USER) config.sql.user = process.env.DB_USER; -if (process.env.DB_PASS) config.sql.password = process.env.DB_PASS; -if (process.env.DB_NAME) config.sql.database = process.env.DB_NAME; +config.sql.host = process.env.DB_HOST || process.env.POSTGRES_HOST || process.env.PGHOST || config.sql.host; +config.sql.port = parseInt(process.env.DB_PORT || process.env.POSTGRES_PORT || process.env.PGPORT || config.sql.port, 10); +config.sql.user = process.env.DB_USER || process.env.POSTGRES_USER || process.env.PGUSER || config.sql.user; +config.sql.password = process.env.DB_PASS || process.env.POSTGRES_PASSWORD || process.env.PGPASSWORD || config.sql.password; +config.sql.database = process.env.DB_NAME || process.env.POSTGRES_DB || process.env.PGDATABASE || config.sql.database; if (process.env.NODE_ENV === 'production') { config.main.development = false; diff --git a/src/inc/routes/apiv2/settings.mjs b/src/inc/routes/apiv2/settings.mjs index aa8e02b..947814a 100644 --- a/src/inc/routes/apiv2/settings.mjs +++ b/src/inc/routes/apiv2/settings.mjs @@ -382,9 +382,22 @@ export default router => { group.put(/\/email/, lib.loggedin, async (req, res) => { const { email } = req.post; if (!email || !email.trim()) return res.json({ success: false, msg: 'Email is required' }, 400); - if (!email.includes('@')) return res.json({ success: false, msg: 'Invalid email address' }, 400); + const cleanEmail = email.trim(); + if (!cleanEmail.includes('@')) return res.json({ success: false, msg: 'Invalid email address' }, 400); - await db`update "user" set email = ${email.trim()} where id = ${+req.session.id}`; + // Check if email is already taken by another user + const existing = await db` + select id from "user" + where lower(email) = lower(${cleanEmail}) + and id != ${+req.session.id} + limit 1 + `; + + if (existing.length > 0) { + return res.json({ success: false, msg: 'Email already in use' }, 400); + } + + await db`update "user" set email = ${cleanEmail} where id = ${+req.session.id}`; return res.json({ success: true, msg: 'Email updated successfully' }, 200); }); diff --git a/src/inc/routes/register.mjs b/src/inc/routes/register.mjs index 73a6aa5..03f6c67 100644 --- a/src/inc/routes/register.mjs +++ b/src/inc/routes/register.mjs @@ -110,8 +110,22 @@ export default (router, tpl) => { } // Check user existence - const existing = await db`select id from "user" where "login" = ${username.toLowerCase()} or "user" = ${username}`; - if (existing.length > 0) return renderError("Username taken"); + const existing = await db` + select id, login, email + from "user" + where "login" = ${username.toLowerCase()} + or "user" = ${username} + or ("email" is not null and "email" = ${email}) + `; + + if (existing.length > 0) { + // Check if it was the email that matched + const emailMatch = existing.find(u => u.email && u.email.toLowerCase() === (email || '').toLowerCase()); + if (emailMatch) { + return renderError("Email already registered"); + } + return renderError("Username taken"); + } // Create User const hash = await lib.hash(password);