import test from "node:test"; import assert from "node:assert/strict"; import {mkdtempSync, readFileSync, rmSync} from "node:fs"; import {tmpdir} from "node:os"; import {join} from "node:path"; import {createAuthentikAdmin} from "./authentik.mjs"; const user = { pk: 3, uuid: "user-uuid", username: "liooil", name: "西腾", email: "liooil@example.com", is_active: true, is_superuser: true, type: "internal", path: "users", groups_obj: [{pk: "group-id", name: "liuhome"}], last_login: null, date_joined: "2026-01-01T00:00:00Z" }; const group = {pk: "group-id", name: "liuhome", is_superuser: false, users: [3], users_obj: [{pk: 3, username: "liooil", name: "西腾"}]}; const application = {pk: "app-id", slug: "xiteng-chat", name: "Xiteng Chat"}; const binding = {pk: "binding-id", target: "app-id", group: "group-id", enabled: true}; function response(payload, status = 200) { return new Response(payload === null ? null : JSON.stringify(payload), {status, headers: {"Content-Type": "application/json"}}); } test("summarizes only human users and liuhome application access", async () => { const directory = mkdtempSync(join(tmpdir(), "authentik-admin-test-")); const originalFetch = globalThis.fetch; globalThis.fetch = async (url) => { const path = new URL(url).pathname; if (path === "/-/health/ready/") return response({status: "ok"}); if (path === "/api/v3/core/users/") return response({results: [user, {...user, pk: 9, username: "ak-outpost", path: "goauthentik.io/outposts"}]}); if (path === "/api/v3/core/groups/") return response({results: [group]}); if (path === "/api/v3/core/applications/") return response({results: [application]}); if (path === "/api/v3/policies/bindings/") return response({results: [binding]}); if (path === "/api/v3/authenticators/admin/totp/") return response({results: [{pk: 1, name: "Phone", user: {pk: 3}}]}); if (path === "/api/v3/authenticators/admin/webauthn/") return response({results: [{pk: 2, name: "Laptop", user: {pk: 3}}]}); throw new Error(`Unexpected URL ${url}`); }; try { const admin = createAuthentikAdmin({baseUrl: "https://auth.example/", token: "token", auditPath: join(directory, "audit.jsonl")}); const summary = await admin.summary(); assert.deepEqual(summary.users.map((item) => item.username), ["liooil"]); assert.deepEqual(summary.groups.map((item) => item.name), ["liuhome"]); assert.deepEqual(summary.applications.find((item) => item.slug === "xiteng-chat").allowedGroups, ["liuhome"]); assert.equal(summary.users[0].totpCount, 1); assert.equal(summary.users[0].passkeyCount, 1); } finally { globalThis.fetch = originalFetch; rmSync(directory, {recursive: true, force: true}); } }); test("refuses to disable liooil", async () => { const originalFetch = globalThis.fetch; globalThis.fetch = async (url) => { if (new URL(url).pathname === "/api/v3/core/users/3/") return response(user); throw new Error(`Unexpected URL ${url}`); }; try { const admin = createAuthentikAdmin({baseUrl: "https://auth.example/", token: "token", auditPath: "/tmp/unused-authentik-audit"}); await assert.rejects(() => admin.mutate("/api/admin/identity/users/3/disable", {}, "liooil"), (error) => { assert.equal(error.statusCode, 409); return /不能停用/.test(error.message); }); } finally { globalThis.fetch = originalFetch; } }); test("does not write temporary passwords to the identity audit", async () => { const directory = mkdtempSync(join(tmpdir(), "authentik-audit-test-")); const auditPath = join(directory, "audit.jsonl"); const originalFetch = globalThis.fetch; globalThis.fetch = async (url, options = {}) => { const path = new URL(url).pathname; if (path === "/api/v3/core/users/3/") return response(user); if (path === "/api/v3/core/users/3/set_password/" && options.method === "POST") return response(null, 204); throw new Error(`Unexpected URL ${url}`); }; try { const admin = createAuthentikAdmin({baseUrl: "https://auth.example/", token: "token", auditPath}); await admin.mutate("/api/admin/identity/users/3/password", {password: "Temporary-secret-2026"}, "liooil"); const audit = readFileSync(auditPath, "utf8"); assert.doesNotMatch(audit, /Temporary-secret-2026/); assert.match(audit, /user\.password/); } finally { globalThis.fetch = originalFetch; rmSync(directory, {recursive: true, force: true}); } }); test("returns only the current user's authenticators and sessions", async () => { const originalFetch = globalThis.fetch; globalThis.fetch = async (url) => { const parsed = new URL(url); const path = parsed.pathname; if (path === "/api/v3/core/users/") return response({results: [user]}); if (path === "/api/v3/authenticators/admin/totp/") return response({results: [ {pk: 1, name: "Phone", user: {pk: 3}}, {pk: 9, name: "Other", user: {pk: 99}} ]}); if (path === "/api/v3/authenticators/admin/webauthn/") return response({results: [ {pk: 2, name: "Laptop", created_on: "2026-01-02T00:00:00Z", device_type: "single_device", aaguid: "aaguid", user: {pk: 3}} ]}); if (path === "/api/v3/core/authenticated_sessions/") return response({results: [ {uuid: "session-id", user: 3, current: true, last_ip: "127.0.0.1", last_user_agent: "Browser", last_used: "2026-01-03T00:00:00Z", expires: "2026-01-04T00:00:00Z"}, {uuid: "other-session", user: 99} ]}); throw new Error(`Unexpected URL ${url}`); }; try { const admin = createAuthentikAdmin({baseUrl: "https://auth.example/", token: "token", auditPath: "/tmp/unused-authentik-audit"}); const account = await admin.accountSummary("liooil"); assert.equal(account.profile.username, "liooil"); assert.deepEqual(account.security.totp.map((device) => device.name), ["Phone"]); assert.deepEqual(account.security.passkeys.map((device) => device.name), ["Laptop"]); assert.deepEqual(account.security.sessions.map((session) => session.id), ["session-id"]); assert.match(account.security.totpSetupUrl, /default-authenticator-totp-setup/); assert.match(account.security.passkeySetupUrl, /default-authenticator-webauthn-setup/); } finally { globalThis.fetch = originalFetch; } }); test("refuses to mutate another user's authenticator", async () => { const originalFetch = globalThis.fetch; globalThis.fetch = async (url) => { const path = new URL(url).pathname; if (path === "/api/v3/core/users/") return response({results: [user]}); if (path === "/api/v3/authenticators/admin/webauthn/9/") return response({pk: 9, name: "Other", user: {pk: 99}}); throw new Error(`Unexpected URL ${url}`); }; try { const admin = createAuthentikAdmin({baseUrl: "https://auth.example/", token: "token", auditPath: "/tmp/unused-authentik-audit"}); await assert.rejects(() => admin.accountMutate("/api/account/security/passkeys/9/delete", {}, "liooil"), (error) => error.statusCode === 404); } finally { globalThis.fetch = originalFetch; } });