diff --git a/src/server/lib/auth.ts b/src/server/lib/auth.ts index 133ec52..4495f2f 100644 --- a/src/server/lib/auth.ts +++ b/src/server/lib/auth.ts @@ -37,7 +37,7 @@ export function create( expire:Date.now()+expire, type, - tokenPermissions + tokenPermissions: type == "App" ? tokenPermissions || ["user"] : undefined } AuthTokens.push(token) @@ -52,6 +52,14 @@ export function validate(token:string) { return AuthTokens.find(e => e.token == token && Date.now() < e.expire)?.account } +export function getType(token:string): TokenType | undefined { + return AuthTokens.find(e => e.token == token && Date.now() < e.expire)?.type +} + +export function getPermissions(token:string): TokenPermission[] | undefined { + return AuthTokens.find(e => e.token == token && Date.now() < e.expire)?.tokenPermissions +} + export function tokenTimer(token:AuthToken) { if (Date.now() >= token.expire) { invalidate(token.token) diff --git a/src/server/lib/middleware.ts b/src/server/lib/middleware.ts index 2f0ed0c..2f487b2 100644 --- a/src/server/lib/middleware.ts +++ b/src/server/lib/middleware.ts @@ -1,17 +1,22 @@ import * as Accounts from "./accounts"; import express, { type RequestHandler } from "express" import ServeError from "../lib/errors"; +import * as auth from "./auth"; -export let getAccount: RequestHandler = function(req, res, next) { - res.locals.acc = Accounts.getFromToken(req.cookies.auth || ( +function tokenFor(req: express.Request) { + return req.cookies.auth || ( req.header("authorization")?.startsWith("Bearer ") ? req.header("authorization")?.split(" ")[1] : undefined - )) + ) +} + +export const getAccount: RequestHandler = function(req, res, next) { + res.locals.acc = Accounts.getFromToken(tokenFor(req)) next() } -export let requiresAccount: RequestHandler = function(_req, res, next) { +export const requiresAccount: RequestHandler = function(_req, res, next) { if (!res.locals.acc) { ServeError(res, 401, "not logged in") return @@ -19,10 +24,53 @@ export let requiresAccount: RequestHandler = function(_req, res, next) { next() } -export let requiresAdmin: RequestHandler = function(_req, res, next) { +export const requiresAdmin: RequestHandler = function(_req, res, next) { if (!res.locals.acc.admin) { ServeError(res, 403, "you are not an administrator") return } next() +} + +export namespace apiBlockers { + + /** + * @description Blocks requests based on the permissions which a token has. Does not apply to routes being accessed with a token of type `User` + * @param tokenPermissions Permissions which your route requires. + * @returns Express middleware + */ + + export const requiresPermissions = function(...tokenPermissions: auth.TokenPermission[]): RequestHandler { + return function(req, res, next) { + let token = tokenFor(req) + let type = auth.getType(token) + + if (type == "App") { + let permissions = auth.getPermissions(token) + + if (!permissions) ServeError(res, 403, "insufficient permissions") + else { + + for (let v in tokenPermissions) + if (!permissions.includes(v as auth.TokenPermission)) { + ServeError(res,403,"insufficient permissions") + return + } + + next() + + } + } else next() + } + } + + /** + * @description Blocks requests based on whether or not the token being used to access the route is of type `User`. + */ + + export const noAPIAccess: RequestHandler = function(req, res, next) { + if (auth.getType(tokenFor(req)) == "App") ServeError(res, 403, "apps are not allowed to access this endpoint") + else next() + } + } \ No newline at end of file