diff --git a/src/reset.html b/src/reset.html new file mode 100644 index 0000000..3b8dd77 --- /dev/null +++ b/src/reset.html @@ -0,0 +1,15 @@ + + + + + + reset + + +

monofile password reset

+
+ + READY... STEADY... +
+ + \ No newline at end of file diff --git a/src/server/routes/api/v1/account/index.ts b/src/server/routes/api/v1/account/index.ts index be0f344..be22775 100644 --- a/src/server/routes/api/v1/account/index.ts +++ b/src/server/routes/api/v1/account/index.ts @@ -94,9 +94,11 @@ const validators: { requireProofOfIdentity: true, validator: (actor, target, params, ctx) => { + const email = params.email.toLowerCase() + if (!Configuration.mail.enabled) return [501, "email not enabled on instance"] - if (!params.email) { + if (!email) { if (target.email) { sendMail( target.email, @@ -107,11 +109,11 @@ const validators: { return undefined } - if (actor.admin) return params.email || undefined + if (actor.admin) return email || undefined // send verification email - const tryCode = CodeMgr.code("verifyEmail", target.id, params.email) + const tryCode = CodeMgr.code("verifyEmail", target.id, email) if (!tryCode.success) return [429, tryCode.error] @@ -119,12 +121,12 @@ const validators: { const { code } = tryCode sendMail( - params.email, + email, `Hey there, ${target.username} - let's connect your email`, `Hello there! You are recieving this message because you decided to link your email, ${ - params.email.split("@")[0] + email.split("@")[0] }@${ - params.email.split("@")[1] + email.split("@")[1] }, to your account, ${ target.username }. If you would like to continue, please { + const { email } = ctx.get("parsedScheme") as z.infer + const actor = ctx.get("account") + const target = ctx.get("target") + + if (actor) + return ServeError(ctx, 404, "account not found") + if (!target.email || email !== target.email) + return ServeError(ctx, 401, "bad email") + + const tryCode = CodeMgr.code("recoverAccount", target.id, null, 15*60*1000) + + if (!tryCode.success) + return ServeError(ctx, 429, tryCode.error) + + await sendMail( + target.email!, + "Password reset requested", + `A password reset for your account, ${target.username}, has been requested.` + + `Go to https://${ctx.req.header("Host")}/go/verify/${tryCode.code.id} to reset your password.` + ) + + return ctx.text("email sent") + } + ) + return router } diff --git a/src/server/routes/api/web/go.ts b/src/server/routes/api/web/go.ts index 782c9f7..92018c8 100644 --- a/src/server/routes/api/web/go.ts +++ b/src/server/routes/api/web/go.ts @@ -6,6 +6,7 @@ import type Files from "../../../lib/files.js" import * as CodeMgr from "../../../lib/codes.js" import { Hono } from "hono" import { getAccount, login } from "../../../lib/middleware.js" +import { sendMail } from "../../../lib/mail.js" export let router = new Hono<{ Variables: { account: Accounts.Account @@ -35,6 +36,44 @@ export default function (files: Files) { return ctx.redirect('/') } else return ServeError(ctx, 404, "code not found") }) + + router.get("/reset/:code", getAccount, async (ctx) => { + let currentAccount = ctx.get("account") + let code = CodeMgr.codes.verifyEmail.byId.get(ctx.req.param("code")) + + if (code) { + if (currentAccount != undefined && !code.check(currentAccount.id)) { + return ServeError(ctx, 403, "you are logged in on a different account") + } + + if (!currentAccount) { + let ac = Accounts.getFromId(code.for) + if (ac) currentAccount = ac + else return ServeError(ctx, 401, "could not locate account") + } + + let pwd = ctx.req.query("password") + + if (!pwd) { + return ctx.html( + await fs.readFile(process.cwd() + "/dist/reset.html", "utf-8") + ) + } else { + if (currentAccount.email) { + sendMail( + currentAccount.email, + `Your login details have been updated`, + `Hello there! Your password on your account, ${currentAccount.username}, has been successfully reset. ` + + `Please update your saved login details accordingly.` + ).catch() + } + + Accounts.password.set(currentAccount.id, pwd) + login(ctx, code.for) + return ctx.redirect("/") + } + } else return ServeError(ctx, 404, "code not found") + }) return router } \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 7cae786..17352ca 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -12,6 +12,7 @@ export default defineConfig({ main: resolve(__dirname, "src/index.html"), download: resolve(__dirname, "src/download.html"), error: resolve(__dirname, "src/error.html"), + reset: resolve(__dirname, "src/reset.html"), }, }, },