From d2a11a800466f19417dc8fe4fc67bcb009928b30 Mon Sep 17 00:00:00 2001 From: adueck Date: Sun, 17 Dec 2023 10:47:00 +0400 Subject: [PATCH] beta trying better practice making sure an e-mail address works before creating the account --- account/src/lib/mail-utils.ts | 99 ++++---- account/src/lib/user-utils.ts | 360 ++++++++++++++++------------- account/src/routers/api-router.ts | 264 +++++++++++---------- account/src/routers/auth-router.ts | 34 ++- account/views/login.ejs | 2 +- 5 files changed, 420 insertions(+), 339 deletions(-) diff --git a/account/src/lib/mail-utils.ts b/account/src/lib/mail-utils.ts index 182b8d5..949ab8b 100644 --- a/account/src/lib/mail-utils.ts +++ b/account/src/lib/mail-utils.ts @@ -3,68 +3,83 @@ import inProd from "./inProd"; import env from "./env-vars"; import * as T from "../../../website/src/types/account-types"; -type Address = string | { name: string, address: string }; +type Address = string | { name: string; address: string }; const adminAddress: Address = { - name: "LingDocs Admin", - address: "admin@lingdocs.com", + name: "LingDocs Admin", + address: "admin@lingdocs.com", }; -function getAddress(user: T.LingdocsUser): Address { - // TODO: Guard against "" - if (!user.name) return user.email || ""; - return { - name: user.name, - address: user.email || "", - }; +export function getAddress(user: T.LingdocsUser): Address { + // TODO: Guard against "" + if (!user.name) return user.email || ""; + return { + name: user.name, + address: user.email || "", + }; } const transporter = nodemailer.createTransport({ - host: env.emailHost, - port: 465, - secure: true, - auth: { - user: env.emailUser, - pass: env.emailPass, - }, + host: env.emailHost, + port: 465, + secure: true, + auth: { + user: env.emailUser, + pass: env.emailPass, + }, }); async function sendEmail(to: Address, subject: string, text: string) { - await transporter.sendMail({ - from: adminAddress, - to, - subject, - text, - }); + await transporter.sendMail({ + from: adminAddress, + to, + subject, + text, + }); } // TODO: MAKE THIS A URL ACROSS PROJECT -const baseURL = inProd ? "https://account.lingdocs.com" : "http://localhost:4000"; +const baseURL = inProd + ? "https://account.lingdocs.com" + : "http://localhost:4000"; -export async function sendVerificationEmail(user: T.LingdocsUser, token: T.URLToken) { - const subject = "Please Verify Your E-mail"; - const content = `Hello ${user.name}, +export async function sendVerificationEmail({ + name, + uid, + email, + token, +}: { + name: string; + uid: T.UUID; + email: string; + token: T.URLToken; +}) { + const subject = "Please Verify Your E-mail"; + const content = `Hello ${name}, -Please verify your email by visiting this link: ${baseURL}/email-verification/${user.userId}/${token} +Please verify your email by visiting this link: ${baseURL}/email-verification/${uid}/${token} LingDocs Admin`; - await sendEmail(getAddress(user), subject, content); + await sendEmail(email, subject, content); } -export async function sendPasswordResetEmail(user: T.LingdocsUser, token: T.URLToken) { - const subject = "Reset Your Password"; - const content = `Hello ${user.name}, +export async function sendPasswordResetEmail( + user: T.LingdocsUser, + token: T.URLToken +) { + const subject = "Reset Your Password"; + const content = `Hello ${user.name}, Please visit this link to reset your password: ${baseURL}/password-reset/${user.userId}/${token} LingDocs Admin`; - await sendEmail(getAddress(user), subject, content); + await sendEmail(getAddress(user), subject, content); } export async function sendAccountUpgradeMessage(user: T.LingdocsUser) { - const subject = "You're Upgraded to Student"; - const content = `Hello ${user.name}, + const subject = "You're Upgraded to Student"; + const content = `Hello ${user.name}, Congratulations on your upgrade to a LingDocs Student account! 👨‍🎓 @@ -72,11 +87,13 @@ Now you can start using your wordlist in the dictionary. It will automatically s LingDocs Admin`; - await sendEmail(getAddress(user), subject, content); + await sendEmail(getAddress(user), subject, content); } -export async function sendUpgradeRequestToAdmin(userWantingToUpgrade: T.LingdocsUser) { - const subject = "Account Upgrade Request"; - const content = `${userWantingToUpgrade.name} - ${userWantingToUpgrade.email} - ${userWantingToUpgrade.userId} is requesting to upgrade to student.`; - await sendEmail(adminAddress, subject, content); -} \ No newline at end of file +export async function sendUpgradeRequestToAdmin( + userWantingToUpgrade: T.LingdocsUser +) { + const subject = "Account Upgrade Request"; + const content = `${userWantingToUpgrade.name} - ${userWantingToUpgrade.email} - ${userWantingToUpgrade.userId} is requesting to upgrade to student.`; + await sendEmail(adminAddress, subject, content); +} diff --git a/account/src/lib/user-utils.ts b/account/src/lib/user-utils.ts index 37daaf9..6ef9dd7 100644 --- a/account/src/lib/user-utils.ts +++ b/account/src/lib/user-utils.ts @@ -1,18 +1,15 @@ import { v4 as uuidv4 } from "uuid"; import { - insertLingdocsUser, - addCouchDbAuthUser, - updateLingdocsUser, - deleteCouchDbAuthUser, + insertLingdocsUser, + addCouchDbAuthUser, + updateLingdocsUser, + deleteCouchDbAuthUser, } from "../lib/couch-db"; -import { - getHash, - getEmailTokenAndHash, -} from "../lib/password-utils"; +import { getHash, getEmailTokenAndHash } from "../lib/password-utils"; import { getTimestamp } from "../lib/time-utils"; import { - sendVerificationEmail, - sendAccountUpgradeMessage, + sendVerificationEmail, + sendAccountUpgradeMessage, } from "../lib/mail-utils"; import { outsideProviders } from "../middleware/setup-passport"; import * as T from "../../../website/src/types/account-types"; @@ -20,183 +17,212 @@ import env from "../lib/env-vars"; import Stripe from "stripe"; const stripe = new Stripe(env.stripeSecretKey, { - apiVersion: "2022-08-01", + apiVersion: "2022-08-01", }); function getUUID(): T.UUID { - return uuidv4() as T.UUID; + return uuidv4() as T.UUID; } export function canRemoveOneOutsideProvider(user: T.LingdocsUser): boolean { - if (user.email && user.password) { - return true; - } - const providersPresent = outsideProviders.filter((provider) => !!user[provider]); - return providersPresent.length > 1; + if (user.email && user.password) { + return true; + } + const providersPresent = outsideProviders.filter( + (provider) => !!user[provider] + ); + return providersPresent.length > 1; } -export function getVerifiedEmail({ emails }: T.ProviderProfile): string | false { - return ( - emails - && emails.length - // @ts-ignore - && emails[0].verified - ) ? emails[0].value : false; +export function getVerifiedEmail({ + emails, +}: T.ProviderProfile): string | false { + return emails && + emails.length && + // @ts-ignore + emails[0].verified + ? emails[0].value + : false; } -export function getEmailFromGoogleProfile(profile: T.GoogleProfile): { email: string | undefined, verified: boolean } { - if (!profile.emails || profile.emails.length === 0) { - return { email: undefined, verified: false }; - } - const em = profile.emails[0]; - // @ts-ignore // but the verified value *is* there - if not it's still safe - const verified = !!em.verified - return { - email: em.value, - verified, - }; +export function getEmailFromGoogleProfile(profile: T.GoogleProfile): { + email: string | undefined; + verified: boolean; +} { + if (!profile.emails || profile.emails.length === 0) { + return { email: undefined, verified: false }; + } + const em = profile.emails[0]; + // @ts-ignore // but the verified value *is* there - if not it's still safe + const verified = !!em.verified; + return { + email: em.value, + verified, + }; } -export async function upgradeUser(userId: T.UUID, subscription?: T.StripeSubscription): Promise { - // add user to couchdb authentication db - const { password, userDbName } = await addCouchDbAuthUser(userId); - // // create user db - // update LingdocsUser - const user = await updateLingdocsUser(userId, { - level: "student", - wordlistDbName: userDbName, - couchDbPassword: password, - upgradeToStudentRequest: undefined, - subscription, - }); - if (user.email) { - sendAccountUpgradeMessage(user).catch(console.error); - } - return { - ok: true, - message: "user upgraded to student", - user, - }; +export async function upgradeUser( + userId: T.UUID, + subscription?: T.StripeSubscription +): Promise { + // add user to couchdb authentication db + const { password, userDbName } = await addCouchDbAuthUser(userId); + // // create user db + // update LingdocsUser + const user = await updateLingdocsUser(userId, { + level: "student", + wordlistDbName: userDbName, + couchDbPassword: password, + upgradeToStudentRequest: undefined, + subscription, + }); + if (user.email) { + sendAccountUpgradeMessage(user).catch(console.error); + } + return { + ok: true, + message: "user upgraded to student", + user, + }; } -export async function downgradeUser(userId: T.UUID, subscriptionId?: string): Promise { - await deleteCouchDbAuthUser(userId); - if (subscriptionId) { - stripe.subscriptions.del(subscriptionId); - } - const user = await updateLingdocsUser(userId, { - level: "basic", - wordlistDbName: undefined, - couchDbPassword: undefined, - upgradeToStudentRequest: undefined, - subscription: undefined, - }); - if (user.email) { - // TODO - // sendAccountDowngradeMessage(user).catch(console.error); - } - return { - ok: true, - message: "user downgraded to basic", - user, - }; +export async function downgradeUser( + userId: T.UUID, + subscriptionId?: string +): Promise { + await deleteCouchDbAuthUser(userId); + if (subscriptionId) { + stripe.subscriptions.del(subscriptionId); + } + const user = await updateLingdocsUser(userId, { + level: "basic", + wordlistDbName: undefined, + couchDbPassword: undefined, + upgradeToStudentRequest: undefined, + subscription: undefined, + }); + if (user.email) { + // TODO + // sendAccountDowngradeMessage(user).catch(console.error); + } + return { + ok: true, + message: "user downgraded to basic", + user, + }; } export async function denyUserUpgradeRequest(userId: T.UUID): Promise { - await updateLingdocsUser(userId, { - upgradeToStudentRequest: "denied", - }); + await updateLingdocsUser(userId, { + upgradeToStudentRequest: "denied", + }); } -export async function createNewUser(input: { - strategy: "local", - email: string, - name: string, - passwordPlainText: string, -} | { - strategy: "github", - profile: T.GitHubProfile, -} | { - strategy: "google", - profile: T.GoogleProfile, -} | { - strategy: "twitter", - profile: T.TwitterProfile, -}): Promise { - const userId = getUUID(); - const now = getTimestamp(); - if (input.strategy === "local") { - const email = await getEmailTokenAndHash(); - const password = await getHash(input.passwordPlainText); - const newUser: T.LingdocsUser = { - _id: userId, - userId, - email: input.email, - emailVerified: email.hash, - name: input.name, - password, - level: "basic", - tests: [], - accountCreated: now, - lastLogin: now, - lastActive: now, - }; - const user = await insertLingdocsUser(newUser); - sendVerificationEmail(user, email.token).catch(console.error); - return user; - } - // GitHub || Twitter - if (input.strategy === "github" || input.strategy === "twitter") { - const newUser: T.LingdocsUser = { - _id: userId, - userId, - emailVerified: false, - name: input.profile.displayName, - [input.strategy]: input.profile, - level: "basic", - tests: [], - accountCreated: now, - lastLogin: now, - lastActive: now, - }; - const user = await insertLingdocsUser(newUser); - return user; - } - // Google - // TODO: Add e-mail in here - const { email, verified } = getEmailFromGoogleProfile(input.profile); - if (email && !verified) { - const em = await getEmailTokenAndHash(); - const newUser: T.LingdocsUser = { - _id: userId, - userId, - email, - emailVerified: em.hash, - name: input.profile.displayName, - google: input.profile, - lastLogin: now, - tests: [], - lastActive: now, - accountCreated: now, - level: "basic", - } - const user = await insertLingdocsUser(newUser); - sendVerificationEmail(user, em.token); - return user; - } +export async function createNewUser( + input: + | { + strategy: "local"; + email: string; + name: string; + passwordPlainText: string; + } + | { + strategy: "github"; + profile: T.GitHubProfile; + } + | { + strategy: "google"; + profile: T.GoogleProfile; + } + | { + strategy: "twitter"; + profile: T.TwitterProfile; + } +): Promise { + const userId = getUUID(); + const now = getTimestamp(); + if (input.strategy === "local") { + const email = await getEmailTokenAndHash(); + const password = await getHash(input.passwordPlainText); const newUser: T.LingdocsUser = { - _id: userId, - userId, - email, - emailVerified: verified, - name: input.profile.displayName, - google: input.profile, - lastLogin: now, - tests: [], - lastActive: now, - accountCreated: now, - level: "basic", - } + _id: userId, + userId, + email: input.email, + emailVerified: email.hash, + name: input.name, + password, + level: "basic", + tests: [], + accountCreated: now, + lastLogin: now, + lastActive: now, + }; + await sendVerificationEmail({ + name: input.name, + uid: userId, + email: input.email || "", + token: email.token, + }); const user = await insertLingdocsUser(newUser); return user; + } + // GitHub || Twitter + if (input.strategy === "github" || input.strategy === "twitter") { + const newUser: T.LingdocsUser = { + _id: userId, + userId, + emailVerified: false, + name: input.profile.displayName, + [input.strategy]: input.profile, + level: "basic", + tests: [], + accountCreated: now, + lastLogin: now, + lastActive: now, + }; + const user = await insertLingdocsUser(newUser); + return user; + } + // Google + // TODO: Add e-mail in here + const { email, verified } = getEmailFromGoogleProfile(input.profile); + if (email && !verified) { + const em = await getEmailTokenAndHash(); + const newUser: T.LingdocsUser = { + _id: userId, + userId, + email, + emailVerified: em.hash, + name: input.profile.displayName, + google: input.profile, + lastLogin: now, + tests: [], + lastActive: now, + accountCreated: now, + level: "basic", + }; + const user = await insertLingdocsUser(newUser); + sendVerificationEmail({ + name: newUser.name, + uid: newUser.userId, + email: newUser.email || "", + token: em.token, + }).catch(console.error); + return user; + } + const newUser: T.LingdocsUser = { + _id: userId, + userId, + email, + emailVerified: verified, + name: input.profile.displayName, + google: input.profile, + lastLogin: now, + tests: [], + lastActive: now, + accountCreated: now, + level: "basic", + }; + const user = await insertLingdocsUser(newUser); + return user; } diff --git a/account/src/routers/api-router.ts b/account/src/routers/api-router.ts index 6c55718..804466e 100644 --- a/account/src/routers/api-router.ts +++ b/account/src/routers/api-router.ts @@ -1,184 +1,210 @@ import express, { Response } from "express"; import { - deleteLingdocsUser, - getLingdocsUser, - updateLingdocsUser, + deleteLingdocsUser, + getLingdocsUser, + updateLingdocsUser, } from "../lib/couch-db"; import { - getHash, - compareToHash, - getEmailTokenAndHash, + getHash, + compareToHash, + getEmailTokenAndHash, } from "../lib/password-utils"; import { - sendUpgradeRequestToAdmin, - sendVerificationEmail, + sendUpgradeRequestToAdmin, + sendVerificationEmail, } from "../lib/mail-utils"; -import { - upgradeUser, -} from "../lib/user-utils"; +import { upgradeUser } from "../lib/user-utils"; import * as T from "../../../website/src/types/account-types"; import env from "../lib/env-vars"; // TODO: ADD PROPER ERROR HANDLING THAT WILL RETURN JSON ALWAYS function sendResponse(res: Response, payload: T.APIResponse) { - return res.send(payload); + return res.send(payload); } const apiRouter = express.Router(); // Guard all api with authentication apiRouter.use((req, res, next) => { - if (req.isAuthenticated()) { - return next(); - } - const r: T.APIResponse = { ok: false, error: "401 Unauthorized" }; - return res.status(401).send(r); + if (req.isAuthenticated()) { + return next(); + } + const r: T.APIResponse = { ok: false, error: "401 Unauthorized" }; + return res.status(401).send(r); }); /** * gets the LingdocsUser object for the user signed in */ apiRouter.get("/user", (req, res, next) => { - if (!req.user) return next("user not found"); - sendResponse(res, { ok: true, user: req.user }); + if (!req.user) return next("user not found"); + sendResponse(res, { ok: true, user: req.user }); }); /** * adds (passed) test results to the record of the user signed in */ apiRouter.put("/user/tests", async (req, res, next) => { - if (!req.user) return next("user not found"); - try { - const { tests } = req.body as T.PostTestResultsBody; - await updateLingdocsUser(req.user.userId, { tests }); - sendResponse(res, { - ok: true, - message: "posted test results", - tests, - }); - } catch(e) { - next(e); - } + if (!req.user) return next("user not found"); + try { + const { tests } = req.body as T.PostTestResultsBody; + await updateLingdocsUser(req.user.userId, { tests }); + sendResponse(res, { + ok: true, + message: "posted test results", + tests, + }); + } catch (e) { + next(e); + } }); /** * receives a request to change or add a user's own password */ apiRouter.post("/password", async (req, res, next) => { - if (!req.user) return next("user not found"); - const { oldPassword, password, passwordConfirmed } = req.body; - const addingFirstPassword = !req.user.password; - if (!oldPassword && !addingFirstPassword) { - return sendResponse(res, { ok: false, error: "Please enter your old password" }); + if (!req.user) return next("user not found"); + const { oldPassword, password, passwordConfirmed } = req.body; + const addingFirstPassword = !req.user.password; + if (!oldPassword && !addingFirstPassword) { + return sendResponse(res, { + ok: false, + error: "Please enter your old password", + }); + } + if (!password) { + return sendResponse(res, { + ok: false, + error: "Please enter a new password", + }); + } + if (!req.user.email) { + return sendResponse(res, { + ok: false, + error: "You need to add an e-mail address first", + }); + } + if (req.user.password) { + const matchedOld = + (await compareToHash(oldPassword, req.user.password)) || + !req.user.password; + if (!matchedOld) { + return sendResponse(res, { ok: false, error: "Incorrect old password" }); } - if (!password) { - return sendResponse(res, { ok: false, error: "Please enter a new password" }); - } - if (!req.user.email) { - return sendResponse(res, { ok: false, error: "You need to add an e-mail address first" }); - } - if (req.user.password) { - const matchedOld = await compareToHash(oldPassword, req.user.password) || !req.user.password; - if (!matchedOld) { - return sendResponse(res, { ok: false, error: "Incorrect old password" }); - } - } - if (password !== passwordConfirmed) { - return sendResponse(res, { ok: false, error: "New passwords do not match" }); - } - if (password.length < 6) { - return sendResponse(res, {ok: false, error: "New password too short" }); - } - const hash = await getHash(password); - await updateLingdocsUser(req.user.userId, { password: hash }); - sendResponse(res, { ok: true, message: addingFirstPassword ? "Password added" : "Password changed" }); + } + if (password !== passwordConfirmed) { + return sendResponse(res, { + ok: false, + error: "New passwords do not match", + }); + } + if (password.length < 6) { + return sendResponse(res, { ok: false, error: "New password too short" }); + } + const hash = await getHash(password); + await updateLingdocsUser(req.user.userId, { password: hash }); + sendResponse(res, { + ok: true, + message: addingFirstPassword ? "Password added" : "Password changed", + }); }); /** - * receives a request to generate a new e-mail verification token and send e-mail + * receives a request to generate a new e-mail verification token and send e-mail */ apiRouter.put("/email-verification", async (req, res, next) => { - try { - if (!req.user) throw new Error("user not found"); - const { token, hash } = await getEmailTokenAndHash(); - const u = await updateLingdocsUser(req.user.userId, { emailVerified: hash }); - sendVerificationEmail(u, token).then(() => { - sendResponse(res, { ok: true, message: "e-mail verification sent" }); - }).catch((err) => { - sendResponse(res, { ok: false, error: err }); - }); - } catch (e) { - next(e); - } + try { + if (!req.user) throw new Error("user not found"); + const { token, hash } = await getEmailTokenAndHash(); + const u = await updateLingdocsUser(req.user.userId, { + emailVerified: hash, + }); + sendVerificationEmail({ + name: u.name, + uid: u.userId, + email: u.email || "", + token, + }) + .then(() => { + sendResponse(res, { ok: true, message: "e-mail verification sent" }); + }) + .catch((err) => { + sendResponse(res, { ok: false, error: err }); + }); + } catch (e) { + next(e); + } }); apiRouter.put("/user/upgrade", async (req, res, next) => { - if (!req.user) throw new Error("user not found"); - try { - const givenPassword = (req.body.password || "") as string; - const studentPassword = env.upgradePassword; - if (givenPassword.toLowerCase().trim() !== studentPassword.toLowerCase()) { - const wrongPass: T.UpgradeUserResponse = { - ok: false, - error: "incorrect password", - }; - res.send(wrongPass); - return; - } - const { userId } = req.user; - const user = await getLingdocsUser("userId", userId); - if (!user) throw new Error("user lost"); - if (user.level !== "basic") { - const alreadyUpgraded: T.UpgradeUserResponse = { - ok: true, - message: "user already upgraded", - user, - }; - res.send(alreadyUpgraded); - return; - } - const upgraded: T.UpgradeUserResponse = await upgradeUser(userId); - res.send(upgraded); - } catch (e) { - next(e); + if (!req.user) throw new Error("user not found"); + try { + const givenPassword = (req.body.password || "") as string; + const studentPassword = env.upgradePassword; + if (givenPassword.toLowerCase().trim() !== studentPassword.toLowerCase()) { + const wrongPass: T.UpgradeUserResponse = { + ok: false, + error: "incorrect password", + }; + res.send(wrongPass); + return; } + const { userId } = req.user; + const user = await getLingdocsUser("userId", userId); + if (!user) throw new Error("user lost"); + if (user.level !== "basic") { + const alreadyUpgraded: T.UpgradeUserResponse = { + ok: true, + message: "user already upgraded", + user, + }; + res.send(alreadyUpgraded); + return; + } + const upgraded: T.UpgradeUserResponse = await upgradeUser(userId); + res.send(upgraded); + } catch (e) { + next(e); + } }); apiRouter.post("/user/upgradeToStudentRequest", async (req, res, next) => { - if (!req.user) throw new Error("user not found"); - try { - if (req.user.level === "student" || req.user.level === "editor") { - res.send({ ok: true, message: "user already upgraded" }); - return; - } - sendUpgradeRequestToAdmin(req.user).catch(console.error); - await updateLingdocsUser(req.user.userId, { upgradeToStudentRequest: "waiting" }); - res.send({ ok: true, message: "request for upgrade sent" }); - } catch (e) { - next(e); + if (!req.user) throw new Error("user not found"); + try { + if (req.user.level === "student" || req.user.level === "editor") { + res.send({ ok: true, message: "user already upgraded" }); + return; } + sendUpgradeRequestToAdmin(req.user).catch(console.error); + await updateLingdocsUser(req.user.userId, { + upgradeToStudentRequest: "waiting", + }); + res.send({ ok: true, message: "request for upgrade sent" }); + } catch (e) { + next(e); + } }); /** * deletes a users own account */ apiRouter.delete("/user", async (req, res, next) => { - try { - if (!req.user) throw new Error("user not found"); - await deleteLingdocsUser(req.user.userId); - sendResponse(res, { ok: true, message: "user deleted" }); - } catch (e) { - next(e); - } -}) + try { + if (!req.user) throw new Error("user not found"); + await deleteLingdocsUser(req.user.userId); + sendResponse(res, { ok: true, message: "user deleted" }); + } catch (e) { + next(e); + } +}); /** * signs out the user signed in */ apiRouter.post("/sign-out", (req, res) => { - req.logOut(); - sendResponse(res, { ok: true, message: "signed out" }); + req.logOut(); + sendResponse(res, { ok: true, message: "signed out" }); }); export default apiRouter; diff --git a/account/src/routers/auth-router.ts b/account/src/routers/auth-router.ts index c4f335e..6c53f84 100644 --- a/account/src/routers/auth-router.ts +++ b/account/src/routers/auth-router.ts @@ -22,6 +22,7 @@ import { upgradeUser, denyUserUpgradeRequest } from "../lib/user-utils"; import { validateReCaptcha } from "../lib/recaptcha"; import { getTimestamp } from "../lib/time-utils"; import { + getAddress, sendPasswordResetEmail, sendVerificationEmail, } from "../lib/mail-utils"; @@ -74,7 +75,13 @@ const authRouter = (passport: PassportStatic) => { email, emailVerified: hash, }); - sendVerificationEmail(updated, token).catch(console.error); + // TODO: AWAIT THE E-MAIL SEND TO MAKE SURE THE E-MAIL WORKS! + sendVerificationEmail({ + name: updated.name, + uid: updated.userId, + email: updated.email || "", + token, + }); return res.render(page, { user: updated, error: null, @@ -170,16 +177,21 @@ const authRouter = (passport: PassportStatic) => { const { email, password, name } = req.body; const existingUser = await getLingdocsUser("email", email); if (existingUser) return res.send("User Already Exists"); - const user = await createNewUser({ - strategy: "local", - email, - passwordPlainText: password, - name, - }); - req.logIn(user, (err) => { - if (err) return next(err); - return res.send({ ok: true, user }); - }); + try { + const user = await createNewUser({ + strategy: "local", + email, + passwordPlainText: password, + name, + }); + req.logIn(user, (err) => { + if (err) return next(err); + return res.send({ ok: true, user }); + }); + } catch (e) { + console.error(e); + return res.send("Invalid E-mail"); + } } catch (e) { next(e); } diff --git a/account/views/login.ejs b/account/views/login.ejs index 35c9450..bfbd701 100644 --- a/account/views/login.ejs +++ b/account/views/login.ejs @@ -29,7 +29,7 @@

Sign in to LingDocs

- +