basic suspension implementation

!! NOT READY WAIT FOR CLIENT-V2 SO WE CAN NUKE V0
This commit is contained in:
May 2024-05-01 18:39:38 +00:00 committed by GitHub
parent 60b0308e31
commit 459c40bece
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 35 additions and 18 deletions

View file

@ -9,7 +9,10 @@ import { z } from "zod"
* @description Middleware which adds an account, if any, to ctx.get("account") * @description Middleware which adds an account, if any, to ctx.get("account")
*/ */
export const getAccount: RequestHandler = function (ctx, next) { export const getAccount: RequestHandler = function (ctx, next) {
ctx.set("account", Accounts.getFromToken(auth.tokenFor(ctx)!)) let account = Accounts.getFromToken(auth.tokenFor(ctx)!)
if (account?.suspension)
setCookie(ctx, "auth", "")
ctx.set("account", account)
return next() return next()
} }

View file

@ -53,7 +53,11 @@ export namespace Settings {
interface: Interface.default({}), links: Links.default({}) interface: Interface.default({}), links: Links.default({})
}) })
} }
export const Suspension =
z.object({
reason: z.string(),
until: z.number().nullable()
})
export const Account = export const Account =
z.object({ z.object({
id: z.string(), id: z.string(),
@ -64,5 +68,6 @@ export const Account =
admin: z.boolean(), admin: z.boolean(),
defaultFileVisibility: FileVisibility, defaultFileVisibility: FileVisibility,
settings: Settings.User settings: Settings.User,
suspension: Suspension.optional()
}) })

View file

@ -101,9 +101,7 @@ const validators: {
return undefined return undefined
} }
if (!z.string().email().safeParse(typeof params.email).success) if (actor.admin) return params.email || undefined
return [400, "bad email"]
if (actor.admin) return params.email
// send verification email // send verification email
@ -191,6 +189,13 @@ const validators: {
else return [400, "cannot demote an admin"] else return [400, "cannot demote an admin"]
} }
}, },
suspension: {
schema: AccountSchemas.Suspension.nullable(),
validator: (actor, target, params) => {
if (!actor.admin) return [400, "only admins can modify suspensions"]
return params.suspension || undefined
}
},
settings: { settings: {
schema: AccountSchemas.Settings.User.partial(), schema: AccountSchemas.Settings.User.partial(),
validator: (actor, target, params) => { validator: (actor, target, params) => {

View file

@ -34,16 +34,24 @@ export default function (files: Files) {
})), async (ctx) => { })), async (ctx) => {
const body = await ctx.req.json() const body = await ctx.req.json()
if (auth.validate(getCookie(ctx, "auth")!)) { if (ctx.get("account"))
ServeError(ctx, 400, "you are already logged in") return ServeError(ctx, 400, "you are already logged in")
return
}
const account = Accounts.getFromUsername(body.username) const account = Accounts.getFromUsername(body.username)
if (!account || !Accounts.password.check(account.id, body.password)) { if (!account || !Accounts.password.check(account.id, body.password)) {
ServeError(ctx, 400, "username or password incorrect") return ServeError(ctx, 400, "username or password incorrect")
return }
if (account.suspension) {
if (account.suspension.until && Date.now() > account.suspension.until) delete account.suspension;
else return ServeError(
ctx,
403,
`account ${account.suspension.until
? `suspended until ${new Date(account.suspension.until).toUTCString()}`
: "suspended indefinitely"
}: ${account.suspension.reason}`)
} }
login(ctx, account.id) login(ctx, account.id)
@ -59,12 +67,8 @@ export default function (files: Files) {
}) })
}) })
router.delete("/", (ctx) => { router.delete("/", requiresAccount, (ctx) => {
if (!auth.validate(getCookie(ctx, "auth")!)) { auth.invalidate(auth.tokenFor(ctx)!)
return ServeError(ctx, 401, "not logged in")
}
auth.invalidate(getCookie(ctx, "auth")!)
return ctx.text("logged out") return ctx.text("logged out")
}) })