token-permissions: update authRoutes

This commit is contained in:
May 2023-10-02 19:14:00 -07:00
parent fad320d7fb
commit 2006fa1cca
3 changed files with 42 additions and 34 deletions

View file

@ -1,4 +1,5 @@
import crypto from "crypto"
import express from "express"
import { readFile, writeFile } from "fs/promises"
export let AuthTokens: AuthToken[] = []
export let AuthTokenTO:{[key:string]:NodeJS.Timeout} = {}
@ -6,8 +7,10 @@ export let AuthTokenTO:{[key:string]:NodeJS.Timeout} = {}
export const ValidTokenPermissions = [
"user", // permissions to /auth/me, with email docked
"email", // adds email back to /auth/me
"private", // allows app to read private files
"upload", // allows an app to upload under an account
"manage", // allows an app to manage an account's files
"customize", // allows an app to change customization settings
"admin" // only available for accounts with admin
// gives an app access to all admin tools
] as const
@ -48,6 +51,14 @@ export function create(
return token.token
}
export function tokenFor(req: express.Request) {
return req.cookies.auth || (
req.header("authorization")?.startsWith("Bearer ")
? req.header("authorization")?.split(" ")[1]
: undefined
)
}
export function validate(token:string) {
return AuthTokens.find(e => e.token == token && Date.now() < e.expire)?.account
}

View file

@ -3,16 +3,8 @@ import express, { type RequestHandler } from "express"
import ServeError from "../lib/errors";
import * as auth from "./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))
res.locals.acc = Accounts.getFromToken(auth.tokenFor(req))
next()
}
@ -40,7 +32,7 @@ export const requiresAdmin: RequestHandler = function(_req, res, next) {
export const requiresPermissions = function(...tokenPermissions: auth.TokenPermission[]): RequestHandler {
return function(req, res, next) {
let token = tokenFor(req)
let token = auth.tokenFor(req)
let type = auth.getType(token)
if (type == "App") {
@ -67,6 +59,6 @@ export const requiresPermissions = function(...tokenPermissions: auth.TokenPermi
*/
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")
if (auth.getType(auth.tokenFor(req)) == "App") ServeError(res, 403, "apps are not allowed to access this endpoint")
else next()
}

View file

@ -3,7 +3,7 @@ import { Router } from "express";
import * as Accounts from "../lib/accounts";
import * as auth from "../lib/auth";
import { sendMail } from "../lib/mail";
import { getAccount, requiresAccount } from "../lib/middleware"
import { getAccount, noAPIAccess, requiresAccount, requiresPermissions } from "../lib/middleware"
import { accountRatelimit } from "../lib/ratelimit"
import ServeError from "../lib/errors";
@ -123,7 +123,7 @@ authRoutes.post("/logout", (req,res) => {
res.send("logged out")
})
authRoutes.post("/dfv", requiresAccount, parser, (req,res) => {
authRoutes.post("/dfv", requiresAccount, requiresPermissions("manage"), parser, (req,res) => {
let acc = res.locals.acc as Accounts.Account
if (['public','private','anonymous'].includes(req.body.defaultFileVisibility)) {
@ -136,7 +136,7 @@ authRoutes.post("/dfv", requiresAccount, parser, (req,res) => {
}
})
authRoutes.post("/customcss", requiresAccount, parser, (req,res) => {
authRoutes.post("/customcss", requiresAccount, requiresPermissions("customize"), parser, (req,res) => {
let acc = res.locals.acc as Accounts.Account
if (typeof req.body.fileId != "string") req.body.fileId = undefined;
@ -158,7 +158,7 @@ authRoutes.post("/customcss", requiresAccount, parser, (req,res) => {
}
})
authRoutes.post("/embedcolor", requiresAccount, parser, (req,res) => {
authRoutes.post("/embedcolor", requiresAccount, requiresPermissions("customize"), parser, (req,res) => {
let acc = res.locals.acc as Accounts.Account
if (typeof req.body.color != "string") req.body.color = undefined;
@ -181,7 +181,7 @@ authRoutes.post("/embedcolor", requiresAccount, parser, (req,res) => {
}
})
authRoutes.post("/embedsize", requiresAccount, parser, (req,res) => {
authRoutes.post("/embedsize", requiresAccount, requiresPermissions("customize"), parser, (req,res) => {
let acc = res.locals.acc as Accounts.Account
if (typeof req.body.largeImage != "boolean") req.body.color = false;
@ -193,7 +193,7 @@ authRoutes.post("/embedsize", requiresAccount, parser, (req,res) => {
res.send(`custom embed image size saved`)
})
authRoutes.post("/delete_account", requiresAccount, parser, async (req,res) => {
authRoutes.post("/delete_account", requiresAccount, noAPIAccess, parser, async (req,res) => {
let acc = res.locals.acc as Accounts.Account
let accId = acc.id
@ -217,7 +217,7 @@ authRoutes.post("/delete_account", requiresAccount, parser, async (req,res) => {
} else cpl()
})
authRoutes.post("/change_username", requiresAccount, parser, (req,res) => {
authRoutes.post("/change_username", requiresAccount, noAPIAccess, parser, (req,res) => {
let acc = res.locals.acc as Accounts.Account
if (typeof req.body.username != "string" || req.body.username.length < 3 || req.body.username.length > 20) {
@ -253,7 +253,7 @@ authRoutes.post("/change_username", requiresAccount, parser, (req,res) => {
let verificationCodes = new Map<string, {code: string, email: string, expiry: NodeJS.Timeout}>()
authRoutes.post("/request_email_change", requiresAccount, accountRatelimit({ requests: 4, per: 60*60*1000 }), parser, (req,res) => {
authRoutes.post("/request_email_change", requiresAccount, noAPIAccess, accountRatelimit({ requests: 4, per: 60*60*1000 }), parser, (req,res) => {
let acc = res.locals.acc as Accounts.Account
@ -292,7 +292,7 @@ authRoutes.post("/request_email_change", requiresAccount, accountRatelimit({ req
})
})
authRoutes.get("/confirm_email/:code", requiresAccount, (req,res) => {
authRoutes.get("/confirm_email/:code", requiresAccount, noAPIAccess, (req,res) => {
let acc = res.locals.acc as Accounts.Account
@ -314,7 +314,7 @@ authRoutes.get("/confirm_email/:code", requiresAccount, (req,res) => {
}
})
authRoutes.post("/remove_email", requiresAccount, (req,res) => {
authRoutes.post("/remove_email", requiresAccount, noAPIAccess, (req,res) => {
let acc = res.locals.acc as Accounts.Account
if (acc.email) {
@ -404,7 +404,7 @@ authRoutes.get("/emergency_login/:code", (req,res) => {
}
})
authRoutes.post("/change_password", requiresAccount, parser, (req,res) => {
authRoutes.post("/change_password", requiresAccount, noAPIAccess, parser, (req,res) => {
let acc = res.locals.acc as Accounts.Account
if (typeof req.body.password != "string" || req.body.password.length < 8) {
@ -429,7 +429,7 @@ authRoutes.post("/change_password", requiresAccount, parser, (req,res) => {
res.send("password changed - logged out all sessions")
})
authRoutes.post("/logout_sessions", requiresAccount, (req,res) => {
authRoutes.post("/logout_sessions", requiresAccount, noAPIAccess, (req,res) => {
let acc = res.locals.acc as Accounts.Account
let accId = acc.id
@ -441,15 +441,20 @@ authRoutes.post("/logout_sessions", requiresAccount, (req,res) => {
res.send("logged out all sessions")
})
authRoutes.get("/me", requiresAccount, (req,res) => {
authRoutes.get("/me", requiresAccount, requiresPermissions("user"), (req,res) => {
let acc = res.locals.acc as Accounts.Account
let sessionToken = auth.tokenFor(req)
let accId = acc.id
res.send({
...acc,
sessionCount: auth.AuthTokens.filter(e => e.account == accId && e.expire > Date.now()).length,
sessionExpires: auth.AuthTokens.find(e => e.token == req.cookies.auth)?.expire,
password: undefined
sessionCount: auth.AuthTokens.filter(e => e.type != "App" && e.account == accId && e.expire > Date.now()).length,
sessionExpires: auth.AuthTokens.find(e => e.token == sessionToken)?.expire,
password: undefined,
email:
auth.getType(sessionToken) == "User" || auth.getPermissions(sessionToken)?.includes("email")
? acc.email
: undefined
})
})