Ctrl K
ComunidadGuías…

test/local-auth-mode.test.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtemp, mkdir, rm } from "node:fs/promises";
import { tmpdir } from "node:os";
import path from "node:path";

/**
 * The private Docker install has one setup door, not public self-registration.
 * Drive the real HTTP routes because the contract spans auth storage, session
 * creation, mode detection and the anonymous configuration the React surface
 * consumes. A pure helper test could pass while one of those seams stayed open.
 */
const scratch = await mkdtemp(path.join(tmpdir(), "forge-local-owner-"));
process.env.FORGE_CONFIG_DIR = path.join(scratch, "config");
process.env.FORGE_DECKS_DIR = path.join(scratch, "decks");
process.env.FORGE_REFERENCE_DIR = path.join(scratch, "reference");
process.env.FORGE_DB_PATH = path.join(scratch, "config", "forge.db");
process.env.FORGE_API_PORT = "0";
process.env.FORGE_HOSTED = "0";
delete process.env.FORGE_LOCAL_MULTI_USER;
delete process.env.FORGE_ADMIN_EMAIL;
for (const key of ["FORGE_SMTP_HOST", "FORGE_SMTP_USER", "FORGE_SMTP_PASS", "FORGE_SMTP_FROM"]) {
  delete process.env[key];
}
await mkdir(process.env.FORGE_CONFIG_DIR, { recursive: true });
await mkdir(process.env.FORGE_DECKS_DIR, { recursive: true });

const { server } = await import("../app/server/index.js");
if (!server.listening) await new Promise((resolve) => server.once("listening", resolve));
const base = `http://127.0.0.1:${server.address().port}`;

test.after(async () => {
  await new Promise((resolve) => server.close(resolve));
  const { closeDb } = await import("../src/db.js");
  closeDb();
  await rm(scratch, { recursive: true, force: true });
});

const json = async (route, options) => {
  const response = await fetch(`${base}${route}`, options);
  return { response, body: await response.json() };
};

test("a fresh local install offers one owner setup and no mail/OAuth surfaces", async () => {
  const { response, body } = await json("/api/auth/registration");
  assert.equal(response.status, 200);
  assert.deepEqual(
    {
      open: body.open,
      mail: body.mail,
      verifyRequired: body.verifyRequired,
      localOwner: body.localOwner,
      ownerConfigured: body.ownerConfigured,
    },
    { open: true, mail: false, verifyRequired: false, localOwner: true, ownerConfigured: false },
  );
  assert.equal((await json("/api/auth/google/config")).body.clientId, null);
});

test("first setup creates an immediately usable owner session and closes registration", async () => {
  const created = await json("/api/auth/register", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name: "Local Owner", email: "owner@forge.local", password: "local-password" }),
  });
  assert.equal(created.response.status, 200);
  assert.equal(created.body.localOwner, true);
  assert.equal(created.body.user.role, "admin");
  assert.equal(created.body.user.verified, true);
  assert.ok(created.body.token?.length >= 32, "setup starts the owner session directly");
  assert.match(created.response.headers.get("set-cookie") ?? "", /forge_session=/);

  const state = (await json("/api/auth/registration")).body;
  assert.equal(state.ownerConfigured, true);
  assert.equal(state.open, false);

  const second = await json("/api/auth/register", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ name: "Second", email: "second@forge.local", password: "second-password" }),
  });
  assert.equal(second.response.status, 403);
  assert.match(second.body.error, /already has an owner/);
});

test("the owner can log back in, while local email and Google entry points stay closed", async () => {
  const login = await json("/api/auth/login", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email: "owner@forge.local", password: "local-password" }),
  });
  assert.equal(login.response.status, 200);
  assert.equal(login.body.user.email, "owner@forge.local");

  for (const [route, body] of [
    ["/api/auth/google", { credential: "not-used" }],
    ["/api/auth/forgot", { email: "owner@forge.local" }],
    ["/api/auth/verify", { token: "not-used" }],
  ]) {
    const out = await json(route, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
    });
    assert.ok([403, 404].includes(out.response.status), `${route} must not be a local-owner surface`);
  }
});

test("hosted mode keeps ordinary multi-user registration unchanged", async () => {
  process.env.FORGE_HOSTED = "1";
  try {
    const state = (await json("/api/auth/registration")).body;
    assert.equal(state.localOwner, false);
    assert.equal(state.open, true);

    const created = await json("/api/auth/register", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name: "Hosted Member", email: "member@example.test", password: "hosted-password" }),
    });
    assert.equal(created.response.status, 200);
    assert.equal(created.body.token, undefined, "hosted self-registration still requires an explicit login");
    assert.equal(created.body.user.role, undefined, "hosted self-registration cannot mint an administrator");
  } finally {
    process.env.FORGE_HOSTED = "0";
  }
});