chore: format auth code and update runtime
This commit is contained in:
+57
-18
@@ -20,11 +20,16 @@ async function setup() {
|
||||
});
|
||||
const pg = mem.adapters.createPg();
|
||||
const db = new pg.Pool();
|
||||
await db.query(`CREATE TABLE users(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),email text UNIQUE NOT NULL,password_hash text NOT NULL,role text NOT NULL DEFAULT 'user',created_at timestamptz DEFAULT now()); CREATE TABLE sessions(token_hash text PRIMARY KEY,user_id uuid NOT NULL REFERENCES users(id),csrf_hash text NOT NULL,expires_at timestamptz NOT NULL,created_at timestamptz DEFAULT now()); CREATE TABLE roast_plans(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id),plan jsonb NOT NULL,created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now()); CREATE TABLE app_settings(key text PRIMARY KEY,value text NOT NULL); INSERT INTO app_settings VALUES('signup_enabled','true')`);
|
||||
await db.query(
|
||||
`CREATE TABLE users(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),email text UNIQUE NOT NULL,password_hash text NOT NULL,role text NOT NULL DEFAULT 'user',created_at timestamptz DEFAULT now()); CREATE TABLE sessions(token_hash text PRIMARY KEY,user_id uuid NOT NULL REFERENCES users(id),csrf_hash text NOT NULL,expires_at timestamptz NOT NULL,created_at timestamptz DEFAULT now()); CREATE TABLE roast_plans(id uuid PRIMARY KEY DEFAULT gen_random_uuid(),user_id uuid NOT NULL REFERENCES users(id),plan jsonb NOT NULL,created_at timestamptz DEFAULT now(),updated_at timestamptz DEFAULT now()); CREATE TABLE app_settings(key text PRIMARY KEY,value text NOT NULL); INSERT INTO app_settings VALUES('signup_enabled','true')`,
|
||||
);
|
||||
const app = createApp({
|
||||
db,
|
||||
root,
|
||||
env: { NODE_ENV: "test", BOOTSTRAP_SETUP_TOKEN: "a-secure-bootstrap-token" },
|
||||
env: {
|
||||
NODE_ENV: "test",
|
||||
BOOTSTRAP_SETUP_TOKEN: "a-secure-bootstrap-token",
|
||||
},
|
||||
});
|
||||
return { db, app, agent: request.agent(app) };
|
||||
}
|
||||
@@ -43,23 +48,38 @@ test("strict CSP/static modules, no-store data, auth lifecycle, and ownership sh
|
||||
|
||||
const landing = await anonymous.get("/");
|
||||
assert.equal(landing.status, 200);
|
||||
assert.match(landing.headers["content-security-policy"], /default-src 'self'/);
|
||||
assert.match(
|
||||
landing.headers["content-security-policy"],
|
||||
/default-src 'self'/,
|
||||
);
|
||||
assert.doesNotMatch(
|
||||
landing.headers["content-security-policy"],
|
||||
/(?:default-src|script-src)[^;]*unsafe-inline/,
|
||||
);
|
||||
assert.match(landing.text, /<script type="module" src="\/js\/landing\.js"><\/script>/);
|
||||
assert.match(
|
||||
landing.text,
|
||||
/<script type="module" src="\/js\/landing\.js"><\/script>/,
|
||||
);
|
||||
assert.doesNotMatch(landing.text, /<script type="module">/);
|
||||
const adminHtml = await anonymous.get("/admin");
|
||||
assert.equal(adminHtml.status, 401);
|
||||
assert.equal(adminHtml.headers["cache-control"], "no-store, private");
|
||||
assert.equal((await anonymous.get("/api/plans")).status, 401);
|
||||
assert.equal((await anonymous.get("/api/plans")).headers["cache-control"], "no-store, private");
|
||||
assert.match((await anonymous.get("/js/admin.js")).text, /async function load/);
|
||||
assert.equal(
|
||||
(await anonymous.get("/api/plans")).headers["cache-control"],
|
||||
"no-store, private",
|
||||
);
|
||||
assert.match(
|
||||
(await anonymous.get("/js/admin.js")).text,
|
||||
/async function load/,
|
||||
);
|
||||
const mainScript = await anonymous.get("/js/main.js");
|
||||
assert.match(mainScript.text, /roastPlannerPlan\.v2/);
|
||||
assert.match(mainScript.text, /localStorage\.removeItem\(key\)/);
|
||||
assert.match((await anonymous.get("/sw.js")).text, /Never serve authenticated/);
|
||||
assert.match(
|
||||
(await anonymous.get("/sw.js")).text,
|
||||
/Never serve authenticated/,
|
||||
);
|
||||
|
||||
const one = await signup(first, "[email protected]");
|
||||
const two = await signup(second, "[email protected]");
|
||||
@@ -68,9 +88,12 @@ test("strict CSP/static modules, no-store data, auth lifecycle, and ownership sh
|
||||
const plan = await first
|
||||
.post("/api/plans")
|
||||
.set("x-csrf-token", one.csrf)
|
||||
.send({ plan: { fields: { "0.1": "Private" } } });
|
||||
.send({ plan: { fields: { 0.1: "Private" } } });
|
||||
assert.equal(plan.status, 201);
|
||||
assert.equal((await first.get("/api/plans")).headers["cache-control"], "no-store, private");
|
||||
assert.equal(
|
||||
(await first.get("/api/plans")).headers["cache-control"],
|
||||
"no-store, private",
|
||||
);
|
||||
assert.equal(
|
||||
(
|
||||
await second
|
||||
@@ -84,13 +107,22 @@ test("strict CSP/static modules, no-store data, auth lifecycle, and ownership sh
|
||||
|
||||
const login = request.agent(app);
|
||||
assert.equal(
|
||||
(await login.post("/api/auth/login").send({ email: "[email protected]", password })).status,
|
||||
(
|
||||
await login
|
||||
.post("/api/auth/login")
|
||||
.send({ email: "[email protected]", password })
|
||||
).status,
|
||||
200,
|
||||
);
|
||||
assert.equal((await login.get("/api/auth/me")).status, 200);
|
||||
const loginCsrf = (await login.post("/api/auth/login").send({ email: "[email protected]", password })).body.csrfToken;
|
||||
const loginCsrf = (
|
||||
await login
|
||||
.post("/api/auth/login")
|
||||
.send({ email: "[email protected]", password })
|
||||
).body.csrfToken;
|
||||
assert.equal(
|
||||
(await login.post("/api/auth/logout").set("x-csrf-token", loginCsrf)).status,
|
||||
(await login.post("/api/auth/logout").set("x-csrf-token", loginCsrf))
|
||||
.status,
|
||||
200,
|
||||
);
|
||||
assert.equal((await login.get("/api/auth/me")).status, 401);
|
||||
@@ -113,10 +145,17 @@ test("strict CSP/static modules, no-store data, auth lifecycle, and ownership sh
|
||||
200,
|
||||
);
|
||||
assert.equal(
|
||||
(await anonymous.post("/api/auth/signup").send({ email: "[email protected]", password })).status,
|
||||
(
|
||||
await anonymous
|
||||
.post("/api/auth/signup")
|
||||
.send({ email: "[email protected]", password })
|
||||
).status,
|
||||
403,
|
||||
);
|
||||
assert.equal((await db.query("SELECT count(*)::int AS count FROM users")).rows[0].count, 3);
|
||||
assert.equal(
|
||||
(await db.query("SELECT count(*)::int AS count FROM users")).rows[0].count,
|
||||
3,
|
||||
);
|
||||
});
|
||||
|
||||
test("bootstrap token is optional after first setup and unavailable before setup without one", async () => {
|
||||
@@ -142,10 +181,10 @@ test("bootstrap token is optional after first setup and unavailable before setup
|
||||
).status,
|
||||
503,
|
||||
);
|
||||
await db.query("INSERT INTO users(email,password_hash,role) VALUES($1,$2,'admin')", [
|
||||
"[email protected]",
|
||||
"not-used-in-this-test",
|
||||
]);
|
||||
await db.query(
|
||||
"INSERT INTO users(email,password_hash,role) VALUES($1,$2,'admin')",
|
||||
["[email protected]", "not-used-in-this-test"],
|
||||
);
|
||||
assert.equal(
|
||||
(
|
||||
await request(noTokenApp).post("/api/auth/bootstrap").send({
|
||||
|
||||
Reference in New Issue
Block a user