This commit is contained in:
May 2024-06-25 16:51:23 -07:00
parent 32a297d2ef
commit ae4252e898
Signed by: split
GPG key ID: C325C61F0BF517C0
4 changed files with 97 additions and 6 deletions

15
src/reset.html Normal file
View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>reset</title>
</head>
<body>
<h1>monofile password reset</h1>
<form>
<input name="password" type="password">
READY... STEADY... <input type="submit" name='FYLE!!!'>
</form>
</body>
</html>

View file

@ -94,9 +94,11 @@ const validators: {
requireProofOfIdentity: true, requireProofOfIdentity: true,
validator: (actor, target, params, ctx) => { validator: (actor, target, params, ctx) => {
const email = params.email.toLowerCase()
if (!Configuration.mail.enabled) return [501, "email not enabled on instance"] if (!Configuration.mail.enabled) return [501, "email not enabled on instance"]
if (!params.email) { if (!email) {
if (target.email) { if (target.email) {
sendMail( sendMail(
target.email, target.email,
@ -107,11 +109,11 @@ const validators: {
return undefined return undefined
} }
if (actor.admin) return params.email || undefined if (actor.admin) return email || undefined
// send verification email // send verification email
const tryCode = CodeMgr.code("verifyEmail", target.id, params.email) const tryCode = CodeMgr.code("verifyEmail", target.id, email)
if (!tryCode.success) if (!tryCode.success)
return [429, tryCode.error] return [429, tryCode.error]
@ -119,12 +121,12 @@ const validators: {
const { code } = tryCode const { code } = tryCode
sendMail( sendMail(
params.email, email,
`Hey there, ${target.username} - let's connect your email`, `Hey there, ${target.username} - let's connect your email`,
`<b>Hello there!</b> You are recieving this message because you decided to link your email, <span code>${ `<b>Hello there!</b> You are recieving this message because you decided to link your email, <span code>${
params.email.split("@")[0] email.split("@")[0]
}<span style="opacity:0.5">@${ }<span style="opacity:0.5">@${
params.email.split("@")[1] email.split("@")[1]
}</span></span>, to your account, <span username>${ }</span></span>, to your account, <span username>${
target.username target.username
}</span>. If you would like to continue, please <a href="https://${ctx.req.header( }</span>. If you would like to continue, please <a href="https://${ctx.req.header(
@ -258,6 +260,10 @@ const UserUpdateScheme = z.union([
}).strict() }).strict()
]) ])
const PasswordResetScheme = z.object({
email: AccountSchemas.Account.shape.email
}).required()
export default function (files: Files) { export default function (files: Files) {
router.post("/", scheme(z.object({ router.post("/", scheme(z.object({
username: AccountSchemas.Username, username: AccountSchemas.Username,
@ -392,5 +398,35 @@ export default function (files: Files) {
}) })
}) })
router.post(
"/:user/requestPasswordReset",
noAPIAccess,
scheme(PasswordResetScheme),
async (ctx) => {
const { email } = ctx.get("parsedScheme") as z.infer<typeof PasswordResetScheme>
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, <span username>${target.username}</span>, 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 return router
} }

View file

@ -6,6 +6,7 @@ import type Files from "../../../lib/files.js"
import * as CodeMgr from "../../../lib/codes.js" import * as CodeMgr from "../../../lib/codes.js"
import { Hono } from "hono" import { Hono } from "hono"
import { getAccount, login } from "../../../lib/middleware.js" import { getAccount, login } from "../../../lib/middleware.js"
import { sendMail } from "../../../lib/mail.js"
export let router = new Hono<{ export let router = new Hono<{
Variables: { Variables: {
account: Accounts.Account account: Accounts.Account
@ -36,5 +37,43 @@ export default function (files: Files) {
} else return ServeError(ctx, 404, "code not found") } 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`,
`<b>Hello there!</b> Your password on your account, <span username>${currentAccount.username}</span>, 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 return router
} }

View file

@ -12,6 +12,7 @@ export default defineConfig({
main: resolve(__dirname, "src/index.html"), main: resolve(__dirname, "src/index.html"),
download: resolve(__dirname, "src/download.html"), download: resolve(__dirname, "src/download.html"),
error: resolve(__dirname, "src/error.html"), error: resolve(__dirname, "src/error.html"),
reset: resolve(__dirname, "src/reset.html"),
}, },
}, },
}, },