/**
* 制御盤向けのルート(`app/api/ds-agent/**`)の先頭で必ず呼ぶ認証(指示書AY 段階5-5。D5・D19)。
*
* proxy の `authenticateAgent()` が既に通しているが、★ルートでも Bearer を再検証して serial を得る★
* (proxy から後段へ serial をヘッダで渡さない。ヘッダは詐称できるため。D5)。
* 通ったら relay の `touch()` で最終接続日時と版を更新する(★すべての制御盤のリクエストで。表5 R7・D19・指示書BJ J9★)。
*/
import { NextResponse } from "next/server";
import { getRelay } from "@/lib/ds-agent/relay";
import { verifyAgentAuthorization } from "@/lib/ds-agent/tokens";
import type { ApiError } from "@/lib/types";
export type RequireAgentResult = { ok: true; serial: string } | { ok: false; response: Response };
/** 合わなければ `null`(拒否しない)。接続の記録に使う(指示書BJ J9) */
const AGENT_VERSION = /^[0-9A-Za-z.+-]{1,32}$/;
export function agentVersionOf(request: Request): string | null {
const raw = request.headers.get("x-agent-version");
return raw !== null && AGENT_VERSION.test(raw) ? raw : null;
}
export async function requireAgent(request: Request): Promise<RequireAgentResult> {
const serial = await verifyAgentAuthorization(request.headers.get("authorization"));
if (serial === null) {
const body: ApiError = { error: { code: "unauthorized", message: "認証が必要です", details: null } };
return { ok: false, response: NextResponse.json(body, { status: 401 }) };
}
getRelay().touch(serial, agentVersionOf(request));
return { ok: true, serial };
}