From 21c05dd90dfb814860035c7c2ddb581c073c1048 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Wed, 7 Feb 2024 16:28:56 +0800 Subject: [PATCH] Add permissions check --- routes/api/config.ts | 13 +++++++++++-- routes/api/eh/image_limit.ts | 7 +++++-- routes/api/exit.ts | 7 ++++++- routes/api/export/gallery/zip/[gid].ts | 5 +++++ routes/api/file/[id].ts | 8 ++++++++ routes/api/file/random.ts | 10 +++++++++- routes/api/file/upload.ts | 12 ++++++++++-- routes/api/filemeta.ts | 22 +++++++++++++++++++--- routes/api/filemeta/[token].ts | 5 +++++ routes/api/files/[token].ts | 7 ++++++- routes/api/gallery/[gid].ts | 5 +++++ routes/api/gallery/list.ts | 8 ++++++++ routes/api/tag/[id].ts | 7 ++++++- routes/api/tag/rows.ts | 7 ++++++- routes/api/thumbnail/[id].ts | 8 ++++++++ routes/api/token.ts | 6 +++++- 16 files changed, 122 insertions(+), 15 deletions(-) diff --git a/routes/api/config.ts b/routes/api/config.ts index 18365a1..24848b5 100644 --- a/routes/api/config.ts +++ b/routes/api/config.ts @@ -8,6 +8,7 @@ import { import { parse_bool } from "../../server/parse_form.ts"; import { return_json } from "../../server/utils.ts"; import { ExitTarget } from "../../signal_handler.ts"; +import type { User } from "../../db.ts"; const UNSAFE_TYPE: (keyof ConfigType)[] = [ "base", @@ -21,7 +22,11 @@ const UNSAFE_TYPE: (keyof ConfigType)[] = [ const UNSAFE_TYPE2 = UNSAFE_TYPE as string[]; export const handler: Handlers = { - async GET(req, _ctx) { + async GET(req, ctx) { + const user = ctx.state.user; + if (user && !user.is_admin) { + return new Response("Permission denied", { status: 403 }); + } const u = new URL(req.url); const current = await parse_bool(u.searchParams.get("current"), false); if (current) { @@ -76,7 +81,11 @@ export const handler: Handlers = { const cfg = await load_settings(path); return return_json(cfg.to_json()); }, - async POST(req, _ctx) { + async POST(req, ctx) { + const user = ctx.state.user; + if (user && !user.is_admin) { + return new Response("Permission denied", { status: 403 }); + } const content_type = req.headers.get("Content-Type"); if (content_type === "application/json") { const d = await req.json(); diff --git a/routes/api/eh/image_limit.ts b/routes/api/eh/image_limit.ts index 7a75215..c06b66c 100644 --- a/routes/api/eh/image_limit.ts +++ b/routes/api/eh/image_limit.ts @@ -1,5 +1,5 @@ import { Handlers } from "$fresh/server.ts"; -import { User } from "../../../db.ts"; +import { User, UserPermission } from "../../../db.ts"; import { get_task_manager } from "../../../server.ts"; import { EHImageLimit } from "../../../server/eh.ts"; import { return_data, return_error } from "../../../server/utils.ts"; @@ -7,7 +7,10 @@ import { return_data, return_error } from "../../../server/utils.ts"; export const handler: Handlers = { async GET(_req, ctx) { const user = ctx.state.user; - if (user && !user.is_admin) { + if ( + user && !user.is_admin && + !(user.permissions & UserPermission.ManageTasks) + ) { return return_error(403, "Permission denied."); } const m = get_task_manager(); diff --git a/routes/api/exit.ts b/routes/api/exit.ts index 4581acb..48dc933 100644 --- a/routes/api/exit.ts +++ b/routes/api/exit.ts @@ -3,9 +3,14 @@ import { parse_bool } from "../../server/parse_form.ts"; import { get_task_manager } from "../../server.ts"; import { ExitTarget } from "../../signal_handler.ts"; import { AlreadyClosedError } from "../../task_manager.ts"; +import type { User } from "../../db.ts"; export const handler: Handlers = { - async POST(req, _ctx) { + async POST(req, ctx) { + const u = ctx.state.user; + if (u && !u.is_admin) { + return new Response("Permission denied.", { status: 403 }); + } let force = false; try { const form = await req.formData(); diff --git a/routes/api/export/gallery/zip/[gid].ts b/routes/api/export/gallery/zip/[gid].ts index 5e9b78b..dfee49a 100644 --- a/routes/api/export/gallery/zip/[gid].ts +++ b/routes/api/export/gallery/zip/[gid].ts @@ -3,9 +3,14 @@ import { get_task_manager } from "../../../../../server.ts"; import { get_export_zip_response } from "../../../../../server/export_zip.ts"; import { parse_bool, parse_int } from "../../../../../server/parse_form.ts"; import type { ExportZipConfig } from "../../../../../tasks/export_zip.ts"; +import { User, UserPermission } from "../../../../../db.ts"; export const handler: Handlers = { async GET(req, ctx) { + const u = ctx.state.user; + if (u && !u.is_admin && !(u.permissions & UserPermission.ReadGallery)) { + return new Response("Permission denied", { status: 403 }); + } const gid = parseInt(ctx.params.gid); if (isNaN(gid)) { return new Response("Bad Request", { status: 400 }); diff --git a/routes/api/file/[id].ts b/routes/api/file/[id].ts index e33d9ce..23759ca 100644 --- a/routes/api/file/[id].ts +++ b/routes/api/file/[id].ts @@ -9,9 +9,17 @@ import pbkdf2Hmac from "pbkdf2-hmac"; import { encodeBase64 as encode } from "std/encoding/base64.ts"; import { get_host, return_data, return_error } from "../../../server/utils.ts"; import type { EhFileExtend } from "../../../server/files.ts"; +import { User, UserPermission } from "../../../db.ts"; export const handler: Handlers = { async GET(req, ctx) { + const user = ctx.state.user; + if ( + user && !user.is_admin && + !(user.permissions & UserPermission.ReadGallery) + ) { + return return_error(403, "Permission denied."); + } const u = new URL(req.url); const data = await parse_bool(u.searchParams.get("data"), false); const id = parseInt(ctx.params.id); diff --git a/routes/api/file/random.ts b/routes/api/file/random.ts index 08c6be1..947f366 100644 --- a/routes/api/file/random.ts +++ b/routes/api/file/random.ts @@ -2,9 +2,17 @@ import { Handlers } from "$fresh/server.ts"; import { get_task_manager } from "../../../server.ts"; import { parse_bool } from "../../../server/parse_form.ts"; import { get_host } from "../../../server/utils.ts"; +import { User, UserPermission } from "../../../db.ts"; export const handler: Handlers = { - async GET(req, _ctx) { + async GET(req, ctx) { + const user = ctx.state.user; + if ( + user && !user.is_admin && + !(user.permissions & UserPermission.ReadGallery) + ) { + return new Response("Permission denied", { status: 403 }); + } const m = get_task_manager(); const u = new URL(req.url); const is_nsfw = await parse_bool(u.searchParams.get("is_nsfw"), null); diff --git a/routes/api/file/upload.ts b/routes/api/file/upload.ts index dbcbca1..9146cdb 100644 --- a/routes/api/file/upload.ts +++ b/routes/api/file/upload.ts @@ -1,5 +1,5 @@ import { Handlers } from "$fresh/server.ts"; -import type { EhFile } from "../../../db.ts"; +import type { EhFile, User } from "../../../db.ts"; import { get_task_manager } from "../../../server.ts"; import { return_data, return_error } from "../../../server/utils.ts"; import { get_string, parse_bool } from "../../../server/parse_form.ts"; @@ -7,9 +7,17 @@ import { fb_get_size } from "../../../thumbnail/ffmpeg_binary.ts"; import { sure_dir } from "../../../utils.ts"; import mime from "mime"; import { extname, join, resolve } from "std/path/mod.ts"; +import { UserPermission } from "../../../db.ts"; export const handler: Handlers = { - async POST(req, _ctx) { + async POST(req, ctx) { + const user = ctx.state.user; + if ( + user && !user.is_admin && + !(user.permissions & UserPermission.EditGallery) + ) { + return return_error(403, "Permission denied."); + } const m = get_task_manager(); try { const form = await req.formData(); diff --git a/routes/api/filemeta.ts b/routes/api/filemeta.ts index 7012abd..c95571b 100644 --- a/routes/api/filemeta.ts +++ b/routes/api/filemeta.ts @@ -3,6 +3,7 @@ import type { EhFileMeta } from "../../db.ts"; import { get_task_manager } from "../../server.ts"; import { get_string, parse_bool, parse_int } from "../../server/parse_form.ts"; import { return_data, return_error } from "../../server/utils.ts"; +import { User, UserPermission } from "../../db.ts"; export function get_filemeta(token: string) { const m = get_task_manager(); @@ -44,13 +45,24 @@ export function put_gallery_filemeta( } export const handler: Handlers = { - GET(req, _ctx) { + GET(req, ctx) { + const user = ctx.state.user; + if ( + user && !user.is_admin && + !(user.permissions & UserPermission.ReadGallery) + ) { + return return_error(403, "Permission denied."); + } const u = new URL(req.url); const token = u.searchParams.get("token"); if (token) return get_filemeta(token); return return_error(400, "token is needed."); }, - async POST(req, _ctx) { + async POST(req, ctx) { + const u = ctx.state.user; + if (u && !u.is_admin && !(u.permissions & UserPermission.EditGallery)) { + return return_error(403, "Permission denied."); + } const ct = req.headers.get("Content-Type")?.split(";")[0].trim() || ""; if (ct === "application/json") { if (!req.body) return_error(1, "Body not found."); @@ -198,7 +210,11 @@ export const handler: Handlers = { } return return_error(4, "Unknown format."); }, - async PUT(req, _ctx) { + async PUT(req, ctx) { + const u = ctx.state.user; + if (u && !u.is_admin && !(u.permissions & UserPermission.EditGallery)) { + return return_error(403, "Permission denied."); + } const ct = req.headers.get("Content-Type")?.split(";")[0].trim() || ""; if (ct === "application/json") { if (!req.body) return_error(1, "Body not found."); diff --git a/routes/api/filemeta/[token].ts b/routes/api/filemeta/[token].ts index a1980ff..97fdd5f 100644 --- a/routes/api/filemeta/[token].ts +++ b/routes/api/filemeta/[token].ts @@ -1,9 +1,14 @@ import { Handlers } from "$fresh/server.ts"; import { return_error } from "../../../server/utils.ts"; import { get_filemeta } from "../filemeta.ts"; +import { User, UserPermission } from "../../../db.ts"; export const handler: Handlers = { GET(_req, ctx) { + const u = ctx.state.user; + if (u && !u.is_admin && !(u.permissions & UserPermission.ReadGallery)) { + return return_error(403, "Permission denied."); + } const token = ctx.params.token; if (token) return get_filemeta(token); return return_error(400, "token is needed."); diff --git a/routes/api/files/[token].ts b/routes/api/files/[token].ts index e3e6a44..25f8d2d 100644 --- a/routes/api/files/[token].ts +++ b/routes/api/files/[token].ts @@ -1,10 +1,15 @@ import { Handlers } from "$fresh/server.ts"; import { get_task_manager } from "../../../server.ts"; import type { EhFiles } from "../../../server/files.ts"; -import { return_data } from "../../../server/utils.ts"; +import { return_data, return_error } from "../../../server/utils.ts"; +import { User, UserPermission } from "../../../db.ts"; export const handler: Handlers = { GET(_req, ctx) { + const u = ctx.state.user; + if (u && !u.is_admin && !(u.permissions & UserPermission.ReadGallery)) { + return return_error(403, "Permission denied."); + } const tokens = ctx.params.token.split(","); const m = get_task_manager(); const data: EhFiles = {}; diff --git a/routes/api/gallery/[gid].ts b/routes/api/gallery/[gid].ts index fd29e56..c5c3175 100644 --- a/routes/api/gallery/[gid].ts +++ b/routes/api/gallery/[gid].ts @@ -2,9 +2,14 @@ import { Handlers } from "$fresh/server.ts"; import { get_task_manager } from "../../../server.ts"; import type { GalleryData } from "../../../server/gallery.ts"; import { return_data, return_error } from "../../../server/utils.ts"; +import { User, UserPermission } from "../../../db.ts"; export const handler: Handlers = { GET(_req, ctx) { + const u = ctx.state.user; + if (u && !u.is_admin && !(u.permissions & UserPermission.ReadGallery)) { + return return_error(403, "Permission denied."); + } const gid = parseInt(ctx.params.gid); if (isNaN(gid)) { return return_error(400, "Failed to parse gid."); diff --git a/routes/api/gallery/list.ts b/routes/api/gallery/list.ts index f5db10c..3871c5c 100644 --- a/routes/api/gallery/list.ts +++ b/routes/api/gallery/list.ts @@ -2,6 +2,7 @@ import { Handlers } from "$fresh/server.ts"; import { get_task_manager } from "../../../server.ts"; import { parse_bool, parse_int } from "../../../server/parse_form.ts"; import { return_data, return_error } from "../../../server/utils.ts"; +import { User, UserPermission } from "../../../db.ts"; const ALLOW_FIELDS = [ "gid", @@ -23,6 +24,13 @@ const ALLOW_FIELDS = [ export const handler: Handlers = { async GET(req, _ctx) { + const user = _ctx.state.user; + if ( + user && !user.is_admin && + !(user.permissions & UserPermission.ReadGallery) + ) { + return return_error(403, "Permission denied."); + } const u = new URL(req.url); const t = get_task_manager(); const all = await parse_bool(u.searchParams.get("all"), false); diff --git a/routes/api/tag/[id].ts b/routes/api/tag/[id].ts index 9a68a7a..1e2c11a 100644 --- a/routes/api/tag/[id].ts +++ b/routes/api/tag/[id].ts @@ -1,15 +1,20 @@ import { Handlers } from "$fresh/server.ts"; import { get_task_manager } from "../../../server.ts"; -import { Tag } from "../../../db.ts"; +import { Tag, User, UserPermission } from "../../../db.ts"; import { gen_data, gen_error, JSONResult, return_data, + return_error, } from "../../../server/utils.ts"; export const handler: Handlers = { GET(_req, ctx) { + const u = ctx.state.user; + if (u && !u.is_admin && !(u.permissions & UserPermission.ReadGallery)) { + return return_error(403, "Permission denied."); + } const ids = ctx.params.id.split(","); const r: Record> = {}; for (const _id of ids) { diff --git a/routes/api/tag/rows.ts b/routes/api/tag/rows.ts index 1793fd5..ea1d2e1 100644 --- a/routes/api/tag/rows.ts +++ b/routes/api/tag/rows.ts @@ -1,9 +1,14 @@ import { Handlers } from "$fresh/server.ts"; import { get_task_manager } from "../../../server.ts"; -import { return_data } from "../../../server/utils.ts"; +import { return_data, return_error } from "../../../server/utils.ts"; +import { User, UserPermission } from "../../../db.ts"; export const handler: Handlers = { GET(_req, _ctx) { + const u = _ctx.state.user; + if (u && !u.is_admin && !(u.permissions & UserPermission.ReadGallery)) { + return return_error(403, "Permission denied."); + } const m = get_task_manager(); return return_data(m.db.get_tag_rows()); }, diff --git a/routes/api/thumbnail/[id].ts b/routes/api/thumbnail/[id].ts index 3c7337e..be94af5 100644 --- a/routes/api/thumbnail/[id].ts +++ b/routes/api/thumbnail/[id].ts @@ -22,11 +22,19 @@ import pbkdf2Hmac from "pbkdf2-hmac"; import { encodeBase64 as encode } from "std/encoding/base64.ts"; import { SortableURLSearchParams } from "../../../server/SortableURLSearchParams.ts"; import type * as FFMPEG_API from "../../../thumbnail/ffmpeg_api.ts"; +import { User, UserPermission } from "../../../db.ts"; let ffmpeg_api: typeof FFMPEG_API | undefined; export const handler: Handlers = { async GET(req, ctx) { + const user = ctx.state.user; + if ( + user && !user.is_admin && + !(user.permissions & UserPermission.ReadGallery) + ) { + return new Response("Permission denied", { status: 403 }); + } const id = parseInt(ctx.params.id); if (isNaN(id)) { return new Response("Bad Request", { status: 400 }); diff --git a/routes/api/token.ts b/routes/api/token.ts index aa48508..4123d52 100644 --- a/routes/api/token.ts +++ b/routes/api/token.ts @@ -5,7 +5,7 @@ import { return_data, return_error } from "../../server/utils.ts"; import { get_task_manager } from "../../server.ts"; import pbkdf2Hmac from "pbkdf2-hmac"; import isEqual from "lodash/isEqual"; -import type { Token } from "../../db.ts"; +import type { Token, User } from "../../db.ts"; import { Mutex } from "async/mutex.ts"; const USER_PASSWORD_ERROR = "Incorrect username or password."; @@ -58,6 +58,10 @@ export const handler: Handlers = { const m = get_task_manager(); const token = m.db.get_token(t); if (!token) return return_error(404, "token not found."); + const user = ctx.state.user; + if (user && !user.is_admin && token.uid !== user.id) { + return return_error(403, "Permission denied."); + } m.db.delete_token(t); const headers: HeadersInit = {}; if (is_from_auth && is_from_cookie) {