Commit Graph
3 Commits
Author SHA1 Message Date
jcoffey-dev f7712b1c1e Group the admin and calendar modules, and stop calling screenshots docs
web/src/lib had grown to 85 flat modules -- 42% of the web source, about
12,800 lines -- with one subdirectory (smime/) to its name. The tell was
that a naming prefix had taken over a directory's job: eight adminX.ts
files sat adjacent because alphabetical order put them there, not because
anything said they belonged together.

  lib/admin/     adminAccess, adminDashboard, adminDirectory, adminDomains,
                 adminGroups, adminLists, adminRoles, adminTenants
  lib/calendar/  appointment, availabilityWindow, eventDrag, ics, recurrence

Tests move with their modules into lib/admin/__tests__ and
lib/calendar/__tests__, which is what views/ already does. describeRules
stays in lib/__tests__: it checks that sieve's describeRule and
recurrence's agree, so it belongs to neither.

recurrence.ts joins the calendar group and archiveDate.ts does not, which
is the opposite of the first guess from the filenames. archiveDate picks
the Archive/2026/09 mailbox for a message -- mail, not calendar --
while recurrence reads JSCalendarRecurrenceRule. schedule.ts is scheduled
*send*, so it stays put too. birthdays.ts is left alone deliberately: it
is read off the contact cards and only rendered by the calendar, so it
belongs to whichever of the two you ask.

docs/ held no documentation. It held ten JPEGs and the two scripts that
capture them, while the actual documentation is a separate site in the
ihasmail.org repository -- so anyone opening docs/ expecting prose found
a headless-Chrome driver. The images are now screenshots/, and the two
capture scripts join the other .mjs tooling in scripts/, which is where a
generator belongs. Renaming docs/ to screenshots/ wholesale would have
produced screenshots/screenshots/inbox-dark.jpg.

No behavior changes: every import was already on the @/ alias, so this is
path rewrites and nothing else.
2026-09-15 22:44:53 -07:00
jcoffey-dev d279fe8f90 Let an operator turn administration off
ADMINISTRATION=0 at launch removes in-app administration for everyone. The
account's permissions are no longer sent to the browser, so the menu never
appears, and the JMAP proxy refuses Stalwart registry methods other than the
account's own (settings, password, app passwords, API keys, public keys,
masked addresses). Hiding the menu alone would have left an administrator's
browser console able to make every call the menu made.

With administration on, the request body streams through untouched as before;
only an installation that turns it off reads and checks the body, forwarding
the parsed form so the server receives exactly what was inspected.
2026-09-13 15:27:05 -07:00
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