# Changelog
## Changes 10/20/2025 (v1.5.3)
security(acl): enforce folder-scope & own-only; fix file list “Select All”; harden ops
### fileListView.js (v1.5.3)
- Restore master “Select All” checkbox behavior and row highlighting.
- Keep selection working with own-only filtered lists.
- Build preview/thumb URLs via secure API endpoints; avoid direct /uploads.
- Minor UI polish: slider wiring and pagination focus handling.
### FileController.php (v1.5.3)
- Add enforceFolderScope($folder, $user, $perms, $need) and apply across actions.
- Copy/Move: require read on source, write on destination; apply scope on both.
- When user only has read_own, enforce per-file ownership (uploader==user).
- Extract ZIP: require write + scope; consistent 403 messages.
- Save/Rename/Delete/Create: tighten ACL checks; block dangerous extensions; consistent CSRF/Auth handling and error codes.
- Download/ZIP: honor read vs read_own; own-only gates by uploader; safer headers.
### FolderController.php (v1.5.3)
- Align with ACL: enforce folder-scope for non-admins; require owner or bypass for destructive ops.
- Create/Rename/Delete: gate by write on parent/target + ownership when needed.
- Share folder link: require share capability; forbid root sharing for non-admins; validate expiry; optional password.
- Folder listing: return only folders user can fully view or has read_own.
- Shared downloads/uploads: stricter validation, headers, and error handling.
This commits a consistent, least-privilege ACL model (owners/read/write/share/read_own), fixes bulk-select in the UI, and closes scope/ownership gaps across file & folder actions.
feat(dnd): default cards to sidebar on medium screens when no saved layout
- Adds one-time responsive default in loadSidebarOrder() (uses layoutDefaultApplied_v1)
- Preserves existing sidebarOrder/headerOrder and small-screen behavior
- Keeps user changes persistent; no override once a layout exists
---
## Changes 10/19/2025 (v1.5.2)
fix(admin): modal bugs; chore(api): update ReDoc SRI; docs(openapi): add annotations + spec
- adminPanel.js
- Fix modal open/close reliability and stacking order
- Prevent background scroll while modal is open
- Tidy focus/keyboard handling for better UX
- style.css
- Polish styles for Folder Access + Users views (spacing, tables, badges)
- Improve responsiveness and visual consistency
- api.php
- Update Redoc SRI hash and pin to the current bundle URL
- OpenAPI
- Add/refresh inline @OA annotations across endpoints
- Introduce src/openapi/Components.php with base Info/Server,
common responses, and shared components
- Regenerate and commit openapi.json.dist
- public/js/adminPanel.js
- public/css/style.css
- public/api.php
- src/openapi/Components.php
- openapi.json.dist
- public/api/** (annotated endpoints)
---
## Changes 10/19/2025 (v1.5.1)
fix(config/ui): serve safe public config to non-admins; init early; gate trash UI to admins; dynamic title; demo toast (closes #56)
Regular users were getting 403s from `/api/admin/getConfig.php`, breaking header title and login option rendering. Issue #56 tracks this.
### What changed
- **AdminController::getConfig**
- Return a **public, non-sensitive subset** of config for everyone (incl. unauthenticated and non-admin users): `header_title`, minimal `loginOptions` (disable* flags only), `globalOtpauthUrl`, `enableWebDAV`, `sharedMaxUploadSize`, and OIDC `providerUrl`/`redirectUri`.
- For **admins**, merge in admin-only fields (`authBypass`, `authHeaderName`).
- Never expose secrets or client IDs.
- **auth.js**
- `loadAdminConfigFunc()` now robustly handles empty/204 responses, writes sane defaults, and sets `document.title` from `header_title`.
- `showToast()` override: on `demo.filerise.net` shows a longer demo-creds toast; keeps TOTP “don’t nag” behavior.
- **main.js**
- Call `loadAdminConfigFunc()` early during app init.
- Run `setupTrashRestoreDelete()` **only for admins** (based on `localStorage.isAdmin`).
- **adminPanel.js**
- Bump visible version to **v1.5.1**.
- **index.html**
- Keep `
FileRise` static; runtime title now driven by `loadAdminConfigFunc()`.
### Security v1.5.1
- Prevents info disclosure by strictly limiting non-admin fields.
- Avoids noisy 403 for regular users while keeping admin-only data protected.
### QA
- As a non-admin:
- Opening the app no longer triggers a 403 on `getConfig.php`.
- Header title and login options render; document tab title updates to configured `header_title`.
- Trash/restore UI is not initialized.
- As an admin:
- Admin Panel loads extra fields; trash/restore UI initializes.
- Title updates correctly.
- On `demo.filerise.net`:
- Pre-login toast shows demo credentials for ~12s.
Closes #56.
---
## Changes 10/17/2025 (v1.5.0)
Security and permission model overhaul. Tightens access controls with explicit, server‑side ACL checks across controllers and WebDAV. Introduces `read_own` for own‑only visibility and separates view from write so uploaders can’t automatically see others’ files. Fixes session warnings and aligns the admin UI with the new capabilities.
> **Security note**
> This release contains security hardening based on a private report (tracked via a GitHub Security Advisory, CVE pending). For responsible disclosure, details will be published alongside the advisory once available. Users should upgrade promptly.
### Highlights
- **ACL**
- New `read_own` bucket (own‑only visibility) alongside `owners`, `read`, `write`, `share`.
- **Semantic change:** `write` no longer implies `read`.
- `ACL::applyUserGrantsAtomic()` to atomically set per‑folder grants (`view`, `viewOwn`, `upload`, `manage`, `share`).
- `ACL::purgeUser($username)` to remove a user from all buckets (used when deleting a user).
- Auto‑heal `folder_acl.json` (ensure `root` exists; add missing buckets; de‑dupe; normalize types).
- More robust admin detection (role flag or session/admin user).
- **Controllers**
- `FileController`: ACL + ownership enforcement for list, download, zip download, extract, move, copy, rename, create, save, tag edit, and share‑link creation. `getFileList()` now filters to the caller’s uploads when they only have `read_own` (no `read`).
- `UploadController`: requires `ACL::canWrite()` for the target folder; CSRF refresh path improved; admin bypass intact.
- `FolderController`: listing filtered by `ACL::canRead()`; optional parent filter preserved; removed name‑based ownership assumptions.
- **Admin UI**
- Folder Access grid now includes **View (own)**; bulk toolbar actions; column alignment fixes; more space for folder names; dark‑mode polish.
- **WebDAV**
- WebDAV now enforces ACL consistently: listing requires `read` (or `read_own` ⇒ shows only caller’s files); writes require `write`.
- Removed legacy “folderOnly” behavior — ACL is the single source of truth.
- Metadata/uploader is preserved through existing models.
### Behavior changes (⚠️ Breaking)
- **`write` no longer implies `read`.**
- If you want uploaders to see all files in a folder, also grant **View (all)** (`read`).
- If you want uploaders to see only their own files, grant **View (own)** (`read_own`).
- **Removed:** legacy `folderOnly` view logic in favor of ACL‑based access.
### Upgrade checklist
1. Review **Folder Access** in the admin UI and grant **View (all)** or **View (own)** where appropriate.
2. For users who previously had “upload but not view,” confirm they now have **Upload** + **View (own)** (or add **View (all)** if intended).
3. Verify WebDAV behavior for representative users:
- `read` shows full listings; `read_own` lists only the caller’s files.
- Writes only succeed where `write` is granted.
4. Confirm admin can upload/move/zip across all folders (regression tested).
### Affected areas
- `config/config.php` — session/cookie initialization ordering; proxy header handling.
- `src/lib/ACL.php` — new bucket, semantics, healing, purge, admin detection.
- `src/controllers/FileController.php` — ACL + ownership gates across operations.
- `src/controllers/UploadController.php` — write checks + CSRF refresh handling.
- `src/controllers/FolderController.php` — ACL‑filtered listing and parent scoping.
- `public/api/admin/acl/*.php` — includes `viewOwn` round‑trip and sanitization.
- `public/js/*` & CSS — folder access grid alignment and layout fixes.
- `src/webdav/*` & `public/webdav.php` — ACL‑aware WebDAV server.
### Credits
- Security report acknowledged privately and will be credited in the published advisory.
### Fix
- fix(folder-model): resolve syntax error, unexpected token
- Deleted accidental second `5 MB; lighter CM settings for big files.
- fileListView.js: latest-call-wins; compute editable via ext + sizeBytes (no blink).
- FileModel.php: add sizeBytes; cap inline content to ≤5 MB (INDEX_TEXT_BYTES_MAX).
- HTML: load extra CM modes: htmlmixed, php, clike, python, yaml, markdown, shell, sql, vb, ruby, perl, properties, nginx.
---
## Changes 10/5/2025 v1.3.14
fix(admin): OIDC optional by default; validate only when enabled (fixes #44)
- AdminModel::updateConfig now enforces OIDC fields only if disableOIDCLogin=false
- AdminModel::getConfig defaults disableOIDCLogin=true and guarantees OIDC keys
- AdminController default loginOptions sets disableOIDCLogin=true; CSRF via header or body
- Normalize file perms to 0664 after write
---
## Changes 10/4/2025 v1.3.13
fix(scanner): resolve dirs via CLI/env/constants; write per-item JSON; skip trash
fix(scanner): rebuild per-folder metadata to match File/Folder models
chore(scanner): skip profile_pics subtree during scans
- scan_uploads.php now falls back to UPLOAD_DIR/META_DIR from config.php
- prevents double slashes in metadata paths; respects app timezone
- unblocks SCAN_ON_START so externally added files are indexed at boot
- Writes per-folder metadata files (root_metadata.json / folder_metadata.json) using the same naming rule as the models
- Adds missing entries for files (uploaded, modified using DATE_TIME_FORMAT, uploader=Imported)
- Prunes stale entries for files that no longer exist
- Skips uploads/trash and symlinks
- Resolves paths from CLI flags, env vars, or config constants (UPLOAD_DIR/META_DIR)
- Idempotent; safe to run at startup via SCAN_ON_START
- Avoids indexing internal avatar images (folder already hidden in UI)
- Reduces scan noise and metadata churn; keeps firmware/other content indexed
---
## Changes 10/4/2025 v1.3.12
Fix: robust PUID/PGID handling; optional ownership normalization (closes #43)
- Remap www-data to PUID/PGID when running as root; skip with helpful log if non-root
- Added CHOWN_ON_START env to control recursive chown (default true; turn off after first run)
- SCAN_ON_START unchanged, with non-root fallback
---
## Changes 10/4/2025 v1.3.11
Chore: keep BASE_URL fallback, prefer env SHARE_URL; fix HTTPS auto-detect
- Remove no-op sed of SHARE_URL from start.sh (env already used)
- Build default share link with correct scheme (http/https, proxy-aware)
---
## Changes 10/4/2025 v1.3.10
Fix: index externally added files on startup; harden start.sh (#46)
- Run metadata scan before Apache when SCAN_ON_START=true (was unreachable after exec)
- Execute scan as www-data; continue on failure so startup isn’t blocked
- Guard env reads for set -u; add umask 002 for consistent 775/664
- Make ServerName idempotent; avoid duplicate entries
- Ensure sessions/metadata/log dirs exist with correct ownership and perms
No behavior change unless SCAN_ON_START=true.
---
## Changes 5/27/2025 v1.3.9
- Support for mounting CIFS (SMB) network shares via Docker volumes
- New `scripts/scan_uploads.php` script to generate metadata for imported files and folders
- `SCAN_ON_START` environment variable to trigger automatic scanning on container startup
- Documentation for configuring CIFS share mounting and scanning
- Clipboard Paste Upload Support (single image):
- Users can now paste images directly into the FileRise web interface.
- Pasted images are renamed to `image.png` and added to the upload queue using the existing drag-and-drop logic.
- Implemented using a `.isClipboard` flag and a delayed UI cleanup inside `xhr.addEventListener("load", ...)`.
---
## Changes 5/26/2025
- Updated `REGEX_FOLDER_NAME` in `config.php` to forbids < > : " | ? * characters in folder names.
- Ensures the whole name can’t end in a space or period.
- Blocks Windows device names.
- Updated `FolderController.php` when `createFolder` issues invalid folder name to return `http_response_code(400);`
---
## Changes 5/23/2025 v1.3.8
- **Folder-strip context menu**
- Enabled right-click on items in the new folder strip (above file list) to open the same “Create / Rename / Share / Delete Folder” menu as in the main folder tree.
- Bound `contextmenu` event on each `.folder-item` in `loadFileList` to:
- Prevent the default browser menu
- Highlight the clicked folder-strip item
- Invoke `showFolderManagerContextMenu` with menu entries:
- Create Folder
- Rename Folder
- Share Folder (passes the strip’s `data-folder` value)
- Delete Folder
- Ensured menu actions are wrapped in arrow functions (`() => …`) so they fire only on menu-item click, not on render.
- Refactored folder-strip injection in `fileListView.js` to:
- Mark each strip item as `draggable="true"` (for drag-and-drop)
- Add `el.addEventListener("contextmenu", …)` alongside existing click/drag handlers
- Clean up global click listener for hiding the context menu
- Prevented premature invocation of `openFolderShareModal` by switching to `action: () => openFolderShareModal(dest)` instead of calling it directly.
- **Create File/Folder dropdown**
- Replaced standalone “Create File” button with a combined dropdown button in the actions toolbar.
- New markup
- Wired up JS handlers in `fileActions.js`:
- `#createFileOption` → `openCreateFileModal()`
- `#createFolderOption` → `document.getElementById('createFolderModal').style.display = 'block'`
- Toggled `.dropdown-menu` visibility on button click, and closed on outside click.
- Applied dark-mode support: dropdown background and text colors switch with `.dark-mode` class.
---
## Changes 5/22/2025 v1.3.7
- `.folder-strip-container .folder-name` css added to center text below folder material icon.
- Override file share_url to always use current origin
- Update `fileList` css to keep file name wrapping tight.
---
## Changes 5/21/2025
- **Drag & Drop to Folder Strip**
- Enabled dragging files from the file list directly onto the folder-strip items.
- Hooked up `folderDragOverHandler`, `folderDragLeaveHandler`, and `folderDropHandler` to `.folder-strip-container .folder-item`.
- On drop, files are moved via `/api/file/moveFiles.php` and the file list is refreshed.
- **Restore files from trash Toast Message**
- Changed the restore handlers so that the toast always reports the actual file(s) restored (e.g. “Restored file: foo.txt”) instead of “No trash record found.”
- Removed reliance on backend message payload and now generate the confirmation text client-side based on selected items.
---
## Changes 5/20/2025 v1.3.6
- **domUtils.js**
- `updateFileActionButtons`
- Hide selection buttons (`Delete Files`, `Copy Files`, `Move Files` & `Download ZIP`) until file is selected.
- Hide `Extract ZIP` until selecting zip files
- Hide `Create File` button when file list items are selected.
---
## Changes 5/19/2025 v1.3.5
### Added Folder strip & Create File
- **Folder strip in file list**
- `loadFileList` now fetches sub-folders in parallel from `/api/folder/getFolderList.php`.
- Filters to only direct children of the current folder, hiding `profile_pics` and `trash`.
- Injects a new `.folder-strip-container` just below the Files In above (summary + slider).
- Clicking a folder in the strip updates:
- the breadcrumb (via `updateBreadcrumbTitle`)
- the tree selection highlight
- reloads `loadFileList` for the chosen folder.
- **Create File feature**
- New “Create New File” button added to the file-actions toolbar and context menu.
- New endpoint `public/api/file/createFile.php` (handled by `FileController`/`FileModel`):
- Creates an empty file if it doesn’t already exist.
- Appends an entry to `_metadata.json` with `uploaded` timestamp and `uploader`.
- `fileActions.js`:
- Implemented `handleCreateFile()` to show a modal, POST to the new endpoint, and refresh the list.
- Added translations for `create_new_file` and `newfile_placeholder`.
---
## Changees 5/15/2025
### Drag‐and‐Drop Upload extended to File List
- **Forward file‐list drops**
Dropping files onto the file‐list area (`#fileListContainer`) now re‐dispatches the same `drop` event to the upload card’s drop zone (`#uploadDropArea`)
- **Visual feedback**
Added a `.drop-hover` class on `#fileListContainer` during drag‐over for a dashed‐border + light‐background hover state to indicate it accepts file drops.
---
## Changes 5/14/2025 v1.3.4
### 1. Button Grouping (Bootstrap)
- Converted individual action buttons (`download`, `edit`, `rename`, `share`) in both **table view** and **gallery view** into a single Bootstrap button group for a cleaner, more compact UI.
- Applied `btn-group` and `btn-sm` classes for consistent sizing and spacing.
### 2. Header Dropdown Replacement
- Replaced the standalone “User Panel” icon button with a **dropdown wrapper** (`.user-dropdown`) in the header.
- Dropdown toggle now shows:
- **Profile picture** (if set) or the Material “account_circle” icon
- **Username** text (between avatar and caret)
- Down-arrow caret span.
### 3. Menu Items Moved to Dropdown
- Moved previously standalone header buttons into the dropdown menu:
- **User Panel** opens the modal
- **Admin Panel** only shown when `data.isAdmin` and on `demo.filerise.net`
- **API Docs** calls `openApiModal()`
- **Logout** calls `triggerLogout()`
- Each menu item now has a matching Material icon (e.g. `person`, `admin_panel_settings`, `description`, `logout`).
### 4. Profile Picture Support
- Added a new `/api/profile/uploadPicture.php` endpoint + `UserController::uploadPicture()` + corresponding `UserModel::setProfilePicture()`.
- On **Open User Panel**, display:
- Default avatar if none set
- Current profile picture if available
- In the **User Panel** modal:
- Stylish “edit” overlay icon on the avatar to launch file picker
- Auto-upload on file selection (no “Save” button click needed)
- Preview updates immediately and header avatar refreshes live
- Persisted in `users.txt` and re-fetched via `getCurrentUser.php`
### 5. API Docs & Logout Relocation
- Removed API Docs from User Panel
- Removed “Logout” buttons from the header toolbar.
- Both are now menu entries in the **User Dropdown**.
### 6. Admin Panel Conditional
- The **Admin Panel** button was:
- Kept in the dropdown only when `data.isAdmin`
- Removed entirely elsewhere.
### 7. Utility & Styling Tweaks
- Introduced a small `normalizePicUrl()` helper to strip stray colons and ensure a leading slash.
- Hidden the scrollbar in the User Panel modal via:
- Inline CSS (`scrollbar-width: none; -ms-overflow-style: none;`)
- Global/WebKit rule for `::-webkit-scrollbar { display: none; }`
- Made the User Panel modal fully responsive and vertically centered, with smooth dark-mode support.
### 8. File/List View & Gallery View Sliders
- **Unified “View‐Mode” Slider**
Added a single slider panel (`#viewSliderContainer`) in the file‐list actions toolbar that switches behavior based on the current view mode:
- **Table View**: shows a **Row Height** slider (min 31px, max 60px).
- Adjusts the CSS variable `--file-row-height` to resize all `` heights.
- Persists the chosen height in `localStorage`.
- **Gallery View**: shows a **Columns** slider (min 1, max 6).
- Updates the grid’s `grid-template-columns: repeat(N, 1fr)`.
- Persists the chosen column count in `localStorage`.
- **Injection Point**
The slider container is dynamically inserted (or updated) just before the folder summary (`#fileSummary`) in `loadFileList()`, ensuring a consistent position across both view modes.
- **Live Updates**
Moving the slider thumb immediately updates the visible table row heights or gallery column layout without a full re‐render.
- **Styling & Alignment**
- `#viewSliderContainer` uses `inline-flex` and `align-items: center` so that label, slider, and value text are vertically aligned with the other toolbar elements.
- Reset margins/padding on the label and value span within `#viewSliderContainer` to eliminate any vertical misalignment.
### 9. Fixed new issues with Undefined username in header on profile pic change & TOTP Enabled not checked
**openUserPanel**
- **Rewritten entirely with DOM APIs** instead of `innerHTML` for any user-supplied text to eliminates “DOM text reinterpreted as HTML” warnings.
- **Default avatar fallback**: now uses `'/assets/default-avatar.png'` whenever `profile_picture` is empty.
- **TOTP checkbox initial state** is now set from the `totp_enabled` value returned by the server.
- **Modal title sync** on reopen now updates the `(username)` correctly (no more “undefined” until refresh).
- **Re-sync on reopen**: background color, avatar, TOTP checkbox and language selector all update when reopen the panel.
**updateAuthenticatedUI**
- **Username fix**: dropdown toggle now always uses `data.username` so the name never becomes `undefined` after uploading a picture.
- **Profile URL update** via `fetchProfilePicture()` always writes into `localStorage` before rebuilding the header, ensuring avatar+name stay in sync instantly.
- **Dropdown rebuild logic** tweaked to update the toggle’s innerHTML with both avatar and username on every call.
**UserModel::getUser**
- Switched to `explode(':', $line, 4)` to the fourth “profile_picture” field without clobbering the TOTP secret.
- **Strip trailing colons** from the stored URL (`rtrim($parts[3], ':')`) so we never send `…png:` back to the client.
- Returns an array with both `'username'` and `'profile_picture'`, matching what `getCurrentUser.php` needs.
### 10. setAttribute + encodeURI to avoid “DOM text reinterpreted as HTML” alerts
### 11. Fix duplicated Upload & Folder cards if they were added to header and page was refreshed
---
## Changes 5/8/2025
### Docker 🐳
- Ensure `/var/www/config` exists and is owned by `www-data` (chmod 750) so that `start.sh`’s `sed -i` updates to `config.php` work reliably
---
## Changes 5/8/2025 v1.3.3
### Enhancements
- **Admin API** (`updateConfig.php`):
- Now merges incoming payload onto existing on-disk settings instead of overwriting blanks.
- Preserves `clientId`, `clientSecret`, `providerUrl` and `redirectUri` when those fields are omitted or empty in the request.
- **Admin API** (`getConfig.php`):
- Returns only a safe subset of admin settings (omits `clientSecret`) to prevent accidental exposure of sensitive data.
- **Frontend** (`auth.js`):
- Update UI based on merged loginOptions from the server, ensuring blank or missing fields no longer revert your existing config.
- **Auth API** (`auth.php`):
- Added `$oidc->addScope(['openid','profile','email']);` to OIDC flow. (This should resolve authentik issue)
---
## Changes 5/8/2025 v1.3.2
### config/config.php
- Added a default `define('AUTH_BYPASS', false)` at the top so the constant always exists.
- Removed the static `AUTH_HEADER` fallback; instead read the adminConfig.json at the end of the file and:
- Overwrote `AUTH_BYPASS` with the `loginOptions.authBypass` setting from disk.
- Defined `AUTH_HEADER` (normalized, e.g. `"X_REMOTE_USER"`) based on `loginOptions.authHeaderName`.
- Inserted a **proxy-only auto-login** block before the usual session/auth checks:
If `AUTH_BYPASS` is true and the trusted header (`$_SERVER['HTTP_' . AUTH_HEADER]`) is present, bump the session, mark the user authenticated/admin, load their permissions, and skip straight to JSON output.
- Relax filename validation regex to allow broader Unicode and special chars
### src/controllers/AdminController.php
- Ensured the returned `loginOptions` object always contains:
- `authBypass` (boolean, default false)
- `authHeaderName` (string, default `"X-Remote-User"`)
- Read `authBypass` and `authHeaderName` from the nested `loginOptions` in the request payload.
- Validated them (`authBypass` → bool; `authHeaderName` → non-empty string, fallback to `"X-Remote-User"`).
- Included them when building the `$configUpdate` array to pass to the model.
### src/models/AdminModel.php
- Normalized `loginOptions.authBypass` to a boolean (default false).
- Validated/truncated `loginOptions.authHeaderName` to a non-empty trimmed string (default `"X-Remote-User"`).
- JSON-encoded and encrypted the full config, now including the two new fields.
- After decrypting & decoding, normalized the loaded `loginOptions` to always include:
- `authBypass` (bool)
- `authHeaderName` (string, default `"X-Remote-User"`)
- Left all existing defaults & validations for the original flags intact.
### public/js/adminPanel.js
- **Login Options** section:
- Added a checkbox for **Disable All Built-in Logins (proxy only)** (`authBypass`).
- Added a text input for **Auth Header Name** (`authHeaderName`).
- In `handleSave()`:
- Included the new `authBypass` and `authHeaderName` values in the payload sent to `updateConfig.php`.
- In `openAdminPanel()`:
- Initialized those inputs from `config.loginOptions.authBypass` and `config.loginOptions.authHeaderName`.
### public/js/auth.js
- In `loadAdminConfigFunc()`:
- Stored `authBypass` and `authHeaderName` in `localStorage`.
- In `checkAuthentication()`:
- After a successful login check, called a new helper (`applyProxyBypassUI()`) which reads `localStorage.authBypass` and conditionally hides the entire login form/UI.
- In the “not authenticated” branch, only shows the login form if `authBypass` is false.
- No other core fetch/token logic changed; all existing flows remain intact.
### Security old
- **Admin API**: `getConfig.php` now returns only a safe subset of admin settings (omits `clientSecret`) to prevent accidental exposure of sensitive data.
---
## Changes 5/4/2025 v1.3.1
### Modals
- **Added** a shared `.editor-close-btn` component for all modals:
- File Tags
- User Panel
- TOTP Login & Setup
- Change Password
- **Truncated** long filenames in the File Tags modal header using CSS `text-overflow: ellipsis`.
- **Resized** File Tags modal from 400px to 450px wide (with `max-width: 90vw` fallback).
- **Capped** User Panel height at 381px and hidden scrollbars to eliminate layout jumps on hover.
### HTML
- **Moved** `…
` out of `.main-wrapper` so the login form can show independently of the app shell.
- **Added** `` immediately inside `` to cover the UI during auth checks.
- **Inserted** inline `