Profile server CLI
FAQ › Profile server › CLI · Nederlands
What is it?
The profile server is one program, euzos-profielserver (crate euzos-profileserver, source server/profile/src/main.rs). The same binary both runs the server (start) and manages it from the command line: accounts, admins, phones, PC sessions, the vault, reports, the app catalogue, download keys and tokens, offline policy, organisations, workplace servers and registered PCs. Every command works directly on the SQLite database named in the configuration file; the server itself does not have to be stopped.
The binary keeps its Dutch name euzos-profielserver (the path on the VPS and the systemd unit use it). The commands and flags are English; the old Dutch command names and flags still work as hidden aliases for one release.
Next to it there is a second, much smaller program for the download server, euzos-download (server/download), with its own three commands (see below).
How do I…?
…run a CLI command on the server?
euzos-profielserver [--config <file>] <command> [arguments]
The configuration file comes from --config <file>, otherwise from the environment variable EUZOS_PROFILE_CONFIG (the old name EUZOS_PROFIEL_CONFIG is still read). On the VPS the systemd unit starts the server as /opt/euzos-profiel/huidig/euzos-profielserver --config /etc/euzos-profiel/profiel.conf start; CLI commands are run the same way, as the service user (sudo -u euzos-profiel …), so they use the same database and keys (docs/PROFILESERVER-SETUP.md). --help or -h (or no command) prints the usage text.
…create an account?
user-create <email> [--first-name F] [--last-name L] [--city C] [--display-name "Name"] [--language nl|en] [--password-stdin]. You are asked for the password twice (or one line on stdin with --password-stdin); at least 10 characters. The account gets the two profiles Werk of school and Privé, status niet_geverifieerd, and a mail with link and code (valid 24 hours). Logging in only works once the address is confirmed. In an emergency (no mail) user-verify <email> confirms by hand; that is recorded in the admin log.
…block, unblock or delete an account?
user-block <email>: no more logins; logs out all PCs and revokes all phones.user-unblock <email>: status back toactief; phones must be paired again.user-delete <email> [--yes <email>]: GDPR erasure of everything (PCs, phones, vault including the storage key, reports, profiles, settings, verifications, mail counters). It asks you to type the address again, or takes it from--yes. The admin log keeps only a hash of the address.
…reset a password?
password <email> [--password-stdin] [--revoke-devices]: a new password; all PCs are logged out, and with --revoke-devices all phones are revoked too.
…make someone an admin of the admin page?
admin-create <email> (the account must be actief). The admin then logs in on https://<admin domain>/beheer with e-mail address and password and confirms in the EUZOS app on a paired phone. admin-delete <email> removes the role, admins lists the admins and how many phones they have paired. See Admin page.
…limit what admin commands a user may run on a PC?
admin-policy <email> [<policy> | geen | --delete]. The policy is a comma-separated part of console,sshd,log,profiel, or geen (none). It is put, signed, into that user's profile (beheer= line). Without a policy argument the command shows the current one; --delete removes it (the PC then follows its build: a test build allows everything, production nothing). Changing it logs out the account's PCs.
…publish an app (Chromium) in the catalogue?
app-set <name> --version <n> --size <bytes> --sha256 <hex> --url <https://…/NAME.APP> [--url <mirror>]… [--package <https://…>]…. The version comes from the .sig, size and SHA-256 from the package (tools/chromium/install.sh --create shows them). --url is the signed description (.sig next to it), --package the package itself (without it: next to the description); the first URL is tried first, the rest are mirrors. apps shows the catalogue, app-delete <name> removes an app. See Apps and downloads.
…set up download tokens?
Once per environment: download-key-create creates the download key in the file named by download_key_file (permissions 0600; it refuses to overwrite) and prints the line for the download server's key list. download-key shows the key id (kid) and that line again. download-token <app> <version> makes a token (valid 2 hours) for admin work and tests; it is written to the admin log.
…set the offline-login policy?
offline-policy shows the rules; offline-policy <*|@domain> <0..30> sets the number of days for this whole environment (*) or one organisation (@domain); 0 means not allowed; without a rule the default is 14 days. offline-policy-delete <*|@domain> removes a rule, offline-revoke <email> revokes every offline vault of an account, offline-tokens lists the valid ones. See PC login and docs/OFFLINE-LOGIN.md.
…set up an organisation for Microsoft (Entra) login?
org-create <name>, then org-tenant <name> <tenant id> (the GUID from Entra, Overview) and org-domain <name> <domain> for every allowed e-mail domain. orgs lists them. See Organisations and docs/WORK-LOGIN.md.
…register a workplace server or an EUZOS PC for Server Admin?
- Workplace server: normally the server installer registers it itself (
POST /api/workplace/v1/register). By hand:workplace-register <name> <key> [--network <ip>[,<ip>]]with the 64-hex key shown byworkplaceon the workplace server. - PC:
pc-register <name> <key> <org>with the device key frompckeyon the PC. - Admin rights:
org-admin <org> <email> [--off].
Compare the fingerprint the command prints with the one on the server/PC.
Details
- Everything is logged. Commands that change something write a line to the admin log (
admin-logshows it). The action texts in that log are stored data and stay Dutch (gebruiker-maak,beheer …,app-zet,werkplek-registreer, …). - Accounts are e-mail addresses. Every
<email>is normalised; the user name is always the address. - Mail limits. Verification mails: 1 per minute and 5 per day per address.
- Passwords are read without echo (asked twice) or from stdin; 10 to 200 characters.
- Legacy names. Old Dutch commands (
gebruiker-maak,kluis,werkplekken, …) and flags (--voornaam,--ja,--wis,--uit, …) are mapped to the English ones before the command runs (tablesLEGACY_COMMANDSandLEGACY_FLAGSinmain.rs, plus small maps inorg.rs,offline.rs,workplace.rs,workplace_admin.rs). - Values stay Dutch. Some arguments are wire values and are typed as such: the policy word
geen, the partsconsole,sshd,log,profiel, the status names (actief,niet_geverifieerd,geblokkeerd), the environment names (lokaal,sandbox,productie).
Note on names. Config keys are moving to English names; the Dutch ones are still accepted (see the config table below). This page shows the names the code uses today.
Reference
Commands of euzos-profielserver
Global option: --config <file> (or EUZOS_PROFILE_CONFIG).
Server
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
start | — | Starts the HTTP(S) server (tokio, at most 64 blocking threads). Locally it can do TLS itself (tls_chain/tls_key); in sandbox/production it listens on localhost behind Caddy. | Start line on stderr: environment, address, domain, key id, number of users, how mail is sent (never secrets). | — |
key | — | Opens the server (creates the signing key on first use). | Environment, domain, key id, and the lines for \EOS\FW\PROFIEL.TXT on an EUZOS PC, still in the legacy Dutch form (server=, omgeving=, sleutel= public key); the PC reads these as well as the English PROFILE.TXT keys (environment=, key=). | sleutel |
Accounts
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
user-create | <email> [--first-name F] [--last-name L] [--city C] [--display-name "Name"] [--language nl|en] [--password-stdin] | Creates an account with profiles Werk of school and Privé, status niet_geverifieerd, sends link + code. Display name: first + last name, otherwise --display-name, otherwise the local part of the address. | Confirmation; whether the mail was sent. | gebruiker-maak |
user-email | <current address or old name> <new address> | Requests a new address (must be confirmed by mail). For an active or blocked account the old address stays valid until then; an unconfirmed account is renamed at once. | What happened. | gebruiker-email |
user-verify | <email> | Emergency: confirms an unconfirmed account, or carries out a pending address change, without mail. Logged. | Confirmation. | gebruiker-verifieer |
user-block | <email> | Blocks the account; logs out all PCs, revokes all phones. | Counts of PCs/phones. | gebruiker-blokkeer |
user-unblock | <email> | Back to actief (only if blocked). | Confirmation. | gebruiker-deblokkeer |
user-delete | <email> [--yes <email>] | GDPR erasure of the whole account (gdpr::user_delete). Asks for the address again unless --yes matches. | Counts per kind of data; the address hash written to the admin log. | gebruiker-wis |
password | <email> [--password-stdin] [--revoke-devices] | New password; logs out all PCs; optionally revokes all phones. | Counts. | wachtwoord |
users | — | All accounts. | Columns: e-mail address, status, profiles, devices; pending new address. | gebruikers |
Admins and admin policy
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
admin-policy | <email> [<policy> | geen | --delete] | Shows/sets/removes the signed admin-command policy (console,sshd,log,profiel,ports,device or a part, or geen; device: the login screen background). Setting it logs out the account's PCs. | Current or new policy. | beheer |
admin-log | — | Prints the admin log. | date who action per line. | beheerlog |
admin-create | <email> | Gives an active account the admin role (beheerder) for the admin page. | Confirmation, number of paired phones, login hint. | beheerder-maak |
admin-delete | <email> | Removes the admin role (open sessions end at the next click). | Confirmation. | beheerder-wis |
admins | — | Accounts with the admin role. | Address, status, phones paired. | beheerders |
Phones and PC sessions
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
devices | [<email>] | Paired phones (all, or of one account). | Device id, user, platform, name, last used, status (active / revoked <date>). | apparaten |
device-revoke | <device id> | Revokes a phone; the PCs that logged in with it are logged out. | Confirmation or error. | apparaat-intrek |
pc-sessions | — | Logged-in PCs. | ref, profile, PC IP, device (or password / web page), since, expires. | pc-sessies |
Reports and vault (GDPR)
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
reports | — | How full the report database is (DriverEnricher, BrowserFeedback). | Path, MB used of the limit, devices, browser reports (with screenshot). Or "reports are off". | meldingen |
reports-delete | <email> | Deletes all reports of an account. | Counts. | meldingen-wis |
vault | <email> | What is in the account's vault (never the content), its desktop backgrounds (id and size, never the picture) and the vault log (90 days; desktop-background with stored, fetched, deleted). | profile, kind, key, changed; then the log. | kluis |
vault-delete | <email> | Deletes the whole vault of the account, including the storage key (the encrypted profile directories become unreadable), and its desktop backgrounds (sealed with that key). | Number of secrets deleted. | kluis-wis |
App catalogue and download tokens
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
apps | — | The app catalogue (what GET /api/apps returns). | Per app: version, size, SHA-256, date, description URLs, package URLs. | — |
app-set | <name> --version <n> --size <bytes> --sha256 <hex> --url <https://…/NAME.APP> [--url <mirror>]… [--package <https://…>]… | Adds or replaces an app (apps::App::check: up to 4 URLs per kind, description must end in /<NAME>.APP). Warns if the version goes down (PCs refuse a lower version). | The catalogue lines of the app. | app-zet |
app-delete | <name> | Removes an app; PCs then report "not available". | Confirmation. | app-wis |
download-key-create | — | Creates the download key (Ed25519) in download_key_file, mode 0600, refuses if it exists. | Environment, kid, the line for the download server's key file. | downloadsleutel-maak |
download-key | — | Reads the download key. | Environment, kid, key line. | downloadsleutel |
download-token | <app> <version> | A download token (2 hours) for admin work and tests, account "beheer"; logged with its jti. | The token on stdout; jti and expiry on stderr. | downloadtoken |
Offline login
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
offline-policy | [<*|@domain> <0..30>] | Without arguments: shows the default (14 days) and the rules. With: sets the days for * (this environment) or @domain (an organisation); 0 = not allowed. | The rules / the new rule. | offline-beleid |
offline-policy-delete | <*|@domain> | Removes a rule. | Confirmation. | offline-beleid-wis |
offline-revoke | <email> | Revokes all offline vaults of the account (the PC wipes its vault and logs out when it reconnects). | Number revoked. | offline-intrek |
offline-tokens | — | Valid offline vaults. | account, ref, profile, since, expires. | — |
Organisations (org.rs)
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
org-create | <name> | Creates an organisation (Microsoft work login). | Hint to run org-tenant and org-domain. | org-maak |
org-tenant | <name> <tenant id> | --delete | Sets (or removes) the Entra tenant id (a GUID). Without a tenant, Microsoft login is not possible. | The tenant. | — |
org-domain | <name> <domain> [--delete] | Adds (or removes) an allowed e-mail domain. | The domain list. | org-domein (flag --wis) |
orgs | — | All organisations. | name, tenant, domains, number of accounts. | — |
org-admin | <org> <email> [--off] | Makes an account admin of an organisation (workplaces, Server Admin), or not any more with --off. | Confirmation. | org-beheerder (flag --uit) |
Workplace servers and registered PCs (workplace.rs, workplace_admin.rs)
| Command | Arguments | What it does | Output | Legacy name |
|---|---|---|---|---|
workplace-register | <name> <key> [--network <ip>[,<ip>]] | Registers a workplace server by its public key (64 hex, shown by workplace on the server). Name 1–64 characters. Without --network the catalogue uses the public address of the sign-in. | Id and fingerprint; the network setting. | werkplek-registreer (flag --netwerk) |
workplaces | — | The workplace servers. | id, name, state (active, not active, never signed in, REVOKED), installed by, external address, lan, public, network. | werkplekken |
workplace-revoke | <id> | Revokes a workplace server: no sign-in, no download tokens, not in the catalogue. | Confirmation. | werkplek-intrek |
workplace-network | <id> <ip>[,<ip>]|auto | For which networks (at most 16) the catalogue names this workplace server to PCs; auto = the public address of its sign-in. | Confirmation. | werkplek-netwerk |
workplace-org | <id> <organization>|geen | Sets the organisation of a workplace server (needed for Server Admin). | Confirmation. | werkplek-org |
pc-register | <name> <key> <org> | Registers an EUZOS PC's device key (64 hex, from pckey on the PC) with an organisation. | Fingerprint to compare. | pc-registreer |
pcs | — | Registered PCs. | key, name, organisation, REVOKED. | — |
pc-revoke | <key> | Revokes a PC key: no more admin proofs for that PC. | Confirmation. | pc-intrek |
Legacy flags (hidden)
| Old | New |
|---|---|
--voornaam | --first-name |
--achternaam | --last-name |
--woonplaats | --city |
--weergavenaam | --display-name |
--taal | --language |
--wachtwoord-stdin | --password-stdin |
--ja | --yes |
--trek-apparaten-in | --revoke-devices |
--wis | --delete |
--versie | --version |
--grootte | --size |
--pakket | --package |
--netwerk | --network |
--uit | --off |
Configuration file (profiel.conf)
key = value lines, # starts a comment (config::read_lines). Relative paths are relative to the configuration file. Every key can also be given as an environment variable EUZOS_PROFILE_<KEY> (upper case), which wins over the file; the old prefix EUZOS_PROFIEL_ (with the English or the Dutch key) is still read. A secret itself (SMTP password, admin token, vault key, Graph secret) is refused in the file: it must be in its own file, named by the *_file key. Examples: server/profile/deploy/lokaal.conf, sandbox.conf, productie.conf. Values are never shown here.
| Key | Legacy (Dutch) key | Meaning | Default |
|---|---|---|---|
environment | omgeving | lokaal, sandbox or productie (required). | — |
address | adres | Where the server listens (ip:port); in sandbox/production only localhost (Caddy in front). | — (required) |
domain | domein | Public host[:port] as in the QR code, the signature and the app. | — (required) |
database | — | The SQLite database. | — (required) |
key | sleutel | The Ed25519 signing key file (created at first start, 0600). | — (required) |
tls_chain | tls_keten | Local only: certificate chain files (comma-separated). | none |
tls_key | tls_sleutel | Local only: the TLS private key file. | none |
behind_proxy | achter_proxy | Take the client IP from X-Forwarded-For (only from localhost with the proxy secret). | yes, except local |
proxy_secret_file | proxy_geheim_bestand | File with the secret Caddy sends in X-Euzos-Proxy. Required behind Caddy. | none |
admin_token_file | beheer_token_bestand | File with the admin key for the agent APIs (DriverEnricher, BrowserFeedback). Without it those APIs are 404. | none |
vault_key_file | kluis_sleutel_bestand | File with the vault's server key. Without it the vault is 404. | none |
download_key_file | download_sleutel_bestand | The download key file. Without it /api/apps/token is 404. | none |
download_base | download_basis | Base URL of the package server (https://<host>/); URLs under it need a download token. | none |
reports | meldingen | Keep DriverEnricher/BrowserFeedback reports. | yes in local/sandbox, no in production |
reports_database | meldingen_database | Report database path. | meldingen.db next to the database |
reports_max_mb | meldingen_max_mb | Limit of the report database in MB. | 1024 |
web_fallback | web_terugval | The web page with password as a fallback without the app. | yes |
allow_v1 | sta_v1_toe | Polls without PC secret (old 8.5 format); local only. | yes local, else no |
registration_open | registratie_open | Users may register themselves (app, PC, web page). | no |
pc_password | pc_wachtwoord | Logging in on the PC with e-mail and password (POST /api/pc/login). | yes |
admin_page | beheerpagina | The admin page /beheer. | yes, except production |
admin_domain | beheer_domein | The admin page's own domain (e.g. <internal-host>); must differ from domain. | none |
qr_duration | qr_duur | Seconds a QR login session that no phone fetched stays valid. | 30 |
confirm_duration | bevestig_duur | Seconds a fetched session waits for approval. | 120 |
token_duration | token_duur | Seconds a PC token (and the signed profile) is valid. | 43200 (12 h) |
app_duration | app_duur | Seconds an app sign-in with password (eza_) is valid. | 900 |
web_duration | web_duur | Seconds a sign-in on the web page is valid. | 3600 |
apple_app_id | — | iOS universal links (TEAMID.eu.euzos.app). | none |
android_package | android_pakket | Android app links: package name. | none |
android_fingerprints | android_vingerafdrukken | Android app links: signing certificate fingerprints (comma-separated). | none |
mail | — | graph, smtp or map (folder). Required in sandbox/production. | map locally |
mail_dir | mail_map | Folder for mail = map. | mail |
smtp_host | — | SMTP host. | — |
smtp_port | smtp_poort | 587 (STARTTLS) or 465 (TLS). | 587 |
smtp_user | smtp_gebruiker | SMTP user. | — |
smtp_password_file | smtp_wachtwoord_bestand | File with the SMTP password. | — |
graph_tenant | — | Microsoft Graph mail: tenant GUID. | — |
graph_client_id | — | Graph app registration (production must use its own, never the sandbox one). | — |
graph_secret_file | graph_geheim_bestand | File with the Graph client secret, or… | — |
graph_certificate_file | graph_certificaat_bestand | …certificate file, together with… | — |
graph_key_file | graph_sleutel_bestand | …its key file. | — |
sender | afzender | Sender of the mails. | EUZOS <no-reply@euzos.eu> |
reply_to | antwoordadres | Reply-to address. | none |
entra_client_id | — | Client id (GUID) of the EUZOS Entra app; without it /api/pc/entra is 404. | none |
entra_check_s | entra_controle_s | How often (s) an Entra account is re-checked with Microsoft (minimum 60). | 900 |
yes/no values also accept ja/nee, true/false, 1/0. Config::check refuses dangerous mixes: outside local the server must listen on localhost, may not do TLS itself, may not allow v1 polls, and needs proxy_secret_file behind Caddy; production may not use the sandbox Graph app registration.
Environment variables
| Variable | Meaning |
|---|---|
EUZOS_PROFILE_CONFIG (legacy EUZOS_PROFIEL_CONFIG) | Path of the configuration file when --config is not given. |
EUZOS_PROFILE_<KEY> (legacy EUZOS_PROFIEL_<KEY>, also with the Dutch key) | Overrides one configuration key, e.g. EUZOS_PROFILE_DATABASE. |
The download server CLI (euzos-download)
server/download/src/main.rs: the token check behind Caddy's forward_auth for download.euzos.eu (see API).
| Command | Arguments | What it does | Legacy name |
|---|---|---|---|
start | [--address 127.0.0.1:8091] [--keys <file>] [--blocklist <file>] | Runs the check server on localhost. Defaults: keys /etc/euzos-download/sleutels.txt, blocklist /etc/euzos-download/zwarte-lijst.txt; both are re-read when they change. | flags --adres, --sleutels, --zwarte-lijst |
revoke | <jti> [comment] | Puts a token's jti (32 lowercase hex, from the log) on the blocklist. | intrek |
keys | — | Lists the known key ids (kid). | sleutels |
Functions and modules
| Function | Role |
|---|---|
main::run | Parses --config, maps legacy names (command, flag_name), loads Config, dispatches. |
main::start | The server: euzos_profileserver::router on axum (TLS via rustls locally). |
main::admins | admin-create, admin-delete, admins. |
config::Config::load, config::read_lines, config::english_key | Configuration file + environment, legacy keys (LEGACY_KEYS). |
gdpr::user_delete | user-delete. |
offline::cli | offline-policy*, offline-revoke, offline-tokens. |
org::cli | org-create, org-tenant, org-domain, orgs. |
workplace::cli | workplace-register, workplaces, workplace-revoke, workplace-network. |
workplace_admin::cli | workplace-org, pc-register, pcs, pc-revoke, org-admin. |
download_token::Key::create / read / token | Download key and tokens. |
apps::App::check / lines | Validating and printing a catalogue entry. |
The Python prototype
tools/profileserver/profileserver.py is the earlier prototype from milestone 8.5 ("for now on the Mac", Python standard library only), with the commands start, user-create, password and users. It is not the production server. It is only still started by make profileserver PKI=/path (local HTTPS on port 8444, milestone 8.5; the Makefile also mentions it for creating a user); the real server runs with make profileserver-rs.
See also
- API · Admin page · Environments and deploy
- docs/PROFILESERVER-SETUP.md
- docs/PROFILE-PROTOCOL.md
- docs/ENGLISH.md ("Profile server CLI", "Database, configuration, CLI")
- docs/OFFLINE-LOGIN.md · docs/WORK-LOGIN.md · docs/WORKPLACE.md · docs/DOWNLOADSERVER.md
EUZOS