From e9b79242fd786e1fae85cd9499189110a397be67 Mon Sep 17 00:00:00 2001 From: John Cardinal Date: Sun, 25 Oct 2026 14:39:00 -0700 Subject: [PATCH] case 4579 - Windows installers: program folder no longer writable by all users Both installers drop users-modify from the program folder (and local-postgres in the single-user installer) and run icacls to remove the Users group's own grants (by SID) from the program folder after copying files, so upgrades over 8.2.4 lose them too. The data folder keeps users-modify and config.json stays readable by local users (the running account is not known at install time); both documented in the single-user and LAN install pages. Changelog updated. F2 fixed (write access), the rest accepted. Deferred: report on a missing record fails with a generic error. Co-Authored-By: Claude Opus 5.5 --- devdocs/modernization/NET10-PORT.md | 3 ++- devdocs/modernization/SECURITY-REVIEW.md | 4 ++-- dist/install/windows/x64/lan.iss | 7 ++++++- dist/install/windows/x64/standalone.iss | 7 +++++-- docs/8.0/ayanova/docs/changelog.md | 1 + docs/8.0/ayanova/docs/ops-install-windows-lan.md | 1 + docs/8.0/ayanova/docs/ops-install-windows-single.md | 1 + 7 files changed, 18 insertions(+), 6 deletions(-) diff --git a/devdocs/modernization/NET10-PORT.md b/devdocs/modernization/NET10-PORT.md index 077d8217..b9572bcc 100644 --- a/devdocs/modernization/NET10-PORT.md +++ b/devdocs/modernization/NET10-PORT.md @@ -224,7 +224,7 @@ John's "next release" cases for AyaNova (exported 2026-10-24). Each is its own s | 4628 | Deleting a work order tied to a CSR gives a raw server error | 1, bug | | 4623 | Docs: migration, what is erased and what is kept | 1, docs | | 4602 | Logo upload UI: hide Upload and Delete until usable | 1, client | -| 4579 | Windows installer modify rights: only the folders AyaNova writes to, only for the account it runs as (includes F2) | 00. **Next (plan proposed 2026-10-24, awaiting John's approval):** remove `Permissions: users-modify` from `{app}` (both installers) and `{app}\local-postgres` (standalone); after install run `icacls` to remove the Users group's granted rights (by SID `*S-1-5-32-545`, not the localised name) from `{app}` (and `local-postgres` with `/T`) so upgraded installs lose them too; keep `users-modify` on `{commonappdata}yanova` (the running account is unknown at install time), recorded as accepted with a manual note. Nothing writes to `{app}` since 8.3.0 (data paths, signing key, report browser all under ProgramData; the launcher writes only there). Proof on John's sandbox: fresh install and upgrade over 8.2.4 of each installer, login, report render, backup, attachment, standalone PostgreSQL start/stop, `icacls` shows no Users (M) on `{app}`. Changelog: "Windows: the installers no longer give all local users write access to the AyaNova program folder." | +| 4579 | Windows installer modify rights: only the folders AyaNova writes to, only for the account it runs as (includes F2) | 00. **Done** (both installers: no `users-modify` on `{app}` or `local-postgres`; `icacls "{app}" /remove:g *S-1-5-32-545 /T /C /Q` after install removes the Users grant on upgrades too; data folder keeps `users-modify` and `config.json` stays readable by local users, accepted by John and documented in the single-user and LAN install pages. Sandbox: single-user fresh and upgrade over 8.2.4, LAN upgrade; Users modify entries under `{app}` 4632/1281 before, 0 after; trial, login, attachment, backup, report render after upgrade. Found on the way: the downloaded "8.2.4" LAN installer installs server 8.2.3, which fails its integrity check on a new PostgreSQL 18 database (E1030); gone once the 8.3.0 LAN installer is published) | | 4690 | .NET 10 port umbrella case | 1 | Sockeye cases (exported 2026-10-24): 4710 (also in the table above) and 4681. 4681 predates the review: a trial request with a made-up address made Sockeye send its verification email, which bounced to support@ (Fastmail notice, 2026-10-16). @@ -273,6 +273,7 @@ Found during the port, out of scope. One line each. - Linux desktop manual (`ops-install-linux-desktop.md`), pre-existing, same in 8.2.4: `sudo mkdir ~/.ayanova-data` creates the folder in the user's home, but `sudo ./AyaNova` runs as root, so `AYANOVA_DATA_PATH` `~/.ayanova-data` resolves to `/root/.ayanova-data` and the user's folder is never used (data, logs and backups end up under `/root`). Found in the 8.3.0 desktop zip test. Fix the manual (absolute data path, or not running as root) after the release - **Own case after the port (John):** the subscription server setup script is hard-coded in `biz-subscription-server.vue`, so every change needs a new Sockeye client build. Make it editable without a rebuild - **Improvement, own case after the port (John to create):** bring back logging of JavaScript error details from report page console errors, as Sockeye's port did. AyaNova logs only `ERROR: {message text}`; the per-argument detail (`arg instanceof Error ? arg.message : arg`) is commented out at `biz/ReportBiz.cs:873-876` since case 4586, because `IJSHandle.ExecutionContext` was removed. Sockeye 8.1.0 (`server/biz/ReportBiz.cs:575`) evaluates on the handle instead: `args.Message.Args.Select(arg => arg.EvaluateFunctionAsync("(arg) => arg instanceof Error ? arg.message : arg"))`, which also needs the console handler to be `async` again +- Pre-existing, same in 8.2.4 (found in the 4579 sandbox test, John: Deferred): rendering a report for a record that does not exist (e.g. work order ids 1 and 2 in a trial without sample data) fails the job with a generic `ArgumentNullException` ("Value cannot be null. (Parameter 'o')") from `JObject.FromObject` in `WorkOrderBiz.GetReportData` (`WorkOrderBiz.cs:1030`), instead of skipping the missing record or saying it is not found. Other object types' `GetReportData` likely do the same ## Log diff --git a/devdocs/modernization/SECURITY-REVIEW.md b/devdocs/modernization/SECURITY-REVIEW.md index 37f9a99c..dc541eb0 100644 --- a/devdocs/modernization/SECURITY-REVIEW.md +++ b/devdocs/modernization/SECURITY-REVIEW.md @@ -218,7 +218,7 @@ take the next free number; a fixed or accepted finding keeps its ID and changes | F9 | Medium | **fixed in case 4725** | Default SuperUser password (by design for trials), and an anonymous route that says whether it is still set | | F36 | Low | **accepted** for standalone and LAN; hosted: `sockeye-client` script to bind 127.0.0.1 | AyaNova listens on all interfaces on plain HTTP port 7575 in every template; hosted droplets are protected by a cloud firewall | | F37 | Low | accepted (John) | Standalone PostgreSQL accepts any local connection without a password (`trust`) | -| F2 | Medium | confirmed (code) | Windows installers give all local users modify rights on the program and data folders, `config.json` included | +| F2 | Medium | **fixed in case 4579** (write access); read access to `config.json` and write access to the data folder accepted and documented | Windows installers give all local users modify rights on the program and data folders, `config.json` included | | F7 | Low | **fixed in case 4725** | Password change or reset does not end existing sessions, and makes the download key non-expiring | | F8 | Low | **fixed in case 4725** | Latest-token check skipped for any URL ending in `/auth` or `notify/hello` | | F4 | Low | **fixed in cases 4712 and 4723** | Any logged-in user can send an in-app notification to any user | @@ -863,7 +863,7 @@ attachments, logs). Any local Windows user can therefore replace program files t the user who starts AyaNova or as the IIS application pool, and can read the database files and backups. Matters on shared or terminal-server machines. The program-folder permission originally let the report browser download beside the app; since 8.3.0 it downloads under -the data folder, so `{app}` may no longer need it. To confirm in pass 10. **Pass 10:** confirmed from `lan.iss` and `standalone.iss`. `config.json`, with the database password and the JWT secret, is installed in `{app}`, so any local user can read those secrets and change the configuration or the program files; standalone also grants `users-modify` on `{app}\local-postgres` (the PostgreSQL binaries) and the database folder. Fix: drop `users-modify` from `{app}` and `local-postgres`; keep write access only where the running account needs it (logs, backups, temp, attachments, report browser), granted to that account or to Administrators rather than all Users; give `config.json` an ACL for Administrators and the service account. +the data folder, so `{app}` may no longer need it. To confirm in pass 10. **Pass 10:** confirmed from `lan.iss` and `standalone.iss`. `config.json`, with the database password and the JWT secret, is installed in `{app}`, so any local user can read those secrets and change the configuration or the program files; standalone also grants `users-modify` on `{app}\local-postgres` (the PostgreSQL binaries) and the database folder. Fix: drop `users-modify` from `{app}` and `local-postgres`; keep write access only where the running account needs it (logs, backups, temp, attachments, report browser), granted to that account or to Administrators rather than all Users; give `config.json` an ACL for Administrators and the service account. **Fixed in case 4579 (2026-10-25):** both installers no longer grant `users-modify` on `{app}` or `{app}\local-postgres`, and after copying files run `icacls "{app}" /remove:g *S-1-5-32-545 /T /C /Q` (Users group by SID), which also removes the old grant on upgrades; inherited read rights from Program Files stay. Nothing writes to `{app}` since 8.3.0. Proved in Windows Sandbox: single-user fresh install and upgrade over 8.2.4, LAN upgrade over the downloaded LAN installer: 4632 (single) and 1281 (LAN) Users modify entries before, 0 after; login, trial, attachment, backup and report render work after the upgrade. **Accepted (John, 2026-10-25), documented in the single-user and LAN install pages:** the data folder keeps `users-modify` and `config.json` (database password) stays readable by local users, because AyaNova runs as whichever user starts it (or the IIS app pool) and that account is not known at install time. ### F3 `notify/direct-smtp` open to every logged-in user diff --git a/dist/install/windows/x64/lan.iss b/dist/install/windows/x64/lan.iss index f4b2c987..d2433df6 100644 --- a/dist/install/windows/x64/lan.iss +++ b/dist/install/windows/x64/lan.iss @@ -43,7 +43,6 @@ Source: "C:\data\code\raven\dist\assets\open-ayanova-app.bat"; DestDir: "{app}"; [Dirs] -Name: "{app}";Permissions: users-modify; Name: "{commonappdata}\ayanova";Permissions: users-modify; Name: "{commonappdata}\ayanova\logs";Permissions: users-modify; @@ -52,6 +51,12 @@ Name: "{commonappdata}\ayanova\logs";Permissions: users-modify; Type: filesandordirs; Name: "{app}\Chrome" Type: filesandordirs; Name: "{app}\ChromeHeadlessShell" +[Run] +; case 4579: the program folder is no longer writable by all local users (nothing writes there, data is under +; {commonappdata}\ayanova). Upgrades over 8.2.4 or older still carry the old grant, so remove the Users group's own +; rights (by SID, the group name is translated) from the program folder and everything in it; inherited read rights stay +Filename: "{sys}\icacls.exe"; Parameters: """{app}"" /remove:g *S-1-5-32-545 /T /C /Q"; Flags: runhidden waituntilterminated + [Icons] Name: "{autoprograms}\AyaNova server\{#MyAppName}"; Filename: "{app}\AyaNova.exe";IconFilename: "{app}\AyaNova.exe"; Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\AyaNova.exe";IconFilename: "{app}\AyaNova.exe"; diff --git a/dist/install/windows/x64/standalone.iss b/dist/install/windows/x64/standalone.iss index 29f792aa..b86ca536 100644 --- a/dist/install/windows/x64/standalone.iss +++ b/dist/install/windows/x64/standalone.iss @@ -45,12 +45,11 @@ Source: "C:\data\code\raven\dist\win-x64\ayanova\standalone\AyaNova.exe"; DestDi Source: "C:\data\code\raven\dist\win-x64\ayanova\standalone\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "C:\data\code\raven\dist\win-x64\launcher\config.json"; DestDir: "{app}"; Flags: ignoreversion confirmoverwrite Source: "C:\data\code\raven\dist\win-x64\launcher\*"; DestDir: "{app}\launcher"; Flags: ignoreversion recursesubdirs createallsubdirs -Source: "C:\data\code\raven\dist\win-x64\postgres-standalone\*"; DestDir: "{app}\local-postgres"; Permissions: users-modify;Flags: ignoreversion recursesubdirs createallsubdirs +Source: "C:\data\code\raven\dist\win-x64\postgres-standalone\*"; DestDir: "{app}\local-postgres"; Flags: ignoreversion recursesubdirs createallsubdirs Source: "C:\data\code\raven\dist\win-x64\postgres-empty-database\*"; DestDir: "{commonappdata}\ayanova\database"; Permissions: users-modify; Flags: ignoreversion recursesubdirs createallsubdirs onlyifdoesntexist uninsneveruninstall [Dirs] ;Name: "{app}\.local-chromium";Permissions: users-modify;Flags: uninsalwaysuninstall -Name: "{app}";Permissions: users-modify; Name: "{commonappdata}\ayanova";Permissions: users-modify;Flags: uninsneveruninstall Name: "{commonappdata}\ayanova\logs";Permissions: users-modify;Flags: uninsneveruninstall ; Empty folders PostgreSQL 14 needs in a new database. Git does not keep empty folders, so dist\win-x64\postgres-empty-database @@ -81,6 +80,10 @@ Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\launcher\ayanova-launcher.e ;removed this from above line to force desktop icon Tasks: desktopicon [Run] +; case 4579: the program folder is no longer writable by all local users (nothing writes there, data is under +; {commonappdata}\ayanova). Upgrades over 8.2.4 or older still carry the old grant, so remove the Users group's own +; rights (by SID, the group name is translated) from the program folder and everything in it; inherited read rights stay +Filename: "{sys}\icacls.exe"; Parameters: """{app}"" /remove:g *S-1-5-32-545 /T /C /Q"; Flags: runhidden waituntilterminated Filename: "{app}\launcher\ayanova-launcher.exe"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent [Code] diff --git a/docs/8.0/ayanova/docs/changelog.md b/docs/8.0/ayanova/docs/changelog.md index c99610bf..b7a52457 100644 --- a/docs/8.0/ayanova/docs/changelog.md +++ b/docs/8.0/ayanova/docs/changelog.md @@ -37,6 +37,7 @@ IN PROGRESS - Linux: Ubuntu 24.04 and 26.04 are now tested and supported. On Ubuntu 24.04 and newer the .NET runtime is installed from Ubuntu's own package archive. - Docs: updated the [Linux server](ops-install-linux-server.md), [Linux desktop](ops-install-linux-desktop.md), [Windows local network](ops-install-windows-lan.md) and [Windows IIS](ops-install-windows-iis.md) installation and upgrade instructions for .NET 10 and Ubuntu 24.04 / 26.04. - Docs: updated the database password guidance in the installation and [backup](ops-form-backup.md) documentation. +- Windows: the installers no longer give all local users write access to the AyaNova program folder; only administrators can change files there. Upgrading removes the earlier write access. - Windows: the local network installer and the [local network](ops-install-windows-lan.md) and [IIS](ops-install-windows-iis.md) installation instructions now link to the official PostgreSQL download page (the third-party guide linked before is no longer available), and the configuration examples assume PostgreSQL 18. - Docs: the Windows installation instructions now state that only one type of AyaNova 8 installation (single user, local network or IIS) can be on a computer at a time. diff --git a/docs/8.0/ayanova/docs/ops-install-windows-lan.md b/docs/8.0/ayanova/docs/ops-install-windows-lan.md index 42719f55..46a45460 100644 --- a/docs/8.0/ayanova/docs/ops-install-windows-lan.md +++ b/docs/8.0/ayanova/docs/ops-install-windows-lan.md @@ -26,6 +26,7 @@ An up to date modern web browser (not Internet Explorer) with Javascript enabled - Program files : By default (and recommended) AyaNova server program files will be installed to `C:\Program Files\ayanova` folder - Data files: All data aside from attachment files is stored in the PostgreSQL database. By default AyaNova will store attachment files, logs and backup files in the %ProgramData% folder under `ayanova` which on most computers will be located at `C:\ProgramData\ayanova`. Each folder location can be changed via [configuration](ops-config-environment-variables.md). +- Folder permissions: only administrators can change files in the program folder, so `config.json` must be edited with Notepad run as administrator (see below). Every user of the computer can change files in the data folder, because the AyaNova server runs as whichever user starts it. If the computer is shared with people who should not have access to AyaNova's data, limit the data folder to the Windows account that runs the AyaNova server. The `config.json` file contains the database password and can be read by every user of the computer; on a shared computer limit it to Administrators and the Windows account that runs the AyaNova server. ## Installation procedure diff --git a/docs/8.0/ayanova/docs/ops-install-windows-single.md b/docs/8.0/ayanova/docs/ops-install-windows-single.md index 874cf7d0..b579d2a5 100644 --- a/docs/8.0/ayanova/docs/ops-install-windows-single.md +++ b/docs/8.0/ayanova/docs/ops-install-windows-single.md @@ -32,6 +32,7 @@ The single user installer will use TCP/IP ports 6432 for the PostgreSQL server a - Program files : By default (and recommended) AyaNova server program files will be installed to `C:\Program Files\ayanova` folder - Data files: AyaNova will store all data in the %ProgramData% folder under `ayanova` which on most computers will be located at `C:\ProgramData\ayanova`. This includes all logs, backups and User attachment files. +- Folder permissions: only administrators can change files in the program folder. Every user of the computer can change files in the data folder, because AyaNova and its built in database server run as whichever user starts them. If the computer is shared with people who should not have access to AyaNova's data, limit the data folder to the Windows account that runs AyaNova. The `config.json` file in the program folder contains the database password and can be read by every user of the computer; on a shared computer limit it to Administrators and the Windows account that runs AyaNova. ## Installation procedure