mirror of
https://github.com/lifegpc/eh-downloader.git
synced 2026-06-10 07:38:52 +08:00
103 lines
4.1 KiB
TypeScript
103 lines
4.1 KiB
TypeScript
import { Handlers } from "$fresh/server.ts";
|
|
import { decode } from "std/encoding/base64.ts";
|
|
import { get_string, parse_bool, parse_int } from "../../server/parse_form.ts";
|
|
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";
|
|
|
|
const USER_PASSWORD_ERROR = "Incorrect username or password.";
|
|
|
|
export const handler: Handlers = {
|
|
async DELETE(req, ctx) {
|
|
let t: string | undefined | null;
|
|
try {
|
|
const data = await req.formData();
|
|
t = await get_string(data.get("token"));
|
|
} catch (_) {
|
|
null;
|
|
}
|
|
let is_from_auth = false;
|
|
const ttoken = <Token | undefined> ctx.state.token;
|
|
const is_from_cookie = <boolean | undefined> ctx.state.is_from_cookie;
|
|
if (!t && ttoken) {
|
|
t = ttoken.token;
|
|
is_from_auth = true;
|
|
}
|
|
if (!t) return return_error(1, "token not specified.");
|
|
const m = get_task_manager();
|
|
const token = m.db.get_token(t);
|
|
if (!token) return return_error(404, "token not found.");
|
|
m.db.delete_token(t);
|
|
const headers: HeadersInit = {};
|
|
if (is_from_auth && is_from_cookie) {
|
|
headers["Set-Cookie"] = `token=${token.token}; Max-Age=0${
|
|
token.http_only ? "; HttpOnly" : ""
|
|
}${token.secure ? "; Secure" : ""}; Path=/api`;
|
|
}
|
|
return return_data(true, 200, headers);
|
|
},
|
|
GET(req, ctx) {
|
|
const u = new URL(req.url);
|
|
let t = u.searchParams.get("token");
|
|
const ttoken = <Token | undefined> ctx.state.token;
|
|
if (!t && ttoken) t = ttoken.token;
|
|
if (!t) return return_error(1, "token not specififed.");
|
|
const m = get_task_manager();
|
|
const token = m.db.get_token(t);
|
|
if (!token) return return_error(404, "token not found.");
|
|
const user = m.db.get_user(token.uid);
|
|
if (!user) return return_error(404, "user not found.");
|
|
return return_data({
|
|
token,
|
|
name: user.username,
|
|
is_admin: user.is_admin,
|
|
permissions: user.permissions,
|
|
});
|
|
},
|
|
async PUT(req, _ctx) {
|
|
const data = await req.formData();
|
|
const username = await get_string(data.get("username"));
|
|
if (!username) return return_error(1, "username not specified.");
|
|
const p = await get_string(data.get("password"));
|
|
if (!p) return return_error(1, "password not specified.");
|
|
let password = null;
|
|
try {
|
|
password = decode(p);
|
|
} catch (_) {
|
|
return return_error(2, "Failed to decode password with base64.");
|
|
}
|
|
if (password.length !== 64) {
|
|
return return_error(2, "Password need 64 bytes.");
|
|
}
|
|
const t = await parse_int(data.get("t"), null);
|
|
if (t === null) return return_error(1, "t not specified.");
|
|
const now = (new Date()).getTime();
|
|
if (t > now + 60000 || t < now - 60000) {
|
|
return return_error(3, "Time is not corrected.");
|
|
}
|
|
const set_cookie = await parse_bool(data.get("set_cookie"), false);
|
|
const http_only = await parse_bool(data.get("http_only"), true);
|
|
const secure = await parse_bool(data.get("secure"), false);
|
|
const m = get_task_manager();
|
|
const u = m.db.get_user_by_name(username);
|
|
if (!u) return return_error(4, USER_PASSWORD_ERROR);
|
|
const pa = new Uint8Array(
|
|
await pbkdf2Hmac(u.password, t.toString(), 1000, 64, "SHA-512"),
|
|
);
|
|
if (!isEqual(pa, password)) {
|
|
return return_error(4, USER_PASSWORD_ERROR);
|
|
}
|
|
const token = m.db.add_token(u.id, now, http_only, secure);
|
|
const headers: HeadersInit = {};
|
|
if (set_cookie) {
|
|
headers["Set-Cookie"] =
|
|
`token=${token.token}; Expires=${token.expired.toUTCString()}${
|
|
http_only ? "; HttpOnly" : ""
|
|
}${secure ? "; Secure" : ""}; Path=/api`;
|
|
}
|
|
return return_data(token, 201, headers);
|
|
},
|
|
};
|