inbuxa-server renames the identifiers that carried the upstream name (its SPEC.md §2.4). Upstream's capability for the registry (x:) objects is now urn:inbuxa:jmap:registry, beside the fork's own urn:inbuxa:jmap, which is unchanged. There's no alias, so this lands with the server change and deploys with it. The mock advertises the new name too. No user-visible strings change.
73 lines
3.2 KiB
TypeScript
73 lines
3.2 KiB
TypeScript
import { test, before, after } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
/**
|
|
* ihasmail requires Stalwart 0.16 or newer. Sign-in is where that is enforced,
|
|
* and it matters that it is enforced *there*: the alternative is signing
|
|
* someone in and letting Files, the account locale and self-service
|
|
* credentials each fail in their own way, with nothing to connect the three or
|
|
* to say what the real problem is.
|
|
*
|
|
* The refusal also has to keep two things apart that look the same from the
|
|
* outside. Bad credentials are a 401 the user can fix by typing again; an
|
|
* unsupported server is not, and telling someone their password is wrong when
|
|
* it is not would send them round in circles.
|
|
*/
|
|
|
|
const PORT = 18799;
|
|
process.env.MOCK_PORT = String(PORT);
|
|
process.env.MOCK_USER = "[email protected]";
|
|
process.env.MOCK_PASS = "demo-password";
|
|
process.env.MOCK_NO_REGISTRY = "1"; // a server without urn:inbuxa:jmap:registry
|
|
process.env.MAIL_SERVER_URL = `http://127.0.0.1:${PORT}`;
|
|
process.env.APP_SECRET = "test-secret-for-login-guard";
|
|
|
|
const mock = await import("./mock/index.js");
|
|
const { createApp } = await import("./app.js");
|
|
|
|
const app = createApp();
|
|
const HEADERS = { "content-type": "application/json", "x-requested-with": "ihasmail" };
|
|
|
|
async function login(body: unknown): Promise<{ status: number; body: any; setCookie: string | null }> {
|
|
const res = await app.request("/api/auth/login", { method: "POST", headers: HEADERS, body: JSON.stringify(body) });
|
|
const text = await res.text();
|
|
return { status: res.status, body: text ? JSON.parse(text) : null, setCookie: res.headers.get("set-cookie") };
|
|
}
|
|
|
|
before(() => {
|
|
assert.equal(process.env.MOCK_NO_REGISTRY, "1");
|
|
});
|
|
|
|
after(() => {
|
|
(mock as { server?: { close(): void } }).server?.close();
|
|
});
|
|
|
|
test("a server without the registry is refused, with good credentials", async () => {
|
|
const res = await login({ username: "[email protected]", password: "demo-password" });
|
|
assert.equal(res.status, 501);
|
|
assert.equal(res.body.error, "unsupported_server");
|
|
});
|
|
|
|
test("the message says the credentials were fine, and that the server isn't supported", async () => {
|
|
const { body } = await login({ username: "[email protected]", password: "demo-password" });
|
|
// Someone hitting this has typed a correct password. Saying so is the
|
|
// difference between "wrong server" and "try your password again".
|
|
assert.match(body.message, /credentials are fine/i);
|
|
assert.match(body.message, /isn't one this webmail supports/);
|
|
});
|
|
|
|
test("no session is minted for a server we cannot talk to", async () => {
|
|
// A cookie here would leave a signed-in session against a server every
|
|
// other request is going to fail on.
|
|
const res = await login({ username: "[email protected]", password: "demo-password" });
|
|
assert.equal(res.setCookie, null);
|
|
});
|
|
|
|
test("bad credentials on such a server are still a 401, not the server error", async () => {
|
|
// The upstream session request fails first, and that answer is the honest
|
|
// one: we never got far enough to learn what the server supports.
|
|
const res = await login({ username: "[email protected]", password: "wrong-password" });
|
|
assert.equal(res.status, 401);
|
|
assert.notEqual(res.body.error, "unsupported_server");
|
|
});
|