2026-04-14 18:05:32 +08:00

135 lines
3.0 KiB
TypeScript

import { getUserByUsername, writeAuthAudit } from "@/lib/store";
import { parseHy2Userpass, verifyNodeToken, evaluateUserForAuth } from "@/lib/hy2";
import { verifyPassword } from "@/lib/password";
type AuthRequest = {
addr?: string;
auth?: string;
tx?: number;
};
function deny(id = "") {
return Response.json({ ok: false, id });
}
export async function POST(
request: Request,
context: RouteContext<"/api/hy2/nodes/[slug]/auth">,
) {
const { slug } = await context.params;
const requestUrl = new URL(request.url);
const token =
requestUrl.searchParams.get("token") ||
request.headers.get("authorization")?.replace(/^Bearer\s+/i, "") ||
request.headers.get("x-node-token");
const nodeResult = await verifyNodeToken(slug, token);
if (!nodeResult.ok) {
await writeAuthAudit({
nodeId: nodeResult.node?.id ?? null,
ok: false,
reason: nodeResult.reason,
});
return deny();
}
const node = nodeResult.node;
if (!node) {
return deny();
}
let payload: AuthRequest;
try {
payload = (await request.json()) as AuthRequest;
} catch {
await writeAuthAudit({
nodeId: node.id,
addr: null,
requestedTx: null,
ok: false,
reason: "bad_json",
});
return deny();
}
if (!payload.auth) {
await writeAuthAudit({
nodeId: node.id,
addr: payload.addr ?? null,
requestedTx: payload.tx ?? null,
ok: false,
reason: "missing_auth",
});
return deny();
}
const parsed = parseHy2Userpass(payload.auth);
if (!parsed) {
await writeAuthAudit({
nodeId: node.id,
addr: payload.addr ?? null,
requestedTx: payload.tx ?? null,
ok: false,
reason: "bad_auth_format",
});
return deny();
}
const user = await getUserByUsername(parsed.username);
if (!user) {
await writeAuthAudit({
nodeId: node.id,
username: parsed.username,
addr: payload.addr ?? null,
requestedTx: payload.tx ?? null,
ok: false,
reason: "user_not_found",
});
return deny();
}
const passwordOk = await verifyPassword(parsed.password, user.password_hash);
if (!passwordOk) {
await writeAuthAudit({
nodeId: node.id,
userId: user.id,
authId: user.auth_id,
username: user.username,
addr: payload.addr ?? null,
requestedTx: payload.tx ?? null,
ok: false,
reason: "password_invalid",
});
return deny();
}
const access = evaluateUserForAuth(user);
if (!access.ok) {
await writeAuthAudit({
nodeId: node.id,
userId: user.id,
authId: user.auth_id,
username: user.username,
addr: payload.addr ?? null,
requestedTx: payload.tx ?? null,
ok: false,
reason: access.reason,
});
return deny();
}
await writeAuthAudit({
nodeId: node.id,
userId: user.id,
authId: user.auth_id,
username: user.username,
addr: payload.addr ?? null,
requestedTx: payload.tx ?? null,
ok: true,
reason: "ok",
});
return Response.json({ ok: true, id: user.auth_id });
}