GitHub(nextgroup2706/ken_nogi)は今後使わず自社Gitea運用に切替え。 NodeSrvは旧リポジトリの履歴を破棄しファイルのみ統合(Dokploy用サービスアカウントは 別途mygit-admin/NodeSrv.gitに履歴あり)。notepmエクスポート(12GB)とPleasanter インストーラzip(208MB)はサイズが大きいため.gitignoreで除外。 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
60 lines
2.2 KiB
JavaScript
60 lines
2.2 KiB
JavaScript
const { test } = require("node:test");
|
|
const assert = require("node:assert");
|
|
const crypto = require("node:crypto");
|
|
const { buildAssertion, fetchAccessToken } = require("../src/lib/lineworksAuth");
|
|
|
|
function base64urlDecode(str) {
|
|
return Buffer.from(str.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
}
|
|
|
|
test("buildAssertion produces a valid RS256 JWT signed with the given private key", () => {
|
|
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 });
|
|
const now = new Date("2026-08-08T00:00:00Z").getTime();
|
|
|
|
const jwt = buildAssertion({
|
|
clientId: "test-client-id",
|
|
serviceAccount: "svc@example.com",
|
|
privateKey: privateKey.export({ type: "pkcs1", format: "pem" }),
|
|
now,
|
|
});
|
|
|
|
const [headerB64, payloadB64, sigB64] = jwt.split(".");
|
|
const header = JSON.parse(base64urlDecode(headerB64).toString("utf8"));
|
|
const payload = JSON.parse(base64urlDecode(payloadB64).toString("utf8"));
|
|
|
|
assert.deepStrictEqual(header, { alg: "RS256", typ: "JWT" });
|
|
assert.strictEqual(payload.iss, "test-client-id");
|
|
assert.strictEqual(payload.sub, "svc@example.com");
|
|
assert.strictEqual(payload.exp - payload.iat, 3600);
|
|
|
|
const verifier = crypto.createVerify("RSA-SHA256");
|
|
verifier.update(`${headerB64}.${payloadB64}`);
|
|
const isValid = verifier.verify(publicKey, base64urlDecode(sigB64));
|
|
assert.strictEqual(isValid, true);
|
|
});
|
|
|
|
test("fetchAccessToken posts a jwt-bearer grant and returns the access_token", async () => {
|
|
const { privateKey } = crypto.generateKeyPairSync("rsa", { modulusLength: 2048 });
|
|
let capturedBody;
|
|
const fetchImpl = async (url, opts) => {
|
|
capturedBody = opts.body;
|
|
return {
|
|
ok: true,
|
|
json: async () => ({ access_token: "fake-token", expires_in: 3600 }),
|
|
};
|
|
};
|
|
|
|
const token = await fetchAccessToken({
|
|
clientId: "cid",
|
|
clientSecret: "secret",
|
|
serviceAccount: "svc@example.com",
|
|
privateKey: privateKey.export({ type: "pkcs1", format: "pem" }),
|
|
scope: "directory.read",
|
|
fetchImpl,
|
|
});
|
|
|
|
assert.strictEqual(token, "fake-token");
|
|
assert.ok(capturedBody.includes("grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer"));
|
|
assert.ok(capturedBody.includes("client_id=cid"));
|
|
});
|