Security:
- PBKDF2-HMAC-SHA256 password hashing (260k iterations, random salt per password)
- Legacy MICRONAS_PASS plaintext still works for existing installs
- MICRONAS_PASS_HASH replaces plaintext in env file after first setup/change
- Timing-safe comparison via hmac.compare_digest
First-login setup:
- /setup route: shown when no credentials configured (fresh install)
- Replaces editing /etc/micronas.env manually
- setup.html dark-themed form matching login.html
Admin credential change:
- POST /api/admin/credentials (requires current password to confirm)
- Settings button in topbar opens modal for username + password change
- Session cleared after change → redirected to login
User management:
- PATCH /api/users/<name>: rename Linux user (usermod -l)
SMB + WebDAV entries removed, password reset required after rename
- Rename button in users table, modal with yellow warning
WebDAV:
- Options Indexes: directories now browsable in a regular web browser
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- _list_groups(): reads /etc/group, returns groups with gid >= 1000
plus a small whitelist (root, staff, sambashare, www-data)
- GET/POST /api/groups: list and create groups (groupadd)
- DELETE /api/groups/<name>: delete group (groupdel)
- POST /api/groups/<name>/members: add user to group (gpasswd -a)
- DELETE /api/groups/<name>/members/<user>: remove user (gpasswd -d)
Frontend:
- Users tab now has a Groups section: table with GID, member badges
with × remove buttons, per-row "add member" select populated with
users not already in the group, delete group button
- loadUsers() caches result in _cachedUsers for groups table to use
- openEditModal is now async; fetches /api/users + /api/groups before
rendering so Owner and Group inputs have datalist autocomplete
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- shares.js, users.js: JSON.stringify() inside onclick="..." attributes
produced unescaped " chars that broke HTML attribute parsing — all
dynamic onclick JSON now passed through esc() so the browser decodes
" back to " before executing the handler
- Replace browser confirm() dialogs with a styled Bootstrap modal
(#deleteModal) for share and user deletion — reusable across all tabs
- users.js: rename shadow variable 'confirm' → 'pwConfirm' to avoid
shadowing the now-removed confirm() call
- main.js: auto-refresh now reloads shares and users every 30 s,
not just the dashboard
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>