Files
ihasmail-inbuxa/server/src/permissions.test.ts
T
jcoffey-dev 82e217155b Add Administration, starting with accounts
An account whose Stalwart role manages accounts now finds Administration in
the account menu. It lists, searches, creates and edits accounts -- display
name, other addresses, role, storage limit -- sets a new password, and
deletes, each offered only when the role holds the matching permission.

The server keeps the permissions list from GET /api/account, which it
already called for the edition and threw the rest away. Everything else is
JMAP x:Account, x:Domain and x:Role calls through the existing /api/jmap
proxy, so nothing new is stored and Stalwart decides every call.

Stalwart checks a grant against the caller's permissions but not a password
change or a delete, so an account that outranks the viewer is shown
read-only. Your own password is changed in Settings, which re-seals the
session; changing it here would strand it.

The mock server gains a directory behind the same permission names, with
MOCK_ROLE choosing admin, tenant-admin, helpdesk or user.

68 new strings, translated in all nine catalogues; strings falling back to
English stay at 16.
2026-09-13 15:11:55 -07:00

28 lines
1.6 KiB
TypeScript

import { test } from "node:test";
import assert from "node:assert/strict";
import { interpretServerAccount, normalizePermission } from "./upstream.js";
/**
* `/api/account` is the only place Stalwart lists what an account may do, and
* ihasmail used to read the edition out of it and throw the rest away.
*/
test("the account's permissions are kept alongside the edition", () => {
const info = interpretServerAccount({ edition: "enterprise", permissions: ["sysAccountGet", "sysAccountQuery"], locale: "en_US" });
assert.deepEqual(info, { edition: "enterprise", permissions: ["sysAccountGet", "sysAccountQuery"] });
});
test("permission names read the same whichever case the server uses", () => {
// The source serialises camelCase; the documentation shows kebab-case.
assert.equal(normalizePermission("sys-account-get"), "sysAccountGet");
assert.equal(normalizePermission("sysAccountGet"), "sysAccountGet");
assert.equal(normalizePermission("sys-dkim-signature-create"), "sysDkimSignatureCreate");
assert.deepEqual(interpretServerAccount({ permissions: ["sys-account-get", "sysAccountGet"] }).permissions, ["sysAccountGet"]);
});
test("a body without a usable list yields no permissions rather than failing", () => {
assert.deepEqual(interpretServerAccount({ edition: "oss" }), { edition: "oss", permissions: [] });
assert.deepEqual(interpretServerAccount({ permissions: "sysAccountGet" }), { edition: null, permissions: [] });
assert.deepEqual(interpretServerAccount({ permissions: [1, null, "sysDomainGet"] }).permissions, ["sysDomainGet"]);
assert.deepEqual(interpretServerAccount(null), { edition: null, permissions: [] });
});