mirror of
https://github.com/mollersuite/monofile.git
synced 2024-11-21 21:36:26 -08:00
updates
This commit is contained in:
parent
42062eaf86
commit
7f694f1a4a
45
src/server/lib/ratelimit.ts
Normal file
45
src/server/lib/ratelimit.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import { RequestHandler } from "express"
|
||||||
|
import { type Account } from "./accounts"
|
||||||
|
import ServeError from "./errors"
|
||||||
|
|
||||||
|
interface ratelimitSettings {
|
||||||
|
|
||||||
|
requests: number
|
||||||
|
per: number
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export function accountRatelimit( settings: ratelimitSettings ): RequestHandler {
|
||||||
|
let activeLimits: {
|
||||||
|
[ key: string ]: {
|
||||||
|
requests: number,
|
||||||
|
expirationHold: NodeJS.Timeout
|
||||||
|
}
|
||||||
|
} = {}
|
||||||
|
|
||||||
|
return (req, res, next) => {
|
||||||
|
if (res.locals.acc) {
|
||||||
|
let accId = res.locals.acc.id
|
||||||
|
let aL = activeLimits[accId]
|
||||||
|
|
||||||
|
if (!aL) {
|
||||||
|
activeLimits[accId] = {
|
||||||
|
requests: 0,
|
||||||
|
expirationHold: setTimeout(() => delete activeLimits[accId], settings.per)
|
||||||
|
}
|
||||||
|
aL = activeLimits[accId]
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aL.requests < settings.requests) {
|
||||||
|
res.locals.undoCount = () => {
|
||||||
|
if (activeLimits[accId]) {
|
||||||
|
activeLimits[accId].requests--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
ServeError(res, 429, "too many requests")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -48,6 +48,13 @@ adminRoutes.post("/reset", parser, (req,res) => {
|
||||||
auth.AuthTokens.filter(e => e.account == targetAccount?.id).forEach((v) => {
|
auth.AuthTokens.filter(e => e.account == targetAccount?.id).forEach((v) => {
|
||||||
auth.invalidate(v.token)
|
auth.invalidate(v.token)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
sendMail(req.body.email, `Your login details have been updated`, `<b>Hello there!</b> This email is to notify you of a password change that an administrator, <span username>${acc.username}</span>, has initiated. You have been logged out of your devices. Thank you for using monofile.`).then(() => {
|
||||||
|
res.send("OK")
|
||||||
|
}).catch((err) => {})
|
||||||
|
|
||||||
|
|
||||||
res.send()
|
res.send()
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,6 +4,7 @@ import * as Accounts from "../lib/accounts";
|
||||||
import * as auth from "../lib/auth";
|
import * as auth from "../lib/auth";
|
||||||
import { sendMail } from "../lib/mail";
|
import { sendMail } from "../lib/mail";
|
||||||
import { getAccount, requiresAccount } from "../lib/middleware"
|
import { getAccount, requiresAccount } from "../lib/middleware"
|
||||||
|
import { accountRatelimit } from "../lib/ratelimit"
|
||||||
|
|
||||||
import ServeError from "../lib/errors";
|
import ServeError from "../lib/errors";
|
||||||
import Files, { FileVisibility, generateFileId, id_check_regex } from "../lib/files";
|
import Files, { FileVisibility, generateFileId, id_check_regex } from "../lib/files";
|
||||||
|
@ -239,14 +240,18 @@ authRoutes.post("/change_username", requiresAccount, parser, (req,res) => {
|
||||||
acc.username = req.body.username
|
acc.username = req.body.username
|
||||||
Accounts.save()
|
Accounts.save()
|
||||||
|
|
||||||
|
sendMail(req.body.email, `Your login details have been updated`, `<b>Hello there!</b> Your username has been updated to <span username>${req.body.username}</span>. Please update your devices accordingly. Thank you for using monofile.`).then(() => {
|
||||||
|
res.send("OK")
|
||||||
|
}).catch((err) => {})
|
||||||
|
|
||||||
res.send("username changed")
|
res.send("username changed")
|
||||||
})
|
})
|
||||||
|
|
||||||
// shit way to do this but...
|
// shit way to do this but...
|
||||||
|
|
||||||
let verificationCodes = new Map<string, {code: string, email: string, expiry: NodeJS.Timeout, requestedAt:number}>()
|
let verificationCodes = new Map<string, {code: string, email: string, expiry: NodeJS.Timeout}>()
|
||||||
|
|
||||||
authRoutes.post("/request_email_change", requiresAccount, parser, (req,res) => {
|
authRoutes.post("/request_email_change", requiresAccount, accountRatelimit({ requests: 4, per: 60*60*1000 }), parser, (req,res) => {
|
||||||
let acc = res.locals.acc as Accounts.Account
|
let acc = res.locals.acc as Accounts.Account
|
||||||
|
|
||||||
|
|
||||||
|
@ -257,12 +262,6 @@ authRoutes.post("/request_email_change", requiresAccount, parser, (req,res) => {
|
||||||
|
|
||||||
let vcode = verificationCodes.get(acc.id)
|
let vcode = verificationCodes.get(acc.id)
|
||||||
|
|
||||||
if (vcode && vcode.requestedAt+(15*60*1000) > Date.now()) {
|
|
||||||
ServeError(res, 429, `Please wait a few moments to request another email change.`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// delete previous if any
|
// delete previous if any
|
||||||
let e = vcode?.expiry
|
let e = vcode?.expiry
|
||||||
if (e) clearTimeout(e)
|
if (e) clearTimeout(e)
|
||||||
|
@ -275,8 +274,7 @@ authRoutes.post("/request_email_change", requiresAccount, parser, (req,res) => {
|
||||||
verificationCodes.set(acc.id, {
|
verificationCodes.set(acc.id, {
|
||||||
code,
|
code,
|
||||||
email: req.body.email,
|
email: req.body.email,
|
||||||
expiry: setTimeout( () => verificationCodes.delete(acc?.id||""), 15*60*1000),
|
expiry: setTimeout( () => verificationCodes.delete(acc?.id||""), 15*60*1000)
|
||||||
requestedAt: Date.now()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// this is a mess but it's fine
|
// this is a mess but it's fine
|
||||||
|
@ -287,6 +285,7 @@ authRoutes.post("/request_email_change", requiresAccount, parser, (req,res) => {
|
||||||
let e = verificationCodes.get(acc?.id||"")?.expiry
|
let e = verificationCodes.get(acc?.id||"")?.expiry
|
||||||
if (e) clearTimeout(e)
|
if (e) clearTimeout(e)
|
||||||
verificationCodes.delete(acc?.id||"")
|
verificationCodes.delete(acc?.id||"")
|
||||||
|
res.locals.undoCount();
|
||||||
ServeError(res, 500, err?.toString())
|
ServeError(res, 500, err?.toString())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -408,6 +407,10 @@ authRoutes.post("/change_password", requiresAccount, parser, (req,res) => {
|
||||||
auth.invalidate(v.token)
|
auth.invalidate(v.token)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
sendMail(req.body.email, `Your login details have been updated`, `<b>Hello there!</b> This email is to notify you of a password change that you have initiated. You have been logged out of your devices. Thank you for using monofile.`).then(() => {
|
||||||
|
res.send("OK")
|
||||||
|
}).catch((err) => {})
|
||||||
|
|
||||||
res.send("password changed - logged out all sessions")
|
res.send("password changed - logged out all sessions")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue