diff --git a/CHANGELOG.md b/CHANGELOG.md index aecb165..97a7764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,51 +1,6 @@ # Changelog -## Unreleased - -### Changed (BREAKING — webroot reorganisation) - -- **`public/` is now THE webroot.** Source code, the SQLite DB, configs, - composer artifacts, the editor's PHP source, theme PHP source and CLI - scripts all live OUTSIDE the webroot now. Defense-in-depth is no longer - load-bearing: a misconfigured Caddy/nginx that lacks deny rules can no - longer expose `data/imanager.db`, `.git/`, `vendor/`, `boot/`, or - `bin/` simply because those paths are not below the document root. - Server admins point `root` at `/public/` and that's it. -- **Themes split into two halves.** - `themes//` (PHP source, includes only) + - `public/themes//` (static assets — css, fonts, images, scripts). - The `site/` wrapper directory is gone; `site/themes/` becomes - `themes/`, `site/modules/` becomes `modules/`. -- **Editor static assets move to `public/editor-assets/`.** The editor - theme's PHP files (`template.php`, `header.php`, `summary.php`) stay in - `editor/theme/` — included only by `editor/index.php`, never web-served. - `editor/lang/` stays in `editor/`. -- **User uploads move to `public/uploads/`** (was `data/uploads-2.0/`). - Inside the webroot, served by the web server directly, no alias rules - needed. The image rendering layer (`Frontend\ImageUrlBuilder`) is - backward-compatible with both the old `data/uploads/` (1.x-migrated) - and `data/uploads-2.0/` (2.0 pre-public-webroot) prefixes — existing - items in the live DB keep rendering without a path migration. -- **New asset-URL helpers**: - `Site::themeAssetUrl()`, `Site::editorAssetUrl()`, `Editor::assetUrl()`. - All bundled-theme + editor-theme templates are converted. Custom - themes built against 2.0 should switch to the helpers — see - [`docs/themes.md`](docs/themes.md). -- **`public/.htaccess`** replaces the root `.htaccess`. The deny list - collapses to dotfiles only, because the source/data directories no - longer live inside the webroot. The `editor/`-specific rewrite is - gone too — every request goes through `public/index.php`, which - handles admin-path delegation in PHP. -- **Demo image rewired**: `nginx.conf` `root` is `/var/www/scriptor/public`, - the `/data/` alias + deny rules are dropped (data/ is outside the - webroot now), `/uploads/` location added with long-cache headers. - -See [`docs/refactor-public-webroot.md`](docs/refactor-public-webroot.md) -for the full migration plan including server-config templates for -Apache, Caddy, nginx and PHP's built-in server, and the -allow/deny test matrix. - -## 2.0.0 — Ground-up rewrite on iManager 2.0 +## 2.0.0 (2026-05-16) — Ground-up rewrite on iManager 2.0 Scriptor 2.0 replaces the embedded 1.x `imanager/` library with the external [iManager 2.0][imanager] package and rebuilds Frontend + @@ -79,6 +34,11 @@ dispatch, PSR-16 caching). The legacy 1.x flat-file storage is gone. - **`Scriptor\Boot\Frontend\*`** — `Site`, `Page`, `PageRepository`, `Sanitizer`, `ImageUrlBuilder` — public-site renderer that bundled themes consume through the standard `$site` surface. +- **Asset-URL helpers**: `Site::themeAssetUrl()`, + `Site::editorAssetUrl()`, `Editor::assetUrl()` — used by every + bundled template after the public/-webroot split. Custom themes + built against 2.0 should call these instead of hard-coding paths; + see [`docs/themes.md`](docs/themes.md). ### Fixed @@ -92,17 +52,62 @@ dispatch, PSR-16 caching). The legacy 1.x flat-file storage is gone. `Site::buildPageUrl()` already tolerates cyclic data via a visited-set guard, so the editor now matches the frontend's defensive shape. +- **Trust `X-Forwarded-Proto` for site URL scheme.** Behind a + TLS-terminating reverse proxy (nginx-proxy on the Hetzner demo, + Caddy as a forwarding proxy), `Frontend\Site::detectSiteUrl()` and + `Editor\Editor::detectSiteUrl()` no longer hard-code `http` from + `$_SERVER['HTTPS']` — they read `X-Forwarded-Proto` first. Fixes + mixed-content errors when the site is reverse-proxied. +- **Demo seed restore recreates the FTS5 index.** The first-boot + entrypoint re-applies the FTS schema and runs `imanager fts:rebuild` + after dropping in the SQL dump, so editor password saves (which + trigger an FTS update) don't crash with "no such table: items_fts" + against snapshots captured by iManager <2.0.1. + +### Changed (BREAKING — webroot reorganisation) + +- **`public/` is now THE webroot.** Source code, the SQLite DB, configs, + composer artifacts, the editor's PHP source, theme PHP source and CLI + scripts all live OUTSIDE the webroot now. Defense-in-depth is no longer + load-bearing: a misconfigured Caddy/nginx that lacks deny rules can no + longer expose `data/imanager.db`, `.git/`, `vendor/`, `boot/`, or + `bin/` simply because those paths are not below the document root. + Server admins point `root` at `/public/` and that's it. +- **Themes split into two halves.** + `themes//` (PHP source, includes only) + + `public/themes//` (static assets — css, fonts, images, scripts). + The `site/` wrapper directory is gone; `site/themes/` becomes + `themes/`, `site/modules/` becomes `modules/`. +- **Editor static assets move to `public/editor-assets/`.** The editor + theme's PHP files (`template.php`, `header.php`, `summary.php`) stay in + `editor/theme/` — included only by `editor/index.php`, never web-served. + `editor/lang/` stays in `editor/`. +- **User uploads move to `public/uploads/`** (was `data/uploads-2.0/`). + Inside the webroot, served by the web server directly, no alias rules + needed. The image rendering layer (`Frontend\ImageUrlBuilder`) is + backward-compatible with both the old `data/uploads/` (1.x-migrated) + and `data/uploads-2.0/` (2.0 pre-public-webroot) prefixes — existing + items in the live DB keep rendering without a path migration. +- **`public/.htaccess`** replaces the root `.htaccess`. The deny list + collapses to dotfiles only, because the source/data directories no + longer live inside the webroot. The `editor/`-specific rewrite is + gone too — every request goes through `public/index.php`, which + handles admin-path delegation in PHP. + +See [`docs/refactor-public-webroot.md`](docs/refactor-public-webroot.md) +for the full migration plan including server-config templates for +Apache, Caddy, nginx and PHP's built-in server, and the +allow/deny test matrix. ### Changed -- **Composer dep on iManager: switched from path-repo + dev to the - Packagist stable release.** With `bigins/imanager 2.0.0` published - on Packagist, the `composer.json` no longer declares the - `../imanager` path repository or the `minimum-stability: dev` / - `prefer-stable: true` pair, and the constraint is plain `^2.0` - instead of `2.0.x-dev`. `composer install` now works against a - fresh clone without any sibling iManager checkout — and against - the public Packagist mirror, not the local working tree. +- **Composer dep on iManager: Packagist `^2.0` (locked to 2.0.1).** + With `bigins/imanager` published on Packagist, `composer.json` no + longer declares the `../imanager` path repository or the + `minimum-stability: dev` / `prefer-stable: true` pair. The lock + pins **2.0.1**, which fixes a `dump`-skips-FTS5 bug that broke + seed-restore round-trips. `composer install` now works against a + fresh clone without any sibling iManager checkout. - **Demo image: drop the composer-rewrite workaround.** With `bigins/imanager` resolvable from Packagist directly, `docker/Dockerfile` no longer needs the `composer-rewrite.php` @@ -124,6 +129,43 @@ dispatch, PSR-16 caching). The legacy 1.x flat-file storage is gone. - **`scriptor-config.php` admin_path comment** no longer claims the user must update `.htaccess` after changing `admin_path`. The 2.0 PHP-level delegation in `index.php` makes that obsolete. +- **Domain rebrand: `scriptor-cms.info` → `scriptor-cms.dev`.** All + in-repo references updated; new banner at + `docs/images/scriptor-banner-2.0.png`. +- **Demo image rewired** for the public/-webroot layout: + `nginx.conf` `root` is `/var/www/scriptor/public`, the `/data/` + alias + deny rules are dropped (`data/` is outside the webroot + now), `/uploads/` location added with long-cache headers. +- **Demo image: two-image stack.** A tiny `nginx:alpine` web + image (`docker/Dockerfile.web`) bakes `public/` so + `SCRIPT_FILENAME` paths resolve identically in both containers + and the front isn't shadowed by a single shared volume. +- **Demo seed mirrors `https://scriptor.cms` content** instead of + the previous synthetic programmatic seed. Snapshot captured via + `imanager dump`. Ships with `admin / gT5nLazzyBob` — change + before exposing. +- **Docker volume layout split**: the pre-refactor single + `scriptor-app` volume mounted code AND state, which silently + shadowed image updates — `git pull && up -d --build` didn't + propagate code changes without `down -v` (which wiped state). + Now `scriptor-data` (DB, cache, logs, settings) and + `scriptor-uploads` (FileStorage) hold state; code lives in the + images, rebuilt on every `--build`. + +### Security + +- **Hardened response headers** on every response: tight + `Content-Security-Policy` (no `script-src 'unsafe-inline'`, + allow-lists `cdn.jsdelivr.net` for the basic theme's UIkit), + `X-Content-Type-Options: nosniff`, `X-Frame-Options: SAMEORIGIN`, + `Referrer-Policy: strict-origin-when-cross-origin`, + `Permissions-Policy` opting out of + geolocation/camera/microphone/payment/FLoC. `server_tokens off` + + `expose_php=Off` — the nginx version no longer leaks and + `X-Powered-By` is gone. +- **Editor `IMSESSID` session cookie** ships with `Secure` + (X-Forwarded-Proto-aware, so local HTTP dev still works), + `HttpOnly`, `SameSite=Lax`. ### Removed