Inside IIS (in-process) AyaNova has no port of its own, so the report page
could not reach the API: user reports called http://127.0.0.1:<request port>
(reset on https), notification reports 127.0.0.1:7575 (refused). Under IIS the
page's requests under the API URL are now intercepted and made by the server
(util/ReportApiRelay.cs) to the local address and port a user's request
arrived on, with its host name and scheme; notification reports use the
latest signed-in request, else the override. Outside IIS nothing changes.
The notification token check requires a request from this machine, no longer
host 127.0.0.1. Manual (IIS install, override page) and changelog updated.
Deferred: emailed PDF content type application/pdf/pdf.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
New config setting AYANOVA_TRUSTED_PROXIES (IP addresses or CIDR networks)
for reverse proxies on another computer: their X-Forwarded-For is used, a
chain of trusted proxies is followed, invalid entries are warned at boot.
X-Forwarded-For from a proxy that is not trusted logs one warning per server
start naming the proxy's address. Without the setting nothing changes (only
a loopback proxy is trusted). Shown in server info; manual page, Linux install
note, changelog. F6 follow-up recorded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every response carries X-Content-Type-Options: nosniff, X-Frame-Options:
SAMEORIGIN and Referrer-Policy: strict-origin, so self-hosted installs
get them too (the hosted nginx sends the same values). F35 (4727 step 6).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A password set by someone else (reset code, administrator) or a disabled
login replaces the user's session token and download key; changing one's
own password keeps the session. PasswordResetCodeExpire is cleared (was
DlKeyExpire). The token middleware exempts only the exact login and
notify/hello routes and refuses inactive users and users who may not log
in. With a purchased licence, notify/hello no longer offers the default
SuperUser login and a SuperUser with the default password may only change
it (SuperUserDefaultPasswordRoutes). F7, F8 and F9 fixed. Manual and
changelog updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Users who may edit contacts but not users (Service, Sales, Accounting) could
give a contact login any role, BizAdmin and OpsAdmin included, and roles are
what every check uses (security review F28). Now:
- saving a Customer or HeadOffice user with any role other than Customer or
CustomerRestricted is refused (error on Roles);
- UserBiz.EffectiveRoles masks a contact's roles to the customer roles wherever
they are applied: the token middleware, download-key routes, and the
notification subscriber check, so contacts that already have staff roles
stored act without them.
Checked: Service creating a contact with BizAdmin refused, with Customer works;
a contact with OpsAdmin stored in the database gets 403 downloading a log file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Customer contacts had the Customer role's Select and read rights on most record
types and could call any route whose staff role check they passed, including
several with no role check (security review F13 to F17). Step 1 of 4712: the
token middleware now answers 403 (same body as other 403s) to Customer and
HeadOffice users for any route not in CustomerContactRoutes, the routes the
customer screens use (read from raven-client). Anonymous routes are always
allowed. New routes stay closed to contacts unless added on purpose.
Ownership of the records these routes return follows in the next steps.
Checked: full integration suite 103 passed, 5 skipped, the same 2 known
failures as the baseline.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The LAN/IIS and Linux templates shipped a placeholder secret printed in the
manual, and installs that kept it signed logins with a public key; any setting
also invited short or reused values (security review F1). The setting is now
ignored (one warning at boot if still present): the server generates a key once
(48 random bytes) into jwt-signing.key in the data folder (beside the app if
there is none; owner-only on Linux) and reuses it, so sign-ins also survive a
restart where the server used to make a new key each boot (standalone, Linux
desktop). If the file cannot be used, a temporary key is used for that run.
Templates and dev launch configs drop the setting; manual updated (key page
rewritten, setting steps removed from install pages); changelog line.
Checked locally: token forged with the old placeholder 401; key file created
and reused after restart (old token 200); auth and 2FA tests pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>