You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.2 KiB
108 lines
3.2 KiB
import assert from "node:assert/strict";
|
|
import { createHmac } from "node:crypto";
|
|
import test from "node:test";
|
|
import { createRequire } from "node:module";
|
|
|
|
const require = createRequire(import.meta.url);
|
|
const {
|
|
issueAgentAccessToken,
|
|
resolveAgentUserId,
|
|
} = require("../app/utils/agentJwt");
|
|
|
|
const decodeJwtPart = (part) => JSON.parse(Buffer.from(part, "base64url").toString("utf8"));
|
|
|
|
test("resolveAgentUserId matches previous X-User-Id order", () => {
|
|
assert.equal(
|
|
resolveAgentUserId({
|
|
localUserId: "local-1",
|
|
id: "id-2",
|
|
pepUserId: "pep-88",
|
|
}),
|
|
"local-1",
|
|
);
|
|
assert.equal(
|
|
resolveAgentUserId({
|
|
id: "id-2",
|
|
pepUserId: "pep-88",
|
|
}),
|
|
"id-2",
|
|
);
|
|
});
|
|
|
|
test("resolveAgentUserId reads nested AIUserInfo", () => {
|
|
assert.equal(
|
|
resolveAgentUserId({
|
|
token: "ai-center-token",
|
|
AIUserInfo: { id: "center-user-9" },
|
|
}),
|
|
"center-user-9",
|
|
);
|
|
});
|
|
|
|
test("issueAgentAccessToken signs HS256 JWT with userid as sub", () => {
|
|
const secret = "local-development-only-long-random-secret";
|
|
const issued = issueAgentAccessToken({
|
|
userInfo: { id: "user-42" },
|
|
config: {
|
|
algorithm: "HS256",
|
|
secret,
|
|
expiresInSeconds: 3600,
|
|
},
|
|
now: 1_700_000_000_000,
|
|
});
|
|
|
|
assert.equal(issued.token_type, "Bearer");
|
|
assert.equal(issued.sub, "user-42");
|
|
assert.equal(issued.expires_in, 3600);
|
|
assert.equal(issued.expires_at, 1_700_000_000 + 3600);
|
|
|
|
const [headerPart, payloadPart, signaturePart] = issued.token.split(".");
|
|
const header = decodeJwtPart(headerPart);
|
|
const payload = decodeJwtPart(payloadPart);
|
|
const expectedSignature = createHmac("sha256", secret)
|
|
.update(`${headerPart}.${payloadPart}`)
|
|
.digest("base64url");
|
|
|
|
assert.equal(header.alg, "HS256");
|
|
assert.equal(payload.sub, "user-42");
|
|
assert.equal(payload.iat, 1_700_000_000);
|
|
assert.equal(payload.exp, 1_700_000_000 + 3600);
|
|
assert.equal(signaturePart, expectedSignature);
|
|
assert.equal(payload.iss, undefined);
|
|
assert.equal(payload.aud, undefined);
|
|
});
|
|
|
|
test("issueAgentAccessToken writes issuer and audience when configured", () => {
|
|
const issued = issueAgentAccessToken({
|
|
userInfo: { userId: "user-7" },
|
|
config: {
|
|
algorithm: "HS256",
|
|
secret: "secret",
|
|
issuer: "query-api",
|
|
audience: "freesun-agent2",
|
|
},
|
|
});
|
|
const payload = decodeJwtPart(issued.token.split(".")[1]);
|
|
assert.equal(payload.iss, "query-api");
|
|
assert.equal(payload.aud, "freesun-agent2");
|
|
});
|
|
|
|
test("issueAgentAccessToken rejects missing userid", () => {
|
|
assert.throws(
|
|
() => issueAgentAccessToken({
|
|
userInfo: {},
|
|
config: { algorithm: "HS256", secret: "secret" },
|
|
}),
|
|
(error) => error.status === 401 && /认证用户信息无效/.test(error.message),
|
|
);
|
|
});
|
|
|
|
test("issueAgentAccessToken rejects missing HS256 secret", () => {
|
|
assert.throws(
|
|
() => issueAgentAccessToken({
|
|
userInfo: { id: "user-1" },
|
|
config: { algorithm: "HS256", secret: "" },
|
|
}),
|
|
(error) => error.status === 503 && /未配置 Agent JWT 签名密钥/.test(error.message),
|
|
);
|
|
});
|
|
|