Update img_verify

This commit is contained in:
2023-08-07 19:28:25 +08:00
parent cd86f44cee
commit af5667f337
14 changed files with 310 additions and 90 deletions

View File

@@ -3,10 +3,8 @@ import { get_task_manager } from "../../server.ts";
import { parse_cookies } from "../../server/cookies.ts";
import { return_error } from "../../server/utils.ts";
import type { Token } from "../../db.ts";
import pbkdf2Hmac from "pbkdf2-hmac";
import { encode } from "std/encoding/base64.ts";
async function handle_auth(req: Request, ctx: MiddlewareHandlerContext) {
function handle_auth(req: Request, ctx: MiddlewareHandlerContext) {
if (req.method === "OPTIONS") return true;
const m = get_task_manager();
if (m.db.get_user_count() === 0) return true;
@@ -18,43 +16,19 @@ async function handle_auth(req: Request, ctx: MiddlewareHandlerContext) {
token = cookies.get("token");
is_from_cookie = true;
}
const check = async () => {
const check = () => {
if (u.pathname === "/api/token" && req.method === "PUT") return true;
if (u.pathname === "/api/status" && req.method === "GET") return true;
if (m.cfg.img_verify_bypass_auth) {
if (
u.pathname.startsWith("/api/file") ||
u.pathname.startsWith("/api/thumbnail")
) {
if (ctx.params.id) {
const verify = u.searchParams.get("verify");
if (verify) {
const tverify = encode(
new Uint8Array(
await pbkdf2Hmac(
`${ctx.params.id}`,
m.cfg.img_verify_secret,
1000,
64,
"SHA-512",
),
),
);
if (verify === tverify) return true;
}
}
}
}
return false;
};
if (!token) return await check();
if (!token) return check();
const t = m.db.get_token(token);
const now = (new Date()).getTime();
if (!t || t.expired.getTime() < now) return await check();
if (!t || t.expired.getTime() < now) return check();
const user = m.db.get_user(t.uid);
if (!user) {
m.db.delete_token(token);
return await check();
return check();
}
ctx.state.user = user;
ctx.state.is_from_cookie = is_from_cookie;
@@ -63,7 +37,7 @@ async function handle_auth(req: Request, ctx: MiddlewareHandlerContext) {
}
export async function handler(req: Request, ctx: MiddlewareHandlerContext) {
if (!(await handle_auth(req, ctx))) {
if (!(handle_auth(req, ctx))) {
return return_error(401, "Unauthorized");
}
const res = await ctx.next();

View File

@@ -4,10 +4,11 @@ import {
get_file_response,
GetFileResponseOptions,
} from "../../../server/get_file_response.ts";
import { get_string } from "../../../server/parse_form.ts";
import { parse_bool } from "../../../server/parse_form.ts";
import pbkdf2Hmac from "pbkdf2-hmac";
import { encode } from "std/encoding/base64.ts";
import { get_host } from "../../../server/utils.ts";
import { get_host, return_data } from "../../../server/utils.ts";
import type { EhFileExtend } from "../../../server/files.ts";
export const handler: Handlers = {
async GET(req, ctx) {
@@ -16,21 +17,24 @@ export const handler: Handlers = {
return new Response("Bad Request", { status: 400 });
}
const m = get_task_manager();
const u = new URL(req.url);
const f = m.db.get_file(id);
const data = await parse_bool(u.searchParams.get("data"), false);
if (!f) {
return new Response("File not found.", { status: 404 });
}
if (data) {
return return_data<EhFileExtend>({
id: f.id,
height: f.height,
width: f.width,
is_original: f.is_original,
token: f.token,
});
}
const opts: GetFileResponseOptions = {};
if (m.cfg.img_verify_secret) {
let verify = null;
try {
const form = await req.formData();
verify = await get_string(form.get("verify"));
} catch (_) {
null;
const u = new URL(req.url);
verify = u.searchParams.get("verify");
}
const verify = u.searchParams.get("verify");
const tverify = encode(
new Uint8Array(
await pbkdf2Hmac(
@@ -46,14 +50,10 @@ export const handler: Handlers = {
const b = new URLSearchParams();
b.append("verify", tverify);
return Response.redirect(
`${get_host(req)}/api/file/${f.id}?${b}`,
`${get_host(req)}/file/${f.id}?${b}`,
);
}
if (verify !== tverify) {
return new Response("Invalid verify.", { status: 400 });
}
}
opts.cache_control = "public, max-age=31536000";
opts.range = req.headers.get("range");
opts.if_modified_since = req.headers.get("If-Modified-Since");
opts.if_unmodified_since = req.headers.get("If-Unmodified-Since");

View File

@@ -1,11 +1,7 @@
import { Handlers } from "$fresh/server.ts";
import { exists } from "std/fs/exists.ts";
import { get_task_manager } from "../../../server.ts";
import {
get_string,
parse_bool,
parse_int,
} from "../../../server/parse_form.ts";
import { parse_bool, parse_int } from "../../../server/parse_form.ts";
import { generate_filename, ThumbnailConfig } from "../../../thumbnail/base.ts";
import { sure_dir } from "../../../utils.ts";
import { ThumbnailMethod } from "../../../config.ts";
@@ -17,6 +13,7 @@ import {
import { get_host } from "../../../server/utils.ts";
import pbkdf2Hmac from "pbkdf2-hmac";
import { encode } from "std/encoding/base64.ts";
import { SortableURLSearchParams } from "../../../server/SortableURLSearchParams.ts";
export const handler: Handlers = {
async GET(req, ctx) {
@@ -80,38 +77,27 @@ export const handler: Handlers = {
}
const opts: GetFileResponseOptions = {};
if (m.cfg.img_verify_secret) {
let verify = null;
try {
const form = await req.formData();
verify = await get_string(form.get("verify"));
} catch (_) {
null;
const u = new URL(req.url);
verify = u.searchParams.get("verify");
}
const tverify = encode(
new Uint8Array(
await pbkdf2Hmac(
`${id}`,
m.cfg.img_verify_secret,
1000,
64,
"SHA-512",
),
),
);
const verify = u.searchParams.get("verify");
if (verify === null) {
const b = new URLSearchParams();
const bs = new SortableURLSearchParams(u.search, ["verify"]);
const tverify = encode(
new Uint8Array(
await pbkdf2Hmac(
`${id}${bs.toString2()}`,
m.cfg.img_verify_secret,
1000,
64,
"SHA-512",
),
),
);
const b = new URLSearchParams(bs.toString());
b.append("verify", tverify);
return Response.redirect(
`${get_host(req)}/api/thumbnail/${f.id}?${b}`,
`${get_host(req)}/thumbnail/${f.id}?${b}`,
);
}
if (verify !== tverify) {
return new Response("Invalid verify.", { status: 400 });
}
}
opts.cache_control = "public, max-age=31536000";
opts.range = req.headers.get("range");
opts.if_modified_since = req.headers.get("If-Modified-Since");
opts.if_unmodified_since = req.headers.get("If-Unmodified-Since");

48
routes/file/[id].ts Normal file
View File

@@ -0,0 +1,48 @@
import { Handlers } from "$fresh/server.ts";
import { get_task_manager } from "../../server.ts";
import {
get_file_response,
GetFileResponseOptions,
} from "../../server/get_file_response.ts";
import pbkdf2Hmac from "pbkdf2-hmac";
import { encode } from "std/encoding/base64.ts";
export const handler: Handlers = {
async GET(req, ctx) {
const id = parseInt(ctx.params.id);
if (isNaN(id)) {
return new Response("Bad Request", { status: 400 });
}
const m = get_task_manager();
const u = new URL(req.url);
if (!m.cfg.img_verify_secret) {
return new Response("Can not verify.", { status: 400 });
}
const verify = u.searchParams.get("verify");
if (!verify) return new Response("Verify is needed.", { status: 400 });
const tverify = encode(
new Uint8Array(
await pbkdf2Hmac(
`${id}`,
m.cfg.img_verify_secret,
1000,
64,
"SHA-512",
),
),
);
if (verify !== tverify) {
return new Response("verify is invalid.", { status: 400 });
}
const f = m.db.get_file(id);
if (!f) {
return new Response("File not found.", { status: 404 });
}
const opts: GetFileResponseOptions = {};
opts.cache_control = "public, no-transform, max-age=31536000";
opts.range = req.headers.get("range");
opts.if_modified_since = req.headers.get("If-Modified-Since");
opts.if_unmodified_since = req.headers.get("If-Unmodified-Since");
return await get_file_response(f.path, opts);
},
};

View File

@@ -0,0 +1,29 @@
import { MiddlewareHandlerContext } from "$fresh/server.ts";
export async function handler(req: Request, ctx: MiddlewareHandlerContext) {
const res = await ctx.next();
if (req.method === "OPTIONS" && res.status === 405) {
const headers = new Headers();
const allow = res.headers.get("Accept");
if (allow) headers.set("Allow", allow);
const origin = req.headers.get("origin");
if (origin) {
headers.set("Access-Control-Allow-Origin", "*");
if (allow) headers.set("Access-Control-Allow-Methods", allow);
headers.set("Access-Control-Allow-Headers", "Content-Type, Range");
}
return new Response(null, { status: 204, headers });
} else {
if (res.status === 101) return res;
const headers = new Headers(res.headers);
const origin = req.headers.get("origin");
if (origin) {
headers.set("Access-Control-Allow-Origin", "*");
}
return new Response(res.body, {
status: res.status,
headers: headers,
statusText: res.statusText,
});
}
}

83
routes/thumbnail/[id].ts Normal file
View File

@@ -0,0 +1,83 @@
import { Handlers } from "$fresh/server.ts";
import { exists } from "std/fs/exists.ts";
import { get_task_manager } from "../../server.ts";
import { parse_int } from "../../server/parse_form.ts";
import { generate_filename, ThumbnailConfig } from "../../thumbnail/base.ts";
import { sure_dir } from "../../utils.ts";
import {
get_file_response,
GetFileResponseOptions,
} from "../../server/get_file_response.ts";
import pbkdf2Hmac from "pbkdf2-hmac";
import { encode } from "std/encoding/base64.ts";
import { SortableURLSearchParams } from "../../server/SortableURLSearchParams.ts";
export const handler: Handlers = {
async GET(req, ctx) {
const id = parseInt(ctx.params.id);
if (isNaN(id)) {
return new Response("Bad Request", { status: 400 });
}
const m = get_task_manager();
const b = m.cfg.thumbnail_dir;
await sure_dir(b);
const f = m.db.get_file(id);
if (!f) {
return new Response("File not found.", { status: 404 });
}
const u = new URL(req.url);
if (!m.cfg.img_verify_secret) {
return new Response("Can not verify.", { status: 400 });
}
const verify = u.searchParams.get("verify");
if (!verify) return new Response("Verify is needed.", { status: 400 });
const bs = new SortableURLSearchParams(u.search, ["verify"]);
const tverify = encode(
new Uint8Array(
await pbkdf2Hmac(
`${id}${bs.toString2()}`,
m.cfg.img_verify_secret,
1000,
64,
"SHA-512",
),
),
);
if (verify !== tverify) {
return new Response("verify is invalid.", { status: 400 });
}
const max = await parse_int(u.searchParams.get("max"), 1200);
const width = await parse_int(u.searchParams.get("width"), null);
const height = await parse_int(u.searchParams.get("height"), null);
const quality = await parse_int(u.searchParams.get("quality"), 1);
const cfg: ThumbnailConfig = { width: 0, height: 0, quality };
if (width !== null && height !== null) {
cfg.width = width;
cfg.height = height;
} else if (width !== null) {
cfg.width = width;
cfg.height = Math.round(f.height / f.width * width);
} else if (height !== null) {
cfg.height = height;
cfg.width = Math.round(f.width / f.height * height);
} else {
if (f.width > f.height) {
cfg.width = max;
cfg.height = Math.round(f.height / f.width * max);
} else {
cfg.height = max;
cfg.width = Math.round(f.width / f.height * max);
}
}
const output = generate_filename(b, f, cfg);
if (!(await exists(output))) {
return new Response("file not exists.", { status: 500 });
}
const opts: GetFileResponseOptions = {};
opts.cache_control = "public, no-transform, max-age=31536000";
opts.range = req.headers.get("range");
opts.if_modified_since = req.headers.get("If-Modified-Since");
opts.if_unmodified_since = req.headers.get("If-Unmodified-Since");
return await get_file_response(output, opts);
},
};

View File

@@ -0,0 +1 @@
export { handler } from "../file/_middleware.ts";