8
Accounts
MelekTaus edited this page 2026-10-16 06:58:43 +02:00

Since #177 the editor is behind a sign-in screen: every project belongs to an account, and nothing is loaded before somebody is signed in.

Signing in

The sign-in screen is drawn in the same canvas as the editor — no second canvas, no HTML form. It asks for a user name and a password; Enter moves from the first field to the second and sends the form from there. The password is drawn as bullets and never appears as itself.

A refused attempt says what went wrong under the form: Enter your password before anything is sent, Wrong user name or password when the server refuses the pair.

The Account menu sits at the far right of the toolbar and holds everything about the account: who is signed in (as an entry that cannot be picked), Change password and Logout. Logout ends the session and brings the sign-in screen back. The name stands in the window title as well (Feuerwerk — user) rather than as a second label in the bar, which since #183 carries icons and no words at all.

Signing in and out never reloads the page and never builds a second canvas: the picture changes, nothing else. What is unsaved is written before the session ends, the editor then lets go of everything it held — its tabs, the project, the running plugins, the console lines — and the sign-in screen is drawn in its place. Signing in builds a fresh editor in the same canvas, so a second account starts from nothing the first one left behind.

Trying it without an account

Below the form, Try without an account lists the demo projects (#428); picking one opens the editor as a guest. The window title names Guest as the account, the place of the save status in the toolbar says that nothing is saved, and a notice says the same in a sentence.

A guest works on a copy held in the tab. Everything can be changed, played and recorded, and nothing reaches the server: the editor sends no request that writes, and the server would refuse one anyway, since there is no session. A reload, or Sign in… in the Account menu, throws the changes away; picking the demo again starts from the copy as it was. What a guest does not get:

  • New project, Open project…, Snapshots… and Release… in the main menu,
  • Upload and Delete in the pickers, which list the demo material alone, and a file dropped or pasted on the editor,
  • Change password and Logout: the Account menu holds Sign in… instead.

A recording a guest makes is saved as a download (an .mkv file), like one a released game makes.

What guests get is the administrators' call. In a project's main menu an administrator finds Demo copy…: it makes a frozen copy of the project as saved, like a release, and the dialog says how old the copy is and whether the project has changed since. Update demo copy replaces it, Remove takes it away. The copy is listed under the project's name. An empty project is just a demo that is empty.

In the image, font, sound and video pickers an administrator has Offer as demo (and Stop offering) for the picked file. Offered files show up in the pickers of every account and every guest, marked demo material under the list, and only an administrator deletes one while it is offered. See API for the routes.

Changing the password

Account → Change password opens a dialog asking for the current password, the new one and its repeat, all three drawn as bullets. The current password is asked for even though the session is already there: a tab somebody left open must not be enough to take an account over.

A new password needs at least 8 characters, may not be the current one, and has to match its repeat. The editor says so before sending anything; the server checks the length again, since a client is free to send whatever it likes.

Every other login of the account ends with the change — a session started with the old password has no business outliving it. The tab that made the change keeps its own.

The session outlasts a deployment

A login is kept on the server (data/sessions/, one file per session, named after the hash of the token in the cookie) and lasts 30 days of not being used; every request pushes that out again. So npm run build — which is the deployment — replaces the editor under an open tab without asking for the password again, and so does closing the browser overnight.

PHP's own session handler would not do that: it throws sessions away after session.gc_maxlifetime, 24 minutes by default.

Roles

Every account has one of two roles (#180): admin or user. An account without a role in data/users.json is a user — the weaker reading is the one a missing field gets, so a file written by hand never hands out rights by accident. The same goes for a role the server does not know.

What an administrator may do on top is decided on the server: every such route asks Auth::requireAdmin() and answers anybody else 403. The editor only leaves out what it may not offer; it shows the role nowhere else, there is no badge and no word in the title.

An administrator

  • manages the accounts in the User management tab (below), and
  • opens and edits every project as if it were their own (#179). A save keeps the project's owner: an administrator who fixes somebody's project does not take it over. Their own project list (Open project…) still shows only their own; the others are reached through the user management.
  • does not delete somebody else's project (#272). Only the owner deletes a project; the server answers an administrator 403, so nothing goes missing without its owner knowing.

User management

Menu → User management (administrators only) opens a tab with every account and, below it, the plugins. Menu → Plugins opens the same tab — for a user it holds the plugins alone and is called Plugins. It closes like a document and is not part of the fixed tabs.

Each account is one row: name, role, creation date (empty for the accounts from before #179) and how many projects it owns, the projects listed under it with Open. On the right:

Button What it does
Rename… A new name. The account's projects move with it — the name is their owner — and the account is signed out everywhere, since its sessions carry the old name
Role user or admin, picked from a menu
Password… Sets a new password without the old one. The account's sessions end; on the administrator's own row their own session stays
Delete Asks first, then removes the account and signs it out. Refused while it owns projects — they would belong to nobody and vanish from every list. The account deletes them first; an administrator cannot (#272)
New user… In the tab's header: name, password (twice) and role

On their own row an administrator may only set a password: renaming themselves would end the session they are working in, and demoting or deleting themselves would lock them out of the page they are on. The server refuses the same, and it refuses to demote or delete the last administrator.

A refused change comes back in the server's words: in the open form (The name e2e is taken), or on the status line for Role and Delete (anna still owns 2 projects).

The accounts

Account Role What it holds
admin admin no projects
e2e user the four projects the check tools write: fixture, Jump and Run, Tetris, Actor demo
e2e-admin admin nothing; the account the user management step signs in as
user user every other project

A project file carries its owner (owner in data/projects/{id}.json). A file without one belongs to nobody and shows up in no list, not even the user management's — the safe way round, and the one that shows up straight away when a new project file is put there by hand without an owner. Only an administrator who knows its id can still open it (?project=<id>).

Making an account on the server

php tools/make-user.php <username> <password> [admin|user]   # creates it, or sets the password
php tools/make-user.php --list                                # name and role per line

This is how the first administrator comes about; after that, accounts are managed in the editor. Without a role a new account is a user, and an existing one keeps the role it has — resetting a password on the command line never demotes an administrator. The CLI does not check the password's length.

Passwords are stored as hashes (password_hash) in data/users.json, which is git-ignored, as is data/sessions/. Registration (#178) and shared projects (#181) are follow-ups of their own.

What the check tools do

Every seed, smoke and e2e run signs in as e2e first and sends the same session cookie a browser would (tools/lib/auth.mjs). The password comes from FEUERWERK_E2E_PASSWORD or from data/e2e-password.txt, which is git-ignored — CI writes its own on a fresh checkout and makes the account with it (tools/ci/serve.sh). e2e-admin works the same way, with FEUERWERK_E2E_ADMIN_PASSWORD or data/e2e-admin-password.txt.

The browser in an e2e run is handed that session as a cookie, so it starts on the editor. The sign-in screen itself is driven by hand in step 45, the one step that sees it. Step 49 signs the browser in as e2e-admin, manages a throwaway account e2e-tmp through the tab and hands the browser back to e2e at the end; the account and its project are gone again even when a check on the way throws.

The API's own rules — roles, who reaches which project, what may not be done to an account — are tested without a server in tests/php/accounts.test.php, a plain PHP file CI runs in the gate job (php tests/php/accounts.test.php). The machine the editor is built on has no PHP; there it runs in the web server's container.