diff options
-rw-r--r-- | src/api/routes/auth/reset.ts | 57 | ||||
-rw-r--r-- | src/api/routes/auth/verify/index.ts | 54 | ||||
-rw-r--r-- | src/util/util/Email.ts | 11 |
3 files changed, 73 insertions, 49 deletions
diff --git a/src/api/routes/auth/reset.ts b/src/api/routes/auth/reset.ts index 94053e1a..9ab25dca 100644 --- a/src/api/routes/auth/reset.ts +++ b/src/api/routes/auth/reset.ts @@ -10,7 +10,6 @@ import { } from "@fosscord/util"; import bcrypt from "bcrypt"; import { Request, Response, Router } from "express"; -import { HTTPError } from "lambert-server"; const router = Router(); @@ -20,37 +19,37 @@ router.post( async (req: Request, res: Response) => { const { password, token } = req.body as PasswordResetSchema; - try { - const { jwtSecret } = Config.get().security; - const { user } = await checkToken(token, jwtSecret, true); - - // the salt is saved in the password refer to bcrypt docs - const hash = await bcrypt.hash(password, 12); + const { jwtSecret } = Config.get().security; - const data = { - data: { - hash, - valid_tokens_since: new Date(), + let user; + try { + const userTokenData = await checkToken(token, jwtSecret, true); + user = userTokenData.user; + } catch { + throw FieldErrors({ + password: { + message: req.t("auth:password_reset.INVALID_TOKEN"), + code: "INVALID_TOKEN", }, - }; - await User.update({ id: user.id }, data); - - // come on, the user has to have an email to reset their password in the first place - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await Email.sendPasswordChanged(user, user.email!); - - res.json({ token: await generateToken(user.id) }); - } catch (e) { - if ((e as Error).toString() === "Invalid Token") - throw FieldErrors({ - password: { - message: req.t("auth:password_reset.INVALID_TOKEN"), - code: "INVALID_TOKEN", - }, - }); - - throw new HTTPError((e as Error).toString(), 400); + }); } + + // the salt is saved in the password refer to bcrypt docs + const hash = await bcrypt.hash(password, 12); + + const data = { + data: { + hash, + valid_tokens_since: new Date(), + }, + }; + await User.update({ id: user.id }, data); + + // come on, the user has to have an email to reset their password in the first place + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + await Email.sendPasswordChanged(user, user.email!); + + res.json({ token: await generateToken(user.id) }); }, ); diff --git a/src/api/routes/auth/verify/index.ts b/src/api/routes/auth/verify/index.ts index 91ff9b93..cdbd371a 100644 --- a/src/api/routes/auth/verify/index.ts +++ b/src/api/routes/auth/verify/index.ts @@ -16,10 +16,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>. */ -import { route, verifyCaptcha } from "@fosscord/api"; -import { checkToken, Config, generateToken, User } from "@fosscord/util"; +import { getIpAdress, route, verifyCaptcha } from "@fosscord/api"; +import { + checkToken, + Config, + FieldErrors, + generateToken, + User, +} from "@fosscord/util"; import { Request, Response, Router } from "express"; -import { HTTPError } from "lambert-server"; const router = Router(); async function getToken(user: User) { @@ -38,9 +43,21 @@ router.post( async (req: Request, res: Response) => { const { captcha_key, token } = req.body; - if (captcha_key) { - const { sitekey, service } = Config.get().security.captcha; - const verify = await verifyCaptcha(captcha_key); + const config = Config.get(); + + if (config.register.requireCaptcha) { + const { sitekey, service } = config.security.captcha; + + if (!captcha_key) { + return res.status(400).json({ + captcha_key: ["captcha-required"], + captcha_sitekey: sitekey, + captcha_service: service, + }); + } + + const ip = getIpAdress(req); + const verify = await verifyCaptcha(captcha_key, ip); if (!verify.success) { return res.status(400).json({ captcha_key: verify["error-codes"], @@ -50,19 +67,26 @@ router.post( } } - try { - const { jwtSecret } = Config.get().security; + const { jwtSecret } = Config.get().security; + let user; - const { user } = await checkToken(token, jwtSecret, true); + try { + const userTokenData = await checkToken(token, jwtSecret, true); + user = userTokenData.user; + } catch { + throw FieldErrors({ + password: { + message: req.t("auth:password_reset.INVALID_TOKEN"), + code: "INVALID_TOKEN", + }, + }); + } - if (user.verified) return res.json(await getToken(user)); + if (user.verified) return res.json(await getToken(user)); - await User.update({ id: user.id }, { verified: true }); + await User.update({ id: user.id }, { verified: true }); - return res.json(await getToken(user)); - } catch (error) { - throw new HTTPError((error as Error).toString(), 400); - } + return res.json(await getToken(user)); }, ); diff --git a/src/util/util/Email.ts b/src/util/util/Email.ts index fa72d9c0..714b3db2 100644 --- a/src/util/util/Email.ts +++ b/src/util/util/Email.ts @@ -52,7 +52,9 @@ export function adjustEmail(email?: string): string | undefined { // return email; } -const transporters = { +const transporters: { + [key: string]: () => Promise<nodemailer.Transporter<unknown> | void>; +} = { smtp: async function () { // get configuration const { host, port, secure, username, password } = @@ -223,8 +225,7 @@ export const Email: { const { provider } = Config.get().email; if (!provider) return; - const transporterFn = - transporters[provider as keyof typeof transporters]; + const transporterFn = transporters[provider]; if (!transporterFn) return console.error(`[Email] Invalid provider: ${provider}`); console.log(`[Email] Initializing ${provider} transport...`); @@ -346,7 +347,7 @@ export const Email: { const link = await this.generateLink("reset", user.id, email); // load the email template - const rawTemplate = fs.readFileSync( + const rawTemplate = await fs.promises.readFile( path.join( ASSET_FOLDER_PATH, "email_templates", @@ -380,7 +381,7 @@ export const Email: { if (!this.transporter) return; // load the email template - const rawTemplate = fs.readFileSync( + const rawTemplate = await fs.promises.readFile( path.join( ASSET_FOLDER_PATH, "email_templates", |