From 8946915bfe99c355e87df6511e6b253f302ed2b9 Mon Sep 17 00:00:00 2001 From: Geoff Moore <84508186+GeoffMoore1979@users.noreply.github.com> Date: Thu, 24 Sep 2026 17:47:34 +0100 Subject: [PATCH] Add Users, media library, navigation menus from the scan, new-page wizard and deleted-page recovery Users (Tools > Users) - Everyone can update their display name, email and password; administrators can add, edit, invite (one-time link), block and delete accounts. - Accounts in config.local.php stay locked to config (the main administrator); CMS accounts live in data/users.json. Sign-in is by login name. - Roles are now editor and administrator (publisher is an alias of editor). - Account protection: password hashes only (12-72 characters), administrator password confirmation for sensitive actions, rate-limited failures, hashed single-use invite tokens, self-lockout guards, sessions of blocked/deleted users end on the next request, every account event audited without secrets. - dataDirectory can move data outside the web root; the dashboard recommends it. Media library - Upload images, documents, video and audio, sorted into four categories by extension. - Extension allow-list; executables, scripts, HTML/SVG, archives, legacy and macro Office files refused; content sniffing; files containing code refused; PDFs with scripts refused; Office/OpenDocument packages inspected for macros and embedded objects. - Media library button in the editor inserts an image, document link, video or audio. Navigation menus, pages and interface - The site scan detects primary/secondary navigation and seeds Navigation Menus; menus can be renamed, edited and deleted but not created by the CMS; a scan button finds new navigation. - New page wizard (template, name, navigation group) in the Pages dialogue; new pages stay private drafts until published; pages can be used as templates. - Deleted pages can be recovered from the Dashboard. - Full-width top bar with the user at the top right, device icons, consistent buttons. Tests and docs updated (tests/run.php, README, ARCHITECTURE, DEVELOPMENT, CHANGELOG). Co-Authored-By: Claude Sonnet 5 --- README.md | 209 +++++++++--- cms/config.local.php.example | 3 + cms/config.php | 3 +- cms/css/editor.css | 137 +++++--- cms/image_upload.php | 67 ++-- cms/index.php | 128 +++++-- cms/js/cms.js | 527 ++++++++++++++++++++++++++--- cms/login/index.php | 57 +++- cms/src/NeoCMS/Authentication.php | 31 +- cms/src/NeoCMS/CMSController.php | 541 +++++++++++++++++++++++++++--- cms/src/NeoCMS/ContentDom.php | 79 ++++- cms/src/NeoCMS/MediaTypes.php | 299 +++++++++++++++++ cms/src/NeoCMS/SiteAnalyser.php | 97 +++++- cms/src/NeoCMS/UserStore.php | 430 ++++++++++++++++++++++++ cms/welcome.html | 18 +- docs/ARCHITECTURE.md | 130 ++++++- docs/CHANGELOG.md | 91 +++++ docs/DEVELOPMENT.md | 45 ++- tests/run.php | 424 ++++++++++++++++++++++- uploads/.htaccess | 10 +- 20 files changed, 3001 insertions(+), 325 deletions(-) create mode 100644 cms/src/NeoCMS/MediaTypes.php create mode 100644 cms/src/NeoCMS/UserStore.php create mode 100644 docs/CHANGELOG.md diff --git a/README.md b/README.md index 7f38781..7e49a4c 100644 --- a/README.md +++ b/README.md @@ -23,19 +23,29 @@ Further technical documentation: * Seamless Integration: Simply add the CMS to any existing static website. Just assign a special class to the elements you want to make editable, and you’re all set. * Consistent Layouts: NeoCMS supports page templates to keep your layouts neat and uniform across all pages. -* Drafts and Publishing: Editors can save drafts without changing the public page. Publishers can publish immediately or - schedule a publication. -* Revision History: Every changed or deleted page receives a timestamped filesystem snapshot that publishers can restore. -* Page Management: Search, create, duplicate, rename, and delete editable HTML pages, including pages in subdirectories. -* Media Library: Browse uploaded images, reuse them, maintain alternative text, see usage counts, and remove files. +* Drafts and Publishing: Clicking Save in the editor keeps the change as a private draft without touching the public page. + Editors can then publish immediately or schedule a publication. +* Revision History: Every changed or deleted page receives a timestamped filesystem snapshot that editors can restore, and + deleted pages can be recovered from the Dashboard. +* Page Management: Search, duplicate, rename, and delete editable HTML pages, including pages in subdirectories. The New page section of the Pages dialogue is a + three-step wizard (template, page name, navigation group); the new page stays a private draft until it is published. Any page can + be offered as a template with Create Template. +* Media Library: Upload images, documents, video, and audio; they are sorted into Imagery, Documents, Video, and Audio by file + extension. Reuse them from the editor's Media library button, maintain alternative text or link text, see usage counts, and + remove files. Executables and files containing code are refused. * SEO Settings: Edit the page title, description, canonical URL, Open Graph image, and robots indexing setting. * Shared Content: Mark content with `data-neo-shared="name"` and update matching regions across the site. -* Navigation Menus: Build ordered and nested navigation markup and insert it into an editable region. -* Responsive Preview: Preview the current page at desktop, tablet, and mobile widths. +* Navigation Menus: The site scan finds each page's primary and secondary navigation and pre-fills the menus. Edit, rename, or + delete a menu and the change is applied to every page that uses it. Menus are created by the web developer's markup, not by the + CMS. +* Responsive Preview: Preview the current page at desktop, tablet, and mobile widths using the device icons in the top bar. * Accessibility Checks: Check common authoring problems such as missing alt text, empty links, heading jumps, missing labels, and absent page metadata before publishing. -* Roles and Activity: Use editor, publisher, and administrator roles. The dashboard displays drafts, schedules, system - problems, and recent activity. +* Site Scan: Analyse every managed page and the media library, then make pages editable in one step. The scan + finds content areas, images, navigation, broken local references, and missing SEO tags, and adds the markers NeoCMS needs. +* Users and Roles: Everyone can update their display name, email address, and password in Tools > Users. Administrators can add, + edit, invite, block, and delete accounts. Two roles, Editor and Administrator, are described on that screen. +* Activity: The dashboard displays drafts, schedules, deleted pages, system problems, and recent activity. ## Installation Guide @@ -46,8 +56,15 @@ To install NeoCMS: * Copy `cms/config.local.php.example` to `cms/config.local.php`, add password hashes, and assign roles. * Update the elements you want to make editable by adding the configured editable class. It is `editable` by default. * Confirm that PHP may write to the managed HTML files, `cms/data/`, `cms/logs/`, and `uploads/`. +* **Live sites:** create a folder outside the web root (for example `/var/neocms-data`), make it writable by PHP, and set + `'dataDirectory' => '/var/neocms-data'` in `cms/config.local.php`. It must be an absolute path. Without this, accounts, drafts, + and revisions live in `cms/data/`, which is protected only by the supplied `.htaccess`. Administrators see a Dashboard + recommendation until the data folder is outside the web root. Audit logs remain in `cms/logs/`, also protected by `.htaccess`. * Visit `/cms/`, log in, and begin editing. +The site may also live in a subfolder (for example `http://localhost/mysite/`): the URL prefix is detected automatically. See +[Subfolder installs](#subfolder-installs). + That’s it! You’re up and running. ## Configuration @@ -57,17 +74,21 @@ Tracked defaults live in `cms/config.php`. Deployment credentials and overrides | Setting | Type | Purpose | | --- | --- | --- | -| `authentication` | array | Maps usernames to `password_hash()` values; plaintext credentials are rejected. | -| `roles` | array | Maps usernames to `editor`, `publisher`, or `administrator`. | +| `authentication` | array | Maps the main administrator usernames to `password_hash()` values; plaintext credentials are rejected. These accounts are managed only here. | +| `roles` | array | Maps those usernames to `editor` or `administrator` (`publisher` is accepted as an alias of `editor`). | | `security` | array | Configures session expiry, login throttling, request limits, storage quotas, and audit-log retention. | -| `uploads` | array | Configures image size, dimension, file-count, and aggregate-storage limits. | +| `uploads` | array | Configures the per-file size limit (all media types), image dimension, file-count, and aggregate-storage limits. | | `audit` | boolean | Enables daily activity logs under `cms/logs/`. | | `skipWelcomePage` | boolean | Opens the public root instead of the built-in guide after login. | | `showFullUrl` | boolean | Displays the current page path in the toolbar. | | `editableClass` | string | Selects the single CSS class used to identify editable regions. | -`dataDirectory` is an internal override used by the integration suite and specialised deployments. Normal installations -should allow NeoCMS to use `cms/data/`. +`dataDirectory` is the absolute path of the folder holding accounts (`users.json`), drafts, revisions, schedules, and menus. It +defaults to `cms/data/`; on a live site, point it at a folder outside the web root (see the Installation Guide) so those files +can never be served. The folder is created on first use if PHP may create it, and the CLI scheduler uses the same setting. + +`basePath` (URL prefix of the site root, such as `/mysite`) and `siteRoot` (the folder containing `cms/`) are detected +automatically and only need setting behind a path-rewriting proxy. ### Editable Class @@ -95,27 +116,52 @@ created pages are immediately discoverable by the page picker. ### Users and Roles -Passwords must be generated with `password_hash()` and stored under `authentication` in `cms/config.local.php`. Assign the -same username a role under `roles`: +There are two kinds of account: + +* **Config accounts** are the main administrators. Generate a hash with `password_hash()` and store it under `authentication` in + `cms/config.local.php`, with a role under `roles`. They can be changed only in that file (in Tools > Users they are listed as + "Config"; only their display name and email can be set from the CMS). +* **CMS accounts** are created in **Tools > Users** and stored in `cms/data/users.json`. ```php 'authentication' => [ - 'author' => '$2y$10$...', - 'publisher' => '$2y$10$...', + 'admin' => '$2y$10$...', ], 'roles' => [ - 'author' => 'editor', - 'publisher' => 'publisher', + 'admin' => 'administrator', ], ``` -* `editor`: edit content, save drafts, and upload media. -* `publisher`: editor permissions plus immediate and scheduled publishing and revision restoration. -* `administrator`: publisher permissions plus page, media, shared-content, and menu management. +There are two roles: -Users without an explicit valid role receive `editor`, the least powerful role. Account removal, password-hash changes, -and role changes affect active sessions on their next request. Sessions expire after 30 minutes of inactivity and 12 hours -in total by default. +| Role | Can do | +| --- | --- | +| `editor` | Edit content, save drafts, upload images, publish or schedule pages, and restore revisions or deleted pages. Cannot change the site structure or manage users. | +| `administrator` | Everything an editor can, plus creating new pages, duplicate, rename and delete pages, templates, navigation menus, shared content, site scan, deleting media, and managing users. | + +The former `publisher` role is now part of `editor`; existing `publisher` assignments are treated as `editor`. Users without an +explicit valid role receive `editor`, the least powerful role. + +#### The Users screen + +* **My account** (every user): see your login name (set by an administrator), change the display name, the email address (needs the + current password), and the password (current, new, confirmation; CMS accounts only). You sign in with your login name and + password; the email address is contact information only. +* **Roles**: a description of each role, with your own marked. +* **User accounts** (administrators): add an account with a password, edit an account (name, email, role, optional password + reset), invite someone, block or unblock, or delete. Add, edit, invite, block, and delete ask for the administrator's own + password. You cannot block, delete, or demote yourself, and config accounts cannot be changed here. +* **Invitations** produce a one-time link that is shown once and expires after 7 days. The invitee opens it and chooses their own + password. No email is sent by the CMS. + +#### Account protection + +Passwords are 12 to 72 characters and are stored only as hashes. Invite tokens are stored only as hashes and work once. Secrets +never appear in API responses or the activity log. Repeated wrong passwords are rate limited, every account event is recorded in +the activity feed and audit log, and blocking, deleting, changing a role, or changing a password affects that user's sessions on +their next request. `data/.htaccess` denies web access to `users.json`. + +Sessions expire after 30 minutes of inactivity and 12 hours in total by default. When HTTPS terminates at a trusted reverse proxy, set `'cookieSecure' => true` beneath `security` in the local override. This keeps the session cookie marked Secure even when PHP receives the proxy's internal HTTP request. @@ -156,7 +202,12 @@ of its shared regions. ### Navigation Menus -Menu items use one line each in this format: +Menus come from your site's own navigation. The **site scan** finds each page's `