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 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 14:39:00 -07:00
parent c04de33af2
commit e9b79242fd
7 changed files with 18 additions and 6 deletions

View File

@@ -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 | | 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 | | 4623 | Docs: migration, what is erased and what is kept | 1, docs |
| 4602 | Logo upload UI: hide Upload and Delete until usable | 1, client | | 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 | | 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). 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 - 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 - **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 - **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 ## Log

View File

@@ -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 | | 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 | | 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`) | | 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 | | 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` | | 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 | | 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 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 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 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 ### F3 `notify/direct-smtp` open to every logged-in user

View File

@@ -43,7 +43,6 @@ Source: "C:\data\code\raven\dist\assets\open-ayanova-app.bat"; DestDir: "{app}";
[Dirs] [Dirs]
Name: "{app}";Permissions: users-modify;
Name: "{commonappdata}\ayanova";Permissions: users-modify; Name: "{commonappdata}\ayanova";Permissions: users-modify;
Name: "{commonappdata}\ayanova\logs";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}\Chrome"
Type: filesandordirs; Name: "{app}\ChromeHeadlessShell" 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] [Icons]
Name: "{autoprograms}\AyaNova server\{#MyAppName}"; Filename: "{app}\AyaNova.exe";IconFilename: "{app}\AyaNova.exe"; Name: "{autoprograms}\AyaNova server\{#MyAppName}"; Filename: "{app}\AyaNova.exe";IconFilename: "{app}\AyaNova.exe";
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\AyaNova.exe";IconFilename: "{app}\AyaNova.exe"; Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\AyaNova.exe";IconFilename: "{app}\AyaNova.exe";

View File

@@ -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\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\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\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 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] [Dirs]
;Name: "{app}\.local-chromium";Permissions: users-modify;Flags: uninsalwaysuninstall ;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";Permissions: users-modify;Flags: uninsneveruninstall
Name: "{commonappdata}\ayanova\logs";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 ; 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 ;removed this from above line to force desktop icon Tasks: desktopicon
[Run] [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 Filename: "{app}\launcher\ayanova-launcher.exe"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
[Code] [Code]

View File

@@ -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. - 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 [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. - 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. - 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. - 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.

View File

@@ -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 - 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). - 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 ## Installation procedure

View File

@@ -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 - 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. - 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 ## Installation procedure