This commit is contained in:
2023-07-03 11:51:13 +08:00
parent b777b4758c
commit 0f3bf48c70
6 changed files with 216 additions and 17 deletions

View File

@@ -1,6 +1,39 @@
import { MiddlewareHandlerContext } from "$fresh/server.ts";
import { get_task_manager } from "../../server.ts";
import { parse_cookies } from "../../server/cookies.ts";
import { return_error } from "../../server/utils.ts";
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;
const u = new URL(req.url);
let token: string | null | undefined = req.headers.get("X-TOKEN");
const cookies = parse_cookies(req.headers.get("Cookies"));
if (!token) {
token = cookies.get("token");
}
if (!token) {
if (u.pathname === "/api/token" && req.method === "PUT") return true;
if (u.pathname === "/api/status" && req.method === "GET") return true;
return false;
}
const t = m.db.get_token(token);
const now = (new Date()).getTime();
if (!t || t.expired.getTime() < now) return false;
const user = m.db.get_user(t.uid);
if (!user) {
m.db.delete_token(token);
return false;
}
ctx.state.user = user;
return true;
}
export async function handler(req: Request, ctx: MiddlewareHandlerContext) {
if (!handle_auth(req, ctx)) {
return return_error(401, "Unauthorized");
}
const res = await ctx.next();
if (req.method === "OPTIONS" && res.status === 405) {
const headers = new Headers();

View File

@@ -9,7 +9,34 @@ import isEqual from "lodash/isEqual";
const USER_PASSWORD_ERROR = "Incorrect username or password.";
export const handler: Handlers = {
async POST(req, _ctx) {
async DELETE(req, _ctx) {
const data = await req.formData();
const t = await get_string(data.get("token"));
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);
return return_data(true);
},
GET(req, _ctx) {
const u = new URL(req.url);
const t = u.searchParams.get("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);
m.db.delete_token(t);
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.");
@@ -34,12 +61,12 @@ export const handler: Handlers = {
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),
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);
return return_data(token);
return return_data(token, 201);
},
};

77
routes/api/user.ts Normal file
View File

@@ -0,0 +1,77 @@
import { Handlers } from "$fresh/server.ts";
import { User, UserPermission } 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 pbkdf2Hmac from "pbkdf2-hmac";
export const handler: Handlers = {
async GET(req, ctx) {
const u = new URL(req.url);
const id = await parse_int(u.searchParams.get("id"), null);
const username = u.searchParams.get("username");
const user = <User | undefined> ctx.state.user;
if (id === null && !username && !user) {
return return_error(1, "user not specified.");
}
const m = get_task_manager();
const us = id !== null
? m.db.get_user(id)
: username
? m.db.get_user_by_name(username)
: user;
if (!us) return return_error(404, "User not found.");
if (user && !user.is_admin && us.id !== user.id) {
return return_error(403, "Permission denied.");
}
return return_data({
id: us.id,
username: us.username,
is_admin: us.is_admin,
permissions: us.permissions,
});
},
async PUT(req, ctx) {
const data = await req.formData();
const user = <User | undefined> ctx.state.user;
if (user && !user.is_admin) {
return return_error(403, "Permission denied.");
}
const name = await get_string(data.get("name"));
const password = await get_string(data.get("password"));
const is_admin = await parse_bool(data.get("is_admin"), false);
let permissions: UserPermission = await parse_int(
data.get("permissions"),
UserPermission.None,
);
if (!name) return return_error(1, "name not specified.");
if (!password) return return_error(1, "password not specified.");
if (is_admin) permissions = UserPermission.All;
const m = get_task_manager();
if (m.db.get_user_by_name(name)) {
return return_error(2, "Please change to another name.");
}
const hpassword = new Uint8Array(
await pbkdf2Hmac(
password,
"eh-downloader-salt",
210000,
64,
"SHA-512",
),
);
if (m.db.get_user_count() === 0) {
m.db.add_root_user(name, hpassword);
return return_data(0, 201);
} else {
const t = m.db.add_user({
id: 0,
username: name,
password: hpassword,
is_admin,
permissions,
});
return return_data(t.id, 201);
}
},
};