# Changelog ## Changes 11/26/2025 (v2.0.4) release(v2.0.4): harden sessions and align Pro paths with USERS_DIR - Enable strict_types in config.php and AdminController - Decouple PHP session lifetime from "remember me" window - Regenerate session ID on persistent token auto-login - Point Pro license / bundle paths at USERS_DIR instead of hardcoded /users - Tweak folder management card drag offset for better alignment --- ## Changes 11/26/2025 (v2.0.3) release(v2.0.3): polish uploads, header dock, and panel fly animations - Rework upload drop area markup to be rebuild-safe and wire a guarded "Choose files" button so only one OS file-picker dialog can open at a time. - Centralize file input change handling and reset selectedFiles/_currentResumableIds per batch to avoid duplicate resumable entries and keep the progress list/drafts in sync. - Ensure drag-and-drop uploads still support folder drops while file-picker is files-only. - Add ghost-based animations when collapsing panels into the header dock and expanding them back to sidebar/top zones, inheriting card background/border/shadow for smooth visuals. - Offset sidebar ghosts so upload and folder cards don't stack directly on top of each other. - Respect header-pinned cards: cards saved to HEADER stay as icons and no longer fly out on expand. - Slightly tighten file summary margin in the file list header for better alignment with actions. --- ## Changes 11/23/2025 (v2.0.2) release(v2.0.2): add config-driven demo mode and lock demo account changes - Wire FR_DEMO_MODE through AdminModel/siteConfig and admin getConfig (demoMode flag) - Drive demo detection in JS from __FR_SITE_CFG__.demoMode instead of hostname - Show consistent login tip + toasts for demo using shared __FR_DEMO__ flag - Block password changes for the demo user and profile picture uploads when in demo mode - Keep normal user dropdown/admin UI visible even on the demo, while still protecting the demo account --- ## Changes 11/23/2025 (v2.0.0) ### FileRise Core v2.0.0 & FileRise Pro v1.1.0 ```text release(v2.0.0): feat(pro): client portals + portal login flow release(v2.0.1): fix: harden portal + core login redirects for codeql ``` ### Core v2.0.0 - **Portal plumbing in core** - New public pages: `portal.html` and `portal-login.html` for client-facing views. - New portal controller + API endpoints that read portal definitions from the Pro bundle, enforce expiry, and expose safe public metadata. - Login flow now respects a `?redirect=` parameter so portals can bounce through login cleanly and land back on the right slug. - **Admin UX + styling** - Admin panel CSS pulled into a dedicated `adminPanelStyles.js` helper instead of inline styles. - User Groups and Client Portals modals use the new shared styling and dark-mode tweaks so they match the rest of the UI. - **Breadcrumb root fix** - Breadcrumbs now always show **root** explicitly and behave correctly when you’re at top level vs nested folders. - **Routing** - Apache rewrite added for pretty portal URLs: `https://host/portal/` → `portal.html?slug=` without affecting other routes. ### Pro v1.1.0 – Client Portals - **Client portal definitions (Admin → FileRise Pro → Client Portals)** - Create multiple portals, each with: - Slug + display name - Target folder - Optional client email - Upload-only / allow-download flags - Per-portal expiry date - Portal-level copy and branding: - Optional title + instructions - Accent color used throughout the portal UI - Footer text at bottom of the portal page - **Optional intake form before uploads** - Enable a form per portal with fields: name, email, reference, notes. - Per-field “default value” and “required” toggles. - Form must be completed before uploads when enabled. - **Submissions log** - Each portal keeps a submissions list showing: - Date/time, folder, submitting user, IP address - The intake form values (name, email, reference, notes). - **Client-facing experience** - New portal UI with: - Branded header (title + accent color) - Optional intake form - Drag-and-drop upload dropzone - If downloads are enabled, a clean list/grid of files already in that portal’s folder with download buttons. - **Portal login page** - Minimal login screen that pulls title/accent/footer from portal metadata. - After successful login, user is redirected back to the original portal URL. --- ## Changes 11/21/2025 (v1.9.14) release(v1.9.14): inline folder rows, synced folder icons, and compact theme polish - Add ACL-aware folder stats and byte counts in FolderModel::countVisible() - Show subfolders inline as rows above files in table view (Explorer-style) - Page folders + files together and wire folder rows into existing DnD and context menu flows - Add folder action buttons (move/rename/color/share) with capability checks from /api/folder/capabilities.php - Cache folder capabilities and owners to avoid repeat calls per row - Add user settings to toggle folder strip and inline folder rows (stored in localStorage) - Default itemsPerPage to 50 and remember current page across renders - Sync inline folder icon size to file row height and tweak vertical alignment for different row heights - Update table headers + i18n keys to use Name / Size / Modified / Created / Owner labels - Compact and consolidate light/dark theme CSS, search pill, pagination, and font-size controls - Tighten file action button hit areas and add specific styles for folder move/rename buttons --- ## Changes 11/20/2025 (v1.9.13) release(v1.9.13): style(ui): compact dual-theme polish for lists, inputs, search & modals - Added compact, unified light/dark theme for core surfaces (file list, upload, folder manager, admin panel). - Updated modals, dropdown menus, and editor header to use the same modern panel styling in both themes. - Restyled search bar into a pill-shaped control with a dedicated icon chip and better hover states. - Refined pagination (Prev/Next) and font size (A-/A+) buttons to be smaller, rounded, and more consistent. - Normalized input fields so borders render cleanly and focus states are consistent across the app. - Tweaked button shadows so primary actions (Create/Upload) pop without feeling heavy in light mode. - Polished dark-mode colors for tables, rows, toasts, and meta text for a more “app-like” feel. --- ## Changes 11/19/2025 (v1.9.12) release(v1.9.12): feat(pro-acl): add user groups and group-aware ACL - Add Pro user groups as a first-class ACL source: - Load group grants from FR_PRO_BUNDLE_DIR/groups.json in ACL::hasGrant(). - Treat group grants as additive only; they can never remove access. - Introduce AclAdminController: - Move getGrants/saveGrants logic into a dedicated controller. - Keep existing ACL normalization and business rules (shareFolder ⇒ view, shareFile ⇒ at least viewOwn). - Refactor public/api/admin/acl/getGrants.php and saveGrants.php to use the controller. - Implement Pro user group storage and APIs: - Add ProGroups store class under FR_PRO_BUNDLE_DIR (groups.json with {name,label,members,grants}). - Add /api/pro/groups/list.php and /api/pro/groups/save.php, guarded by AdminController::requireAuth/requireAdmin/requireCsrf(). - Keep groups and bundle code behind FR_PRO_ACTIVE/FR_PRO_BUNDLE_DIR checks. - Ship Pro-only endpoints from core instead of the bundle: - Move public/api/pro/uploadBrandLogo.php into core and gate it on FR_PRO_ACTIVE. - Remove start.sh logic that copied public/api/pro from the Pro bundle into the container image. - Extend admin UI for user groups: - Turn “User groups” into a real Pro-only modal with add/delete groups, multi-select members, and member chips. - Add “Edit folder access” for each group, reusing the existing folder grants grid. - Overlay group grants when editing a user’s ACL: - Show which caps are coming from groups, lock those checkboxes, and update tooltips. - Show group membership badges in the user permissions list. - Add a collapsed “Groups” section at the top of the permissions screen to preview group ACLs (read-only). - Misc: - Bump PRO_LATEST_BUNDLE_VERSION hint in adminPanel.js to v1.0.1. - Tweak modal border-radius styling to include the new userGroups and groupAcl modals. --- ## Changes 11/18/2025 (v1.9.11) release(v1.9.11): fix(media): HTTP Range streaming; feat(ui): paged folder strip (closes #68) - media: add proper HTTP Range support to /api/file/download.php so HTML5 video/audio can seek correctly across all browsers (Brave/Chrome/Android/Windows). - media: avoid buffering the entire file in memory; stream from disk with 200/206 responses and Accept-Ranges for smoother playback and faster start times. - media: keep video progress tracking, watched badges, and status chip behavior unchanged but now compatible with the new streaming endpoint. - ui: update the folder strip to be responsive: - desktop: keep the existing "chip" layout with icon above name. - mobile: switch to inline rows `[icon] [name]` with reduced whitespace. - ui: add simple lazy-loading for the folder strip so only the first batch of folders is rendered initially, with a "Load more…" button to append chunks for very large folder sets (stays friendly with 100k+ folders). - misc: small CSS tidy-up around the folder strip classes to remove duplicates and keep mobile/desktop behavior clearly separated. --- ## Changes 11/18/2025 (v1.9.10) release(v1.9.10): add Pro bundle installer and admin panel polish - Add FileRise Pro section in admin panel with license management and bundle upload - Persist Pro bundle under users/pro and sync public/api/pro endpoints on container startup - Improve admin config API: Pro metadata, license file handling, hardened auth/CSRF helpers - Update Pro badge/version UI with “update available” hint and link to filerise.net - Change Pro bundle installer to always overwrite existing bundle files for clean upgrades --- ## Changes 11/16/2025 (v1.9.9) release(v1.9.9): fix(branding): sanitize custom logo URL preview - Sanitize branding.customLogoUrl on the server before writing siteConfig.json - Allow only http/https or site-relative paths; strip invalid/sneaky values - Update adminPanel.js live logo preview to set img src/alt safely - Addresses CodeQL XSS warning while keeping Pro branding logo overrides working --- ## Changes 11/16/2025 (v1.9.8) release(v1.9.8): feat(pro): wire core to Pro licensing + branding hooks - Add Pro feature flags + bootstrap wiring - Define FR_PRO_ACTIVE/FR_PRO_TYPE/FR_PRO_EMAIL/FR_PRO_VERSION/FR_PRO_LICENSE_FILE in config.php and optionally require src/pro/bootstrap_pro.php. - Expose a `pro` block from AdminController::getConfig() so the UI can show license status, type, email, and bundle version without leaking the raw key. - Implement license save endpoint - Add AdminController::setLicense() and /api/admin/setLicense.php to accept a FRP1 license string via JSON, validate basic shape, and persist it to FR_PRO_LICENSE_FILE with strict 0600 permissions. - Return structured JSON success/error responses for the admin UI. - Extend admin config model with branding + safer validation - Add `branding.customLogoUrl`, `branding.headerBgLight`, and `branding.headerBgDark` fields to AdminModel defaults and updateConfig(). - Introduce AdminModel::sanitizeLogoUrl() to allow only site-relative /uploads paths or http(s) URLs; reject absolute filesystem paths, data: URLs, and javascript: URLs. - Continue to validate ONLYOFFICE docsOrigin as http(s) only, keeping core config hardening intact. - New Pro-aware Admin Panel UI - Rework User Management section to group: - Add user / Remove user - Folder Access (per-folder ACL) - User Permissions (account-level flags) - Add Pro-only actions with clear gating: - “User groups” button (Pro) - “Client upload portal” button with “Pro · Coming soon” pill - Add “FileRise Pro” section: - Show current Pro status (Free vs Active) + license metadata. - Textarea for pasting license key, file upload helper, and “Save license” action wired to /api/admin/setLicense.php. - Optional “Copy current license” button when a license is present. - Add “Sponsor / Donations” section with fixed GitHub Sponsors and Ko-fi URLs and one-click copy/open buttons. - Header branding controls (Pro) - Add Header Logo + Header Colors controls under Header Settings, gated by `config.pro.active`. - Allow uploading a logo via /api/pro/uploadBrandLogo.php and auto-filling the normalized /uploads path. - Add live-preview helpers to update the header logo and header background colors in the running UI after saving. - Apply branding on app boot - Update main.js to read branding config on load and apply: - Custom header logo (or fallback to /assets/logo.svg). - Light/dark header background colors via CSS variables. - Keeps header consistent with saved branding across reloads and before opening the admin panel. - Styling + UX polish - Add styles for new admin sections: collapsible headers, dark-mode aware modal content, and refined folder access grid. - Introduce .btn-pro-admin and .btn-pro-pill classes to render “Pro” and “Pro · Coming soon” pills overlayed on buttons, matching the existing header “Core/Pro” badge treatment. - Minor spacing/typography tweaks in admin panel and ACL UI. Note: Core code remains MIT-licensed; Pro functionality is enabled via optional runtime hooks and separate closed-source bundle, without changing the core license text. --- ## Changes 11/14/2025 (v1.9.7) release(v1.9.7): harden client path guard and refine header/folder strip CSS - Tighten isSafeFolderPath() to reject dot-prefixed/invalid segments (client-side defense-in-depth on folder paths). - Rework header layout: consistent logo sizing, centered title, cleaner button alignment, and better small-screen stacking. - Polish user dropdown and icon buttons: improved hover/focus states, dark-mode colors, and rounded menu corners. - Update folder strip tiles: cap tile width, allow long folder names to wrap neatly, and fine-tune text/icon alignment. - Tweak folder tree rows: better label wrapping, vertical alignment, and consistent SVG folder icon rendering. - Small CSS cleanup and normalization (body, main wrapper, media modal/progress styles) without changing behavior. --- ## Changes 11/14/2025 (v1.9.6) release(v1.9.6): hardened resumable uploads, menu/tag UI polish and hidden temp folders (closes #67) - Resumable uploads - Normalize resumable GET “test chunk” handling in `UploadModel` using `resumableChunkNumber` + `resumableIdentifier`, returning explicit `status: "found"|"not found"`. - Skip CSRF checks for resumable GET tests in `UploadController`, but keep strict CSRF validation for real POST uploads with soft-fail `csrf_expired` responses. - Refactor `UploadModel::handleUpload()` for chunked uploads: strict filename validation, safe folder normalization, reliable temp chunk directory creation, and robust merge with clear errors if any chunk is missing. - Add `UploadModel::removeChunks()` + internal `rrmdir()` to safely clean up `resumable_…` temp folders via a dedicated controller endpoint. - Frontend resumable UX & persistence - Enable `testChunks: true` for Resumable.js and wire GET checks to the new backend status logic. - Track in-progress resumable files per user in `localStorage` (identifier, filename, folder, size, lastPercent, updatedAt) and show a resumable hint banner inside the Upload card with a dismiss button that clears the hints for that folder. - Clamp client-side progress to max `99%` until the server confirms success, so aborted tabs still show resumable state instead of “100% done”. - Improve progress UI: show upload speed, spinner while finalizing, and ensure progress elements exist even for non-standard flows (e.g., submit without prior list build). - On complete success, clear the progress UI, reset the file input, cancel Resumable’s internal queue, clear draft records for the folder, and re-show the resumable banner only when appropriate. - Hiding resumable temp folders - Hide `resumable_…` folders alongside `trash` and `profile_pics` in: - Folder tree BFS traversal (child discovery / recursion). - `listChildren.php` results and child-cache hydration. - The inline folder strip above the file list (also filtered in `fileListView.js`). - Folder manager context menu upgrade - Replace the old ad-hoc folder context menu with a unified `filr-menu` implementation that mirrors the file context menu styling. - Add Material icon mapping per action (`create_folder`, `move_folder`, `rename_folder`, `color_folder`, `folder_share`, `delete_folder`) and clamp the menu to viewport with escape/outside-click close behavior. - Wire the new menu from both tree nodes and breadcrumb links, respecting locked folders and current folder capabilities. - File context menu & selection logic - Define a semantic file context menu in `index.html` (`#fileContextMenu` with `.filr-menu` buttons, icons, `data-action`, and `data-when` visibility flags). - Rebuild `fileMenu.js` to: - Derive the current selection from file checkboxes and map back to real `fileData` entries, handling the encoded row IDs. - Toggle menu items based on selection state (`any`, `one`, `many`, `zip`, `can-edit`) and hide redundant separators. - Position the menu within the viewport, add ESC/outside-click dismissal, and delegate click handling to call the existing file actions (preview, edit, rename, copy/move/delete/download/extract, tag single/multiple). - Tagging system robustness - Refactor `fileTags.js` to enforce single-instance modals for both single-file and multi-file tagging, preventing duplicate DOM nodes and double bindings. - Centralize global tag storage (`window.globalTags` + `localStorage`) with shared dropdowns for both modals, including “×” removal for global tags that syncs back to the server. - Make the tag modals safer and more idempotent (re-usable DOM, Esc and backdrop-to-close, defensive checks on elements) while keeping the existing file row badge rendering and tag-based filtering behavior. - Localize various tag-related strings where possible and ensure gallery + table views stay in sync after tag changes. - Visual polish & theming - Introduce a shared `--menu-radius` token and apply it across login form, file list container, restore modal, preview modals, OnlyOffice modal, user dropdown menus, and the Upload / Folder Management cards for consistent rounded corners. - Update header button hover to use the same soft blue hover as other interactive elements and tune card shadows for light vs dark mode. - Adjust media preview modal background to a darker neutral and tweak `filePreview` panel background fallback (`--panel-bg` / `--bg-color`) for better dark mode contrast. - Style `.filr-menu` for both file + folder menus with max-height, scrolling, proper separators, and Material icons inheriting text color in light and dark themes. - Align the user dropdown menu hover/active styles with the new menu hover tokens (`--filr-row-hover-bg`, `--filr-row-outline-hover`) for a consistent interaction feel. --- ## Changes 11/13/2025 (v1.9.5) release(v1.9.5): harden folder tree DOM, add a11y to “Load more”, and guard folder paths - Replace innerHTML-based row construction in folderManager.js with safe DOM APIs (createElement, textContent, dataset). All user-derived strings now use textContent; only locally-generated SVG remains via innerHTML. - Add isSafeFolderPath() client-side guard; fail closed on suspicious paths before rendering clickable nodes. - “Load more” button rebuilt with proper a11y: - aria-label, optional aria-controls to the UL - aria-busy + disabled during fetch; restore state only if the node is still present (Node.isConnected). - Keep lazy tree + cursor pagination behavior intact; chevrons/icons continue to hydrate from server hints (hasSubfolders/nonEmpty) once available. - Addresses CodeQL XSS findings by removing unsafe HTML interpolation and avoiding HTML interpretation of extracted text. No breaking changes; security + UX polish on top of v1.9.4. --- ## Changes 11/13/2025 (v1.9.4) release(v1.9.4): lazy folder tree, cursor pagination, ACL-safe chevrons, and “Load more” (closes #66) **Big focus on folder management performance & UX for large libraries.** feat(folder-tree): - Lazy-load children on demand with cursor-based pagination (`nextCursor` + `limit`), including inline “Load more” row. - BFS-based initial selection: if user can’t view requested/default folder, auto-pick the first accessible folder (but stick to (Root) when user can view it). - Persisted expansion state across reloads; restore saved path and last opened folder; prevent navigation into locked folders (shows i18n toast instead). - Breadcrumb now respects ACL: clicking a locked crumb toggles expansion only (no navigation). - Live chevrons from server truth: `hasSubfolders` is computed server-side to avoid file count probes and show correct expanders (even when a direct child is unreadable). - Capabilities-driven toolbar enable/disable for create/move/rename/color/delete/share. - Color-carry on move/rename + expansion state migration so moved/renamed nodes keep colors and stay visible. - Root DnD honored only when viewable; structural locks disable dragging. perf(core): - New `FS.php` helpers: safe path resolution (`safeReal`), segment sanitization, symlink defense, ignore/skip lists, bounded child counting, `hasSubfolders`, and `hasReadableDescendant` (depth-limited). - Thin caching for child lists and counts, with targeted cache invalidation on move/rename/create/delete. - Bounded concurrency for folder count requests; short timeouts to keep UI snappy. api/model: - `FolderModel::listChildren(...)` now returns items shaped like: `{ name, locked, hasSubfolders, nonEmpty? }` - `nonEmpty` included only for unlocked nodes (prevents side-channel leakage). - Locked nodes are only returned when `hasReadableDescendant(...)` is true (preserves legacy “structural visibility without listing the entire tree” behavior). - `public/api/folder/listChildren.php` delegates to controller/model; `isEmpty.php` hardened; `capabilities.php` exposes `canView` (or derived) for fast checks. - Folder color endpoints gate results by ACL so users only see colors for folders they can at least “own-view”. ui/ux: - New “Load more” row (`
  • `) with dark-mode friendly ghost button styling; consistent padding, focus ring, hover state. - Locked folders render with padlock overlay and no DnD; improved contrast/spacing; icons/chevrons update live as children load. - i18n additions: `no_access`, `load_more`, `color_folder(_saved|_cleared)`, `please_select_valid_folder`, etc. - When a user has zero access anywhere, tree selects (Root) but shows `no_access` instead of “No files found”. security: - Stronger path traversal + symlink protections across folder APIs (all joins normalized, base-anchored). - Reduced metadata leakage by omitting `nonEmpty` for locked nodes and depth-limiting descendant checks. fixes: - Chevron visibility for unreadable intermediate nodes (e.g., “Files” shows a chevron when it contains a readable “Resources” descendant). - Refresh now honors the actively viewed folder (session/localStorage), not the first globally readable folder. chore: - CSS additions for locked state, tree rows, and dark-mode ghost buttons. - Minor code cleanups and comments across controller/model and JS tree logic. --- ## Changes 11/11/2025 (v1.9.3) release(v1.9.3): unify folder icons across tree & strip, add “paper” lines, live color sync, and vendor-aware release - UI / Icons - Replace Material icon in folder strip with shared `folderSVG()` and export it for reuse. Adds clipPaths, subtle gradients, and `shape-rendering: geometricPrecision` to eliminate the tiny seam. - Add ruled “paper” lines and blue handwriting dashes; CSS for `.paper-line` and `.paper-ink` included. - Match strokes between tree (24px) and strip (48px) so both look identical; round joins/caps to avoid nicks. - Polish folder strip layout & hover: tighter spacing, centered icon+label, improved wrapping. - Folder color & non-empty detection - Live color sync: after saving a color we dispatch `folderColorChanged`; strip repaints and tree refreshes. - Async strip icon: paint immediately, then flip to “paper” if the folder has contents. HSL helpers compute front/back/stroke shades. - FileList strip - Render subfolders with `` + name, wire context menu actions (move, color, share, etc.), and attach icons for each tile. - Exports & helpers - Export `openColorFolderModal(...)` and `openMoveFolderUI(...)` for the strip and toolbar; use `refreshFolderIcon(...)` after ops to keep icons current. - AppCore - Update file upload DnD relay hook to `#fileList` (id rename). - CSS tweaks - Bring tree icon stroke/paint rules in line with the strip, add scribble styles, and adjust margins/spacing. - CI/CD (release) - Build PHP dependencies during release: setup PHP 8.3 + Composer, cache downloads, install into `staging/vendor/`, exclude `vendor/` from placeholder checks, and ship artifact including `vendor/`. - Changelog highlights - Sharper, seam-free folder SVGs shared across tree & strip, with paper lines + handwriting accents. - Real-time folder color propagation between views. - Folder strip switched to SVG tiles with better layout + context actions. - Release pipeline now produces a ready-to-run zip that includes `vendor/`. --- ## Changes 11/10/2025 (v1.9.2) release(v1.9.2): Upload modal + DnD relay from file list (with robust synthetic-drop fallback) - New “Upload file(s)” action in Create menu: - Adds `
  • ` to the dropdown. - Opens a reusable Upload modal that *moves* the existing #uploadCard into the modal (no cloning = no lost listeners). - ESC / backdrop / “×” close support; focus jumps to “Choose Files” for fast keyboard flow. - Drag & Drop from file list → Upload: - Drag-over on #fileListContainer shows drop-hover and auto-opens the Upload modal after a short hover. - On drop, waits until the modal’s #uploadDropArea exists, then relays the drop to it. - Uses a resilient relay: attempts to attach DataTransfer to a synthetic event; falls back to a stash. - Synthetic drop fallback: - Introduces window.__pendingDropData (cleared after use). - upload.js now reads e.dataTransfer || window.__pendingDropData to accept relayed drops across browsers. - Implementation details: - fileActions.js: adds openUploadModal()/closeUploadModal() with a hidden sentinel to return #uploadCard to its original place on close. - appCore.js: imports openUploadModal, adds waitFor() helper, and wires dragover/leave/drop logic for the relay. - index.html: adds Upload option to the Create menu and the #uploadModal scaffold. - UX/Safety: - Defensive checks if modal/card isn’t present. - No backend/API changes; CSRF/auth unchanged. Files touched: public/js/upload.js, public/js/fileActions.js, public/js/appCore.js, public/index.html --- ## Changes 11/9/2025 (v1.9.1) release(v1.9.1): customizable folder colors + live preview; improved tree persistence; accent button; manual sync script ### Highlights v1.9.1 - 🎨 Per-folder colors with live SVG preview and consistent styling in light/dark modes. - 📄 Folder icons auto-refresh when contents change (no full page reload). - 🧭 Drag-and-drop breadcrumb fallback for folder→folder moves. - 🛠️ Safer upgrade helper script to rsync app files without touching data. - feat(colors): add per-folder color customization - New endpoints: GET /api/folder/getFolderColors.php and POST /api/folder/saveFolderColor.php - AuthZ: reuse canRename for “customize folder”, validate hex, and write atomically to metadata/folder_colors.json. - Read endpoint filters map by ACL::canRead before returning to the user. - Frontend: load/apply colors to tree rows; persist on move/rename; API helpers saveFolderColor/getFolderColors. - feat(ui): color-picker modal with live SVG folder preview - Shows preview that updates as you pick; supports Save/Reset; protects against accidental toggle clicks. - feat(controls): “Color folder” button in Folder Management card - New `.btn-color-folder` with accent palette (#008CB4), hover/active/focus states, dark-mode tuning; event wiring gated by caps. - i18n: add strings for color UI (color_folder, choose_color, reset_default, save_color, folder_color_saved, folder_color_cleared). - ux(tree): make expansion state more predictable across refreshes - `expandTreePath(path, {force,persist,includeLeaf})` with persistence; keep ancestors expanded; add click-suppression guard. - ux(layout): center the folder-actions toolbar; remove left padding hacks; normalize icon sizing. - chore(ops): add scripts/manual-sync.sh (safe rsync update path, preserves data dirs and public/.htaccess). --- ## Changes 11/9/2025 (v1.9.0) release(v1.9.0): folder tree UX overhaul, fast ACL-aware counts, and .htaccess hardening feat(ui): modern folder tree - New crisp folder SVG with clear paper insert; unified yellow/orange palette for light & dark - Proper ARIA tree semantics (role=treeitem, aria-expanded), cleaner chevrons, better alignment - Breadcrumb tweaks (› separators), hover/selected polish - Prime icons locally, then confirm via counts for accurate “empty vs non-empty” feat(api): add /api/folder/isEmpty.php via controller/model - public/api/folder/isEmpty.php delegates to FolderController::stats() - FolderModel::countVisible() enforces ACL, path safety, and short-circuits after first entry - Releases PHP session lock early to avoid parallel-request pileups perf: cap concurrent “isEmpty” requests + timeouts - Small concurrency limiter + fetch timeouts - In-memory result & inflight caches for fewer network hits fix(state): preserve user expand/collapse choices - Respect saved folderTreeState; don’t auto-expand unopened nodes - Only show ancestors for visibility when navigating (no unwanted persists) security: tighten .htaccess while enabling WebDAV - Deny direct PHP except /api/*.php, /api.php, and /webdav.php - AcceptPathInfo On; keep path-aware dotfile denial refactor: move count logic to model; thin controller action chore(css): add unified “folder tree” block with variables (sizes, gaps, colors) Files touched: FolderModel.php, FolderController.php, public/js/folderManager.js, public/css/styles.css, public/api/folder/isEmpty.php (new), public/.htaccess --- ## Changes 11/8/2025 (v1.8.13) release(v1.8.13): ui(dnd): stabilize zones, lock sidebar width, and keep header dock in sync - dnd: fix disappearing/overlapping cards when moving between sidebar/top; return to origin on failed drop - layout: placeCardInZone now live-updates top layout, sidebar visibility, and toggle icon - toggle/collapse: move ALL cards to header on collapse, restore saved layout on expand; keep icon state synced; add body.sidebar-hidden for proper file list expansion; emit `zones:collapsed-changed` - header dock: show dock whenever icons exist (and on collapse); hide when empty - responsive: enforceResponsiveZones also updates toggle icon; stash/restore behavior unchanged - sidebar: hard-lock width to 350px (CSS) and remove runtime 280px minWidth; add placeholder when empty to make dropping back easy - CSS: right-align header dock buttons, centered “Drop Zone” label, sensible min-height; dark-mode safe - refactor: small renames/ordering; remove redundant z-index on toggle; minor formatting --- ## Changes 11/8/2025 (v1.8.12) release(v1.8.12): auth UI & DnD polish — show OIDC, auto-SSO, right-aligned header icons - auth (public/js/main.js) - Robust login options: tolerate key variants (disableFormLogin/disable_form_login, etc.). - Correctly show/hide wrapper + individual methods (form/OIDC/basic). - Auto-SSO when OIDC is the only enabled method; add opt-out with `?noauto=1`. - Minor cleanup (SW register catch spacing). - drag & drop (public/js/dragAndDrop.js) - Reworked zones model: Sidebar / Top (left/right) / Header (icon+modal). - Persist user layout with `userZonesSnapshot.v2` and responsive stash for small screens. - Live UI sync: toggle icon (`material-icons`) updates immediately after moves. - Smarter small-screen behavior: lift sidebar cards ephemerally; restore only what belonged to sidebar. - Cleaner header icon modal plumbing; remove legacy/dead code. - styles (public/css/styles.css) - Header drop zone fills remaining space and right-aligns its icons. UX: - OIDC button reliably appears when form/basic are disabled. - If OIDC is the sole method, users are taken straight to the provider (unless `?noauto=1`). - Header icons sit with the other header actions (right-aligned), and the toggle icon reflects layout changes instantly. --- ## Changes 11/8/2025 (v1.8.11) release(v1.8.11): fix(oidc): always send PKCE (S256) and treat empty secret as public client - Force PKCE via setCodeChallengeMethod('S256') so Authelia’s public-client policy is satisfied. - Convert empty OIDC client secret to null to correctly signal a public client. - Optional commented hook to switch token endpoint auth to client_secret_post if desired. - OIDC_TOKEN_ENDPOINT_AUTH_METHOD added to config.php --- ## Changes 11/8/2025 (v1.8.10) release(v1.8.10): theme-aware media modal, stronger file drag-and-drop, unified progress color, and favicon overhaul UI/UX — Media modal - Add fixed top bar to avoid filename/controls overlapping native media chrome; keep hover-on-stage look. - Show a Material icon by file type next to the filename (image/video/pdf/code/arch/txt, with fallback). - Restore “X” behavior and make hover theme-aware (red pill + white ‘X’ in light, red pill + black ‘X’ in dark). Video/Image controls - Top-right action icons use theme-aware styles and align with the filename row. - Prev/Next paddles remain high-contrast and vertically centered within the stage. Progress badges (list & modal) - Standardize “in-progress” to darker orange (#ea580c) for better contrast in light/dark; update CSS and list badge rendering. Drag & drop - Support multi-select drags with a clean JSON payload + text fallback; nicer drag ghost. - More resilient drops: accept data-dest-folder, safer JSON parse, early guards, and better toasts. - POST move now sends Accept header, uses global CSRF, and refreshes the active view on success. Editor & ONLYOFFICE - Full-screen OO modal with preconnect, optional hidden warm-up to reduce first-open latency, and live theme sync. - CodeMirror path: fix theme/mode setters (use `cm`) and tighten dynamic mode loading. Assets & polish - Swap in full favicon stack (SVG + PNG 512/32/16 + ICO) and set theme-color; cache-busted via `{{APP_QVER}}`. - Refresh `logo.svg` (accessibility, cleaner handles/gradients). Also added: refreshed resource images and new logo sizes (logo-16, logo-32, logo-64, etc.) for crisper favicons and embeds. --- ## Changes 11/7/2025 (v1.8.9) release(v1.8.9): fix(oidc, admin): first-save Client ID/Secret (closes #64) - adminPanel.js: - Masked inputs without a saved value now start with data-replace="1". - handleSave() now sends oidc.clientId / oidc.clientSecret on first save (no longer requires clicking “Replace” first). --- ## Changes 11/7/2025 (v1.8.8) release(v1.8.8): background ZIP jobs w/ tokenized download + in‑modal progress bar; robust finalize; janitor cleanup — closes #60 **Summary** This release moves ZIP creation off the request thread into a **background worker** and switches the client to a **queue > poll > tokenized GET** download flow. It fixes large multi‑GB ZIP failures caused by request timeouts or cross‑device renames, and provides a resilient in‑modal progress experience. It also adds a 6‑hour janitor for temporary tokens/logs. **Backend** changes: - Add **zip status** endpoint that returns progress and readiness, and **tokenized download** endpoint for one‑shot downloads. - Update `FileController::downloadZip()` to enqueue a job and return `{ token, statusUrl, downloadUrl }` instead of streaming a blob in the POST response. - Implement `spawnZipWorker()` to find a working PHP CLI, set `TMPDIR` on the same filesystem as the final ZIP, spawn with `nohup`, and persist PID/log metadata for diagnostics. - Serve finished ZIPs via `downloadZipFile()` with strict token/user checks and streaming headers; unlink the ZIP after successful read. New **Worker**: - New `src/cli/zip_worker.php` builds the archive in the background. - Writes progress fields (`pct`, `filesDone`, `filesTotal`, `bytesDone`, `bytesTotal`, `current`, `phase`, `startedAt`, `finalizeAt`) to the per‑token JSON. - During **finalizing**, publishes `selectedFiles`/`selectedBytes` and clears incremental counters to avoid the confusing “N/N files” display before `close()` returns. - Adds a **janitor**: purge `.tokens/*.json` and `.logs/WORKER-*.log` older than **6 hours** on each run. New **API/Status Payload**: - `zipStatus()` exposes `ready` (derived from `status=done` + existing `zipPath`), and includes `startedAt`/`finalizeAt` for UI timers. - Returns a prebuilt `downloadUrl` for a direct handoff once the ZIP is ready. **Frontend (UX)** changes: - Replace blob POST download with **enqueue → poll → tokenized GET** flow. - Native `` bar now renders **inside the modal** (no overflow/jitter). - Shows determinate **0–98%** during enumeration, then **locks at 100%** with **“Finalizing… mm:ss — N files, ~Size”** until the download starts. - Modal closes just before download; UI resets for the next operation. Added **CSS**: - Ensure the progress modal has a minimum height and hidden overflow; ellipsize the status line to prevent scrollbars. **Why this closes #60**? - ZIP creation no longer depends on the request lifetime (avoids proxy/Apache timeouts). - Temporary files and final ZIP are created on the **same filesystem** (prevents “rename temp file failed” during `ZipArchive::close()`). - Users get continuous, truthful feedback for large multi‑GB archives. Additional **Notes** - Download tokens are **one‑shot** and are deleted after the GET completes. - Temporary artifacts (`META_DIR/ziptmp/.tokens`, `.logs`, and old ZIPs) are cleaned up automatically (≥6h). --- ## Changes 11/5/2025 (v1.8.7) release(v1.8.7): fix(zip-download): stream clean ZIP response and purge stale temp archives - FileController::downloadZip - Remove _jsonStart/_jsonEnd and JSON wrappers; send a pure binary ZIP - Close session locks, disable gzip/output buffering, set Content-Length when known - Stream in 1MiB chunks; proper HTTP codes/messages on errors - Unlink the temp ZIP after successful send - Preserves all auth/ACL/ownership checks - FileModel::createZipArchive - Purge META_DIR/ziptmp/download-*.zip older than 6h before creating a new ZIP Result: fixes “failed to fetch / load failed” with fetch>blob flow and reduces leftover tmp ZIPs. --- ## Changes 11/4/2025 (v1.8.6) release(v1.8.6): fix large ZIP downloads + safer extract; close #60 - Zip creation - Write archives to META_DIR/ziptmp (on large/writable disk) instead of system tmp. - Auto-create ziptmp (0775) and verify writability. - Free-space sanity check (~files total +5% +20MB); clearer error on low space. - Normalize/validate folder segments; include only regular files. - set_time_limit(0); use CREATE|OVERWRITE; improved error handling. - Zip extraction - New: stamp metadata for files in nested subfolders (per-folder metadata.json). - Skip hidden “dot” paths (files/dirs with any segment starting with “.”) by default via SKIP_DOTFILES_ON_EXTRACT=true; only extract allow-listed entries. - Hardenings: zip-slip guard, reject symlinks (external_attributes), zip-bomb limits (MAX_UNZIP_BYTES default 200GiB, MAX_UNZIP_FILES default 20k). - Persist metadata for all touched folders; keep extractedFiles list for top-level names. Ops note: ensure /var/www/metadata/ziptmp exists & is writable (or mount META_DIR to a large volume). Closes #60. --- ## Changes 11/4/2025 (v1.8.5) release(v1.8.5): ci: reduce pre-run delay to 2-min and add missing `needs: delay`, final test - No change release just testing --- ## Changes 11/4/2025 (v1.8.4) release(v1.8.4): ci: add 3-min pre-run delay to avoid workflow_run races - No change release just testing --- ## Changes 11/4/2025 (v1.8.3) release(v1.8.3): feat(mobile+ci): harden Capacitor switcher & make release-on-version robust - switcher.js: allow running inside Capacitor; remove innerHTML usage; build nodes safely; normalize/strip creds from URLs; add withParam() for ?frapp=1; drop inline handlers; clamp rename length; minor UX polish. - CI: cancel superseded runs per ref; checkout triggering commit (workflow_run head_sha); improve APP_VERSION parsing; point tag to checked-out commit; add recent-tag debug. --- ## Changes 11/4/2025 (v1.8.2) release(v1.8.2): media progress tracking + watched badges; PWA scaffolding; mobile switcher (closes #37) - **Highlights** - Video: auto-save playback progress and mark “Watched”, with resume-on-open and inline status chips on list/gallery. - Mobile: introduced FileRise Mobile (Capacitor) companion repo + in-app server switcher and PWA bits. - **Details** - API (new): - POST /api/media/updateProgress.php — persist per-user progress (seconds/duration/completed). - GET /api/media/getProgress.php — fetch per-file progress. - GET /api/media/getViewedMap.php — folder map for badges. - **Frontend (media):** - Video previews now resume from last position, periodically save progress, and mark completed on end, with toasts. - Added status badges (“Watched” / %-complete) in table & gallery; CSS polish for badges. - Badges render during list/gallery refresh; safer filename wrapping for badge injection. - **Mobile & PWA:** - New in-app server switcher (Capacitor-aware) loaded only in app/standalone contexts. - Service Worker + manifest added (root scope via /public/sw.js; worker body in /js/pwa/sw.js; manifest icons). - main.js conditionally imports the mobile switcher and registers the SW on web origins only. - **Notes** - Companion repo: **filerise-mobile** (Capacitor app shell) created for iOS/Android distribution. - No breaking changes expected; endpoints are additive. Closes #37. --- ## Changes 11/3/2025 (V1.8.1) release(v1.8.1): fix(security,onlyoffice): sanitize DS origin; safe api.js/iframe probes; better UX placeholder - Add ONLYOFFICE URL sanitizers: - getTrustedDocsOrigin(): enforce http/https, strip creds, normalize to origin - buildOnlyOfficeApiUrl(): construct fixed /web-apps/.../api.js via URL() - Probe hardening (addresses CodeQL js/xss-through-dom): - ooProbeScript/ooProbeFrame now use sanitized origins and fixed paths - optional CSP nonce support for injected script - optional iframe sandbox; robust cleanup/timeout handling - CSP helper now renders lines based on validated origin (fallback to raw for visibility) - Admin UI UX: placeholder switched to HTTPS example (`https://docs.example.com`) - Comments added to justify safety to static analyzers Files: public/js/adminPanel.js Refs: #37 --- ## Changes 11/3/2025 (v1.8.0) release(v1.8.0): feat(onlyoffice): first-class ONLYOFFICE integration (view/edit), admin UI, API, CSP helpers Refs #37 — implements ONLYOFFICE integration suggested in the discussion; video progress saving will be tracked separately. Adds secure, ACL-aware ONLYOFFICE support throughout FileRise: - **Backend / API** - New OnlyOfficeController with supported extensions (doc/xls/ppt/pdf etc.), status/config endpoints, and signed download flow. - New endpoints: - GET /api/onlyoffice/status.php — reports availability + supported exts. - GET /api/onlyoffice/config.php — returns DocEditor config (signed URLs, callback). - GET /api/onlyoffice/signed-download.php — serves signed blobs to DS. - Effective config/overrides: env/constant wins; supports docsOrigin, publicOrigin, and jwtSecret; status gated on presence of origin+secret. - Public origin resolution (BASE_URL/proxy aware) for absolute URLs. - **Admin config / UI** - AdminPanel gets a new “ONLYOFFICE” section with Enable toggle, Document Server Origin, masked JWT Secret, and “Replace” control. - Built-in connection tester (status, secret presence, callback ping, api.js load, iframe embed) + CSP helper (Apache & Nginx snippets) - **Frontend integration** - fileEditor detects OO capability via /api/onlyoffice/status and routes supported types to the DocEditor; loads DocsAPI dynamically. - editFile() short-circuits to openOnlyOffice when applicable; includes live dark/light theme sync where supported. - fileListView pulls status once on load to drive UI decisions (e.g., editing affordances). - **AdminModel / config** - Adds onlyoffice {enabled, docsOrigin, publicOrigin} defaults and update path, with jwtSecret persisted (kept unless explicitly replaced). - Optional constants in config.php to override and debug. - **Security & UX notes** - Editor access remains ACL-checked (read/edit) and uses absolute, signed URLs surfaced via controller. - Admin UI never echoes secrets; “Replace” toggles explicit updates only. - CSP helper makes it straightforward to permit api.js + iframe + XHR to your DS. - **Docs/Styling** - Minor CSS touch-ups around hover states and modal layout. --- ## Changes 11/2/2025 (v1.7.5) release(v1.7.5): CSP hardening, API-backed previews, flicker-free theming, cache tuning & deploy script (closes #50) release(v1.7.5): retrigger CI bump (no code changes) release(v1.7.5): retrigger CI bump ensure up to date ### Security/headers - Tighten CSP: pin the inline pre-theme snippet with a script-src SHA-256 and keep everything else on 'self'. - Improve cache policy for versioned assets: force 1y + immutable and add s-maxage for CDNs; also avoid HSTS redirects on local/dev hosts. ### Previews & editor - Remove hardcoded `/uploads/` paths; always build preview URLs via the API (respects UPLOAD_DIR/ACL). - Use the API URL for gallery prev/next and file-menu “Preview” to fix 404s on custom storage roots. - Editor now probes size safely (HEAD → Range 0-0 fallback) before fetching, then fetches with credentials. ### Login, theming & UX polish - Pre-theme inline boot sets `dark-mode` + background early; swap to `[hidden]`/`unhide()` instead of inline `display:none`. - Add full-screen loading overlay with quick fade and proper color-scheme; prevent white/black flash on theme flips. - Refactor app/login reveal flow in `main.js` (`revealAppAndHideOverlay`, `authed` path, setup wizard). ### HTML/CSS & perf - Make Bootstrap/Styles/Roboto critical (plain ``); keep fonts as true preloads; modulepreload app entry. - Export a `__CSS_PROMISE__` from `defer-css.js` for sites that still promote preloads. - Header logo marked `fetchpriority="high"` for faster first paint. - Normalize dark-mode selectors to `.dark-mode` scope (admin panel, etc.). ### Manual Deploy script - Add `scripts/filerise-deploy.sh`: idempotent rsync-based deploy with writable dirs preserved, optional Composer install, and PHP-FPM/Apache reloads. ### Notes - If you change the inline pre-theme snippet, update the CSP hash accordingly. --- ## Changes 10/31/2025 (v1.7.4) release(v1.7.4): login hint replace toast + fix unauth boot main.js - Added isDemoHost() and showLoginTip(message). - In the unauth branch, call showLoginTip('Please log in to continue'). - Removed ensureToastReady() + showToast('please_log_in_to_continue') in the unauth path to avoid loading toast/DOM utils before auth. --- ## Changes 10/31/2025 (v1.7.3) release(v1.7.3): lightweight boot pipeline, dramatically faster first paint, deduped /api writes, sturdier uploads/auth ### 🎃 Highlights (advantages) 👻 🦇 - ⚡ Faster, cleaner boot: a lightweight **main.js** decides auth/setup before painting, avoids flicker, and wires modules exactly once. - ♻️ Fewer duplicate actions: **request coalescer** dedupes POST/PUT/PATCH/DELETE to /api/* . - ✅ Truthy UX: global **toast bridge** queues early toasts and normalizes misleading “not found/already exists” messages after success. - 🔐 Smoother auth: CSRF priming/rotation + **TOTP step-up detection** across JSON & redirect paths; “Welcome back, `user`” toast once per tab. - 🌓 Polished UI: **dark-mode persistence with system fallback**, live siteConfig title application, higher-z modals, drag auto-scroll. - 🚀 Faster first paint & interactions: defer CodeMirror/Fuse/Resumable, promote preloaded CSS, and coalesce duplicate requests → snappier UI. - 🧭 Admin polish: live header title preview, masked OIDC fields with **Replace** flow, and a **read-only Sponsors/Donations** section. - 🧱 Safer & cache-smarter: opinionated .htaccess (CSP/HSTS/MIME/compression) + `?v={{APP_QVER}}` for versioned immutable assets. ### Core bootstrap (main.js) overhaul - Early **toast bridge** (queues until domUtils is ready); expose `window.__FR_TOAST_FILTER__` for centralized rewrites/suppression. - **Result guard + request coalescer** wrapping `fetch`: - Dedupes same-origin `/api/*` mutating requests for ~800ms using a stable key (method + path + normalized body). - Tracks “last OK” JSON (`success|status|result=ok`) to suppress false-negative error toasts after success. - **Boot orchestrator** with hard guards: - `__FR_FLAGS` (`booted`, `initialized`, `wired.*`, `bootPromise`, `entryStarted`) to prevent double init/leaks. - **No-flicker login**: resolve `checkAuth()` + `setup` before showing UI; show login only when truly unauthenticated. - **Heavy boot** for authed users: load i18n, `appCore.loadCsrfToken/initializeApp`, first file list, then light UI wiring. - **Auth flow**: - `primeCsrf()` + `` management; persist token in localStorage. - **TOTP** detection via header (`X-TOTP-Required`) & JSON (`totp_required` / `TOTP_REQUIRED`); calls `openTOTPLoginModal()`. - **Welcome toast** once per tab via `sessionStorage.__fr_welcomed`. - **UI/UX niceties**: - `applySiteConfig()` updates header title & login method visibility on both login & authed screens. - Dark-mode persistence with system fallback, proper a11y labels/icons. - Create dropdown/menu wiring with capture-phase outside-click + ESC close; modal cancel safeties. - Lift modals above cards (z-index), **drag auto-scroll** near viewport edges. - Dispatch legacy `DOMContentLoaded`/`load` **once** (supports older inline handlers). - Username label refresh for existing `.user-name-label` without injecting new DOM. ### Performance & UX changes - CSS/first paint: - Preload Bootstrap & app CSS; promote at DOMContentLoaded; keep inline CSS minimal. - Add `width/height/decoding/fetchpriority` to logo to reduce layout shift. - Search/editor/uploads: - **fileListView.js**: lazy-load Fuse with instant substring fallback; `warmUpSearch()` hook. - **fileEditor.js**: lazy-load CodeMirror core/theme/modes; start plain then upgrade; guard very large files gracefully. - **upload.js**: lazy-load Resumable; resilient init; background warm-up; smarter addFile/submit; clearer toasts. - Toast/UX: - Install early toast bridge; queue & normalize messages; neutral “Done.” when server returns misleading errors after success. ### Correctness: uploads, paths, ACLs - **UploadController/UploadModel**: normalize folders via `ACL::normalizeFolder(rawurldecode())`; stricter segment checks; consistent base paths; safer metadata writes; proper chunk presence/merge & temp cleanup. ### Auth hardening & resilience - **auth.js/main.js/appCore.js**: CSRF rotate/retry (JSON then x-www-form-urlencoded fallback); robust login handling; fewer misleading error toasts. - **AuthController**: OIDC username fallback to `email` or `sub` when `preferred_username` missing. ### Admin panel - **adminPanel.js**: - Live header title preview (instant update without reload). - Masked OIDC client fields with **Replace** button; saved-value hints; only send secrets when replacing. - **New “Sponsor / Donations” section (read-only)**: - GitHub Sponsors → `https://github.com/sponsors/error311` - Ko-fi → `https://ko-fi.com/error311` - Includes **Copy** and **Open** buttons; values are fixed. - **AdminController**: boolean for `oidc.hasClientId/hasClientSecret` to drive masked inputs. ### Security & caching (.htaccess) - Consolidated security headers (CSP, CORP, HSTS on HTTPS), MIME types, compression (Brotli/Deflate), TRACE disable. - Caching rules: - HTML/version.js: no-cache; unversioned JS/CSS: 1h; unversioned static: 7d; **versioned assets `?v=`: 1y `immutable`**. - **config.php**: remove duplicate runtime headers (now via Apache) to avoid proxy/CDN conflicts. ### Upgrade notes - No schema changes. - Ensure Apache modules (`headers`, `rewrite`, `brotli`/`deflate`) are available for the new .htaccess rules (fallbacks included). - Versioned assets mean users shouldn’t need a hard refresh; `?v={{APP_QVER}}` busts caches automatically. --- ## Changes 10/29/2025 (v1.7.0 & v1.7.1 & v1.7.2) release(v1.7.0): asset cache-busting pipeline, public siteConfig cache, JS core split, and caching/security polish ### ✨ Features - Public, non-sensitive site config cache: - Add `AdminModel::buildPublicSubset()` and `writeSiteConfig()` to write `USERS_DIR/siteConfig.json`. - New endpoint `public/api/siteConfig.php` + `UserController::siteConfig()` to serve the public subset (regenerates if stale). - Frontend now reads `/api/siteConfig.php` (safe subset) instead of `/api/admin/getConfig.php`. - Frontend module versioning: - Replace all module imports with `?v={{APP_QVER}}` query param so the release/Docker stamper can pin exact versions. - Add `scripts/stamp-assets.sh` to stamp `?v=` and `{{APP_VER}}/{{APP_QVER}}` in **staging** for ZIP/Docker builds. ### 🧩 Refactors - Extract shared boot/bootstrap logic into `public/js/appCore.js`: - CSRF helpers (`setCsrfToken`, `getCsrfToken`, `loadCsrfToken`) - `initializeApp()`, `triggerLogout()` - Keep `main.js` lean; wrap global `fetch` once to append/rotate CSRF. - Update imports across JS modules to use versioned module URLs. ### 🚀 Performance - Aggressive, safe caching for versioned assets: - `.htaccess`: `?v=…` ⇒ `Cache-Control: max-age=31536000, immutable`. - Unversioned JS/CSS short cache (1h), other static (7d). - Eliminate duplicate `main.js` loads and tighten CodeMirror mode loading. ### 🔒 Security / Hardening - `.htaccess`: - Conditional HSTS only when HTTPS, add CORP and X-Permitted-Cross-Domain-Policies. - CSP kept strict for modules, workers, blobs. - Admin config exposure reduced to a curated subset in `siteConfig.json`. ### 🧪 CI/CD / Release - **FileRise repo** - `sync-changelog.yml`: keep `public/js/version.js` as source-of-truth only (no repo-wide stamping). - `release-on-version.yml`: build **stamped** ZIP from a staging copy via `scripts/stamp-assets.sh`, verify placeholders removed, attach checksum. - **filerise-docker repo** - Read `VERSION`, checkout app to `app/`, run stamper inside build context before `docker buildx`, tag `latest` and `:${VERSION}`. ### 🔧 Defaults - Sample/admin config defaults now set `disableBasicAuth: true` (safer default). Existing installations keep their current setting. ### 📂 Notable file changes - `src/models/AdminModel.php` (+public subset +atomic write) - `src/controllers/UserController.php` (+siteConfig action) - `public/api/siteConfig.php` (new) - `public/js/appCore.js` (new), `public/js/main.js` (slim, uses appCore) - Many `public/js/*.js` import paths updated to `?v={{APP_QVER}}` - `public/.htaccess` (caching & headers) - `scripts/stamp-assets.sh` (new) ### ⚠️ Upgrade notes - Ensure `USERS_DIR` is writable by web server for `siteConfig.json`. - Proxies/edge caches: the new `?v=` scheme enables long-lived immutable caching; purge is automatic on version bump. - If you previously read admin config directly on the client, it now reads `/api/siteConfig.php`. ### Additional changes/fixes for release - `release-on-version.yml` - normalize line endings (strip CRLF) - stamp-assets.sh don’t rely on the exec; invoke via bash release(v1.7.2): harden asset stamping & CI verification ### build(stamper) - Rewrite scripts/stamp-assets.sh to be repo-agnostic and macOS/Windows friendly: - Drop reliance on git ls-files/mapfile; use find + null-delimited loops - Normalize CRLF to LF for all web assets before stamping - Stamp ?v= in HTML/CSS/PHP and {{APP_VER}} everywhere - Normalize any ".mjs|.js?v=..." occurrences inside JS (ESM imports/strings) - Force-write public/js/version.js from VER (source of truth in stamped output) - Print touched counts and fail fast if any {{APP_QVER}}|{{APP_VER}} remain --- ## Changes 10/28/2025 (v1.6.11) release(v1.6.11) fix(ui/dragAndDrop) restore floating zones toggle click action Re-add the click handler to toggle `zonesCollapsed` so the header “sidebarToggleFloating” button actually expands/collapses the zones again. This regressed in v1.6.10 during auth-gating refactor. Refs: #regression #ux chore(codeql): move config to repo root for default setup - Relocate .github/codeql/codeql-config.yml to codeql-config.yml so GitHub default code scanning picks it up - Keep paths: public/js, api - Keep ignores: public/vendor/**, public/css/vendor/**, public/fonts/**, public/**/*.min.{js,css}, public/**/*.map --- ## Changes 10/28/2025 (v1.6.10) release(v1.6.10): self-host ReDoc, gate sidebar toggle on auth, and enrich release workflow - Vendor ReDoc and add MIT license file under public/vendor/redoc/; switch api.php to local bundle to satisfy CSP (script-src 'self'). - main.js: add/remove body.authenticated on login/logout so UI can reflect auth state. - dragAndDrop.js: only render sidebarToggleFloating when authenticated; stop event bubbling, keep dark-mode styles. - sync-changelog.yml: also stamp ?v= in PHP templates (public/**/*.php). - release-on-version.yml: build zip first, compute SHA-256, assemble release body with latest CHANGELOG snippet, “Full Changelog” compare link, and attach .sha256 alongside the zip. - THIRD_PARTY.md: document ReDoc vendoring and rationale. Refs: #security #csp #release --- ## Changes 10/27/2025 (v1.6.9) release(v1.6.9): feat(core) localize assets, harden headers, and speed up load - index.html: drop all CDNs in favor of local /vendor assets - add versioned cache-busting query (?v=…) on CSS/JS - wire version.js for APP_VERSION and numeric cache key - public/vendor/: add pinned copies of: - bootstrap 4.5.2, codemirror 5.65.5 (+ themes/modes), dompurify 2.4.0, fuse.js 6.6.2, resumable.js 1.1.0 - fonts: add self-hosted Material Icons + Roboto (latin + latin-ext) with vendor CSS (material-icons.css, roboto.css) - fileEditor.js: load CodeMirror modes from local vendor with ?v=APP_VERSION_NUM, keep timeout/plain-text fallback, no SRI (same-origin) - dragAndDrop.js: nudge zonesToggle 65px left to sit tighter to the logo - styles.css: prune/organize rules and add small utility classes; move 3P font CSS to /css/vendor/ - .htaccess: security + performance overhaul - Content-Security-Policy: default-src 'self'; img-src include data: and blob: - version-aware caching: HTML/version.js = no-cache; assets with ?v= = 1y immutable - correct MIME for fonts/SVG; enable Brotli/Gzip (if available) - X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS, Permissions-Policy - disable TRACE; deny dotfiles; prevent directory listing - .gitattributes: mark vendor/minified as linguist-vendored, treat assets as binary in diffs, exclude CI/resources from source archives - docs/licensing: - add licenses/ and THIRD_PARTY.md with upstream licenses/attribution - README: add “License & Credits” section with components and licenses - CI: (sync-changelog) stamp asset cache-busters to the numeric release (e.g. ?v=1.6.9) and write window.APP_VERSION in version.js before Docker build perf: site loads significantly faster with local assets + compression + long-lived caching security: CSP, strict headers, and same-origin assets reduce XSS/SRI/CORS risk Refs: #performance #security --- ## Changes 10/25/2025 (v1.6.8) release(v1.6.8): fix(ui) prevent Extract/Create flash on refresh; remember last folder - Seed `currentFolder` from `localStorage.lastOpenedFolder` (fallback to "root") - Stop eager `loadFileList('root')` on boot; defer initial load to resolved folder - Hide capability-gated actions by default (`#extractZipBtn`, `#createBtn`) to avoid pre-auth flash - Eliminates transient root state when reloading inside a subfolder User-visible: refreshing a non-root folder no longer flashes Root items or privileged buttons; app resumes in the last opened folder. --- ## Changes 10/25/2025 (v1.6.7) release(v1.6.7): Folder Move feature, stable DnD persistence, safer uploads, and ACL/UI polish ### 📂 Folder Move (new major feature) **Drag & Drop to move folder, use context menu or Move Folder button** - Added **Move Folder** support across backend and UI. - New API endpoint: `public/api/folder/moveFolder.php` - Controller and ACL updates to validate scope, ownership, and permissions. - Non-admins can only move within folders they own. - `ACL::renameTree()` re-keys all subtree ACLs on folder rename/move. - Introduced new capabilities: - `canMoveFolder` - `canMove` (UI alias for backward compatibility) - New “Move Folder” button + modal in the UI with full i18n strings (`i18n.js`). - Action button styling and tooltip consistency for all folder actions. ### 🧱 Drag & Drop / Layout Improvements - Fixed **random sidebar → top zone jumps** on refresh. - Cards/panels now **persist exactly where you placed them** (`userZonesSnapshot`) — no unwanted repositioning unless the window is resized below the small-screen threshold. - Added hysteresis around the 1205 px breakpoint to prevent flicker when resizing. - Eliminated the 50 px “ghost” gutter with `clampSidebarWhenEmpty()`: - Sidebar no longer reserves space when collapsed or empty. - Temporarily “unclamps” during drag so drop targets remain accurate and full-width. - Removed forced 800 px height on drag highlight; uses natural flex layout now. - General layout polish — smoother transitions when toggling *Hide/Show Panels*. ### ☁️ Uploads & UX - Stronger folder sanitization and safer base-path handling. - Fixed subfolder creation when uploading directories (now builds under correct parent). - Improved chunk error handling and metadata key correctness. - Clearer success/failure toasts and accurate filename display from server responses. ### 🔐 Permissions / ACL - Simplified file rename checks — now rely solely on granular `ACL::canRename()`. - Updated capability lists to include move/rename operations consistently. ### 🌐 UI / i18n Enhancements - Added i18n strings for new “Move Folder” prompts, modals, and tooltips. - Minor UI consistency tweaks: button alignment, focus states, reduced-motion support. --- ## Changes 10/24/2025 (v1.6.6) release(v1.6.6): header-mounted toggle, dark-mode polish, persistent layout, and ACL fix - dragAndDrop: mount zones toggle beside header logo (absolute, non-scrolling); stop click propagation so it doesn’t trigger the logo link; theme-aware styling - live updates via MutationObserver; snapshot card locations on drop and restore on load (prevents sidebar reset); guard first-run defaults with `layoutDefaultApplied_v1`; small/medium layout tweaks & refactors. - CSS: switch toggle icon to CSS variable (`--toggle-icon-color`) with dark-mode override; remove hardcoded `!important`. - API (capabilities.php): remove unused `disableUpload` flag from `canUpload` and flags payload to resolve undefined variable warning. --- ## Changes 10/24/2025 (v1.6.5) release(v1.6.5): fix PHP warning and upload-flag check in capabilities.php - Fix undefined variable: use $disableUpload consistently - Harden flag read: (bool)($perms['disableUpload'] ?? false) - Prevents warning and ensures Upload capability is computed correctly --- ## Changes 10/24/2025 (v1.6.4) release(v1.6.4): runtime version injection + CI bump/sync; caching tweaks - Add public/js/version.js (default "dev") and load it before main.js. - adminPanel.js: replace hard-coded string with `window.APP_VERSION || "dev"`. - public/.htaccess: add no-cache for js/version.js - GitHub Actions: replace sync job with “Bump version and sync Changelog to Docker Repo”. - Parse commit msg `release(vX.Y.Z)` -> set step output `version`. - Write `public/js/version.js` with `window.APP_VERSION = ''`. - Commit/push version.js if changed. - Mirror CHANGELOG.md to filerise-docker and write a VERSION file with ``. - Guard all steps with `if: steps.ver.outputs.version != ''` to no-op on non-release commits. This wires the UI version label to CI, keeps dev builds showing “dev”, and feeds the Docker repo with CHANGELOG + VERSION for builds. --- ## Changes 10/24/2025 (v1.6.3) release(v1.6.3): drag/drop card persistence, admin UX fixes, and docs (closes #58) Drag & Drop - Upload/Folder Management Cards layout - Persist panel locations across refresh; snapshot + restore when collapsing/expanding. - Unified “zones” toggle; header-icon mode no longer loses card state. - Responsive: auto-move sidebar cards to top on small screens; restore on resize. - Better top-zone placeholder/cleanup during drag; tighter header modal sizing. - Safer order saving + deterministic placement for upload/folder cards. Admin Panel – Folder Access - Fix: newly created folders now appear without a full page refresh (cache-busted `getFolderList`). - Show admin users in the list with full access pre-applied and inputs disabled (read-only). - Skip sending updates for admins when saving grants. - “Folder” column now has its own horizontal scrollbar so long names / “Inherited from …” are never cut off. Admin Panel – User Permissions (flags) - Show admins (marked as Admin) with all switches disabled; exclude from save payload. - Clarified helper text (account-level vs per-folder). UI/Styling - Added `.folder-cell` scroller in ACL table; improved dark-mode scrollbar/thumb. Docs - README edits: - Clarified PUID/PGID mapping and host/NAS ownership requirements for mounted volumes. - Environment variables section added - CHOWN_ON_START additional details - Admin details - Upgrade section added - 💖 Sponsor FileRise section added --- ## Changes 10/23/2025 (v1.6.2) feat(i18n,auth): add Simplified Chinese (zh-CN) and expose in User Panel - Add zh-CN locale to i18n.js with full key set. - Introduce chinese_simplified label key across locales. - Added some missing labels - Update language selector mapping to include zh-CN (English/Spanish/French/German/简体中文). - Wire zh-CN into Auth/User Panel (authModals) language dropdown. - Fallback-safe rendering for language names when a key is missing. ui: fix “Change Password” button sizing in User Panel - Keep consistent padding and font size for cleaner layout --- ## Changes 10/23/2025 (v1.6.1) feat(ui): unified zone toggle + polished interactions for sidebar/top cards - Add floating toggle button styling (hover lift, press, focus ring, ripple) for #zonesToggleFloating and #sidebarToggleFloating (CSS). - Ensure icons are visible and centered; enforce consistent sizing/color. - Introduce unified “zones collapsed” state persisted via `localStorage.zonesCollapsed`. - Update dragAndDrop.js to: - manage a single floating toggle for both Sidebar and Top Zone - keep toggle visible when cards are in Top Zone; hide only when both cards are in Header - rotate icon 90° when both cards are in Top Zone and panels are open - respect collapsed state during DnD flows and on load - preserve original DnD behaviors and saved orders (sidebar/header) - Minor layout/visibility fixes during drag (clear temp heights; honor collapsed). Notes: - No breaking API changes; existing `sidebarOrder` / `headerOrder` continue to work. - New key: `zonesCollapsed` (string '0'/'1') controls visibility of Sidebar + Top Zone. UX: - Floating toggle feels more “material”: subtle hover elevation, press feedback, focus ring, and click ripple to restore the prior interactive feel. - Icons remain legible on white (explicit color set), centered in the circular button. --- ## Changes 10/22/2025 (v1.6.0) feat(acl): granular per-folder permissions + stricter gates; WebDAV & UI aligned - Add granular ACL buckets: create, upload, edit, rename, copy, move, delete, extract, share_file, share_folder - Implement ACL::canX helpers and expand upsert/explicit APIs (preserve read_own) - Enforce “write no longer implies read” in canRead; use granular gates for write-ish ops - WebDAV: use canDelete for DELETE, canUpload/canEdit + disableUpload for PUT; enforce ownership on overwrite - Folder create: require Manage/Owner on parent; normalize paths; seed ACL; rollback on failure - FileController: refactor copy/move/rename/delete/extract to granular gates + folder-scope checks + own-only ownership enforcement - Capabilities API: compute effective actions with scope + readOnly/disableUpload; protect root - Admin Panel (v1.6.0): new Folder Access editor with granular caps, inheritance hints, bulk toggles, and UX validations - getFileList: keep root visible but inert for users without visibility; apply own-only filtering server-side - Bump version to v1.6.0 --- ## 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 feat(editor): make modal non-blocking; add SRI + timeout for CodeMirror mode loads - Build the editor modal immediately and wire close (✖, Close button, and Esc) before any async work, so the UI is always dismissible. - Restore MODE_URL and add normalizeModeName() to resolve aliases (text/html → htmlmixed, php → application/x-httpd-php). - Add SRI for each lazily loaded mode (MODE_SRI) and apply integrity/crossOrigin on script tags; switch to async and improved error messages. - Introduce MODE_LOAD_TIMEOUT_MS=2500 and Promise.race() to init in text/plain if a mode is slow; auto-upgrade to the real mode once it arrives. - Graceful fallback: if CodeMirror core isn’t present, keep textarea, enable Save, and proceed. - Minor UX: disable Save until the editor is ready, support theme toggling, better resize handling, and font size controls without blocking. Security: Locks CDN mode scripts with SRI. --- ## 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 `