Find Stalwart's administration instead of asking for it
The dashboard's link to Stalwart's own administration needed
STALWART_ADMIN_URL, which an operator had to know to set. Everything it
holds can be read from the server:
- the origin is the host Stalwart advertises in its own session URLs, the
one people reach it at even when ihasmail talks to it on a private
address;
- the prefix is where its web interface application is installed. The
production server's x:Application reads "Stalwart Web Interface",
enabled, urlPrefix {"/admin", "/account"}, and /admin is also what
Stalwart writes at first boot.
So, for an account that administers, the account info fetch now asks the
account's own server for its applications and links to origin + /admin/.
An installation whose web interface is disabled or moved gets no link; an
administrator who may not read applications gets Stalwart's default
/admin. It is cached with the rest of the account info.
STALWART_ADMIN_URL and a servers file entry's adminUrl still win, for an
administration that lives somewhere else. A routed domain without one now
takes what its own server said, never the default server's.
This commit is contained in:
@@ -18,7 +18,7 @@ process.env.STALWART_URL = "https://default.example";
|
||||
process.env.STALWART_ADMIN_URL = "https://admin.default.example/";
|
||||
process.env.STALWART_SERVERS_FILE = file;
|
||||
|
||||
const { adminUrlFor, upstreamFor } = await import("./upstream.js");
|
||||
const { adminPrefixFrom, adminUrlFor, advertisedOrigin, upstreamFor } = await import("./upstream.js");
|
||||
const { config, parseStalwartServers } = await import("./config.js");
|
||||
|
||||
/**
|
||||
@@ -39,10 +39,33 @@ test("an unmapped domain and a bare username open the default administration", (
|
||||
|
||||
test("a routed domain opens its own server's administration, and never the default's", () => {
|
||||
assert.equal(adminUrlFor("[email protected]"), "https://admin.linked.test");
|
||||
// Routed away, with no adminUrl of its own: no link rather than the wrong server.
|
||||
// Routed away, with no adminUrl of its own and nothing found: no link rather than the wrong server.
|
||||
assert.equal(adminUrlFor("[email protected]"), null);
|
||||
});
|
||||
|
||||
test("what the operator configured wins over what was found, and what was found fills the gap", () => {
|
||||
assert.equal(adminUrlFor("[email protected]", "https://found.example/admin/"), "https://admin.default.example");
|
||||
assert.equal(adminUrlFor("[email protected]", "https://found.example/admin/"), "https://admin.linked.test");
|
||||
// The routed domain without an adminUrl takes what its own server said.
|
||||
assert.equal(adminUrlFor("[email protected]", "https://mail.plain.test/admin/"), "https://mail.plain.test/admin/");
|
||||
});
|
||||
|
||||
/** Finding the administration on the server itself, as production's answered on 2026-09-15. */
|
||||
test("the web interface's prefix is read from the applications Stalwart has installed", () => {
|
||||
const got = (list: unknown[]) => adminPrefixFrom([["x:Application/query", { ids: ["a"] }, "q"], ["x:Application/get", { list }, "g"]]);
|
||||
assert.equal(got([{ enabled: true, description: "Stalwart Web Interface", urlPrefix: { "/admin": true, "/account": true } }]), "/admin");
|
||||
assert.equal(got([{ enabled: false, urlPrefix: { "/admin": true } }]), null);
|
||||
assert.equal(got([{ enabled: true, urlPrefix: { "/console": true } }]), null);
|
||||
assert.equal(got([]), null);
|
||||
// May not read applications: not an answer, so Stalwart's own default.
|
||||
assert.equal(adminPrefixFrom([["error", { type: "forbidden" }, "q"], ["error", { type: "forbidden" }, "g"]]), "/admin");
|
||||
});
|
||||
|
||||
test("the origin is the one Stalwart advertises, even when it is reached on a private address", () => {
|
||||
assert.equal(advertisedOrigin({ apiUrl: "https://mail.example.com/jmap/", baseUrl: "http://127.0.0.1:8080" }), "https://mail.example.com");
|
||||
assert.equal(advertisedOrigin({ apiUrl: "/jmap/", baseUrl: "https://mail.example.com" }), "https://mail.example.com");
|
||||
});
|
||||
|
||||
test("the shipped example loads through the parser that reads it", () => {
|
||||
const example = new URL("../../stalwart-servers.example.json", import.meta.url);
|
||||
const parsed = parseStalwartServers(JSON.parse(readFileSync(example, "utf8")), "example");
|
||||
|
||||
Reference in New Issue
Block a user