generated from jric11/baseProject
Chat's updates for security, db and workflow
Security and workflow regressions / regression (push) Has been cancelled
Security and workflow regressions / regression (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
# Project repairs and multi-club setup
|
||||
|
||||
Implemented and tested October 18, 2026. Existing authentication work is described
|
||||
in [AUTHENTICATION.md](AUTHENTICATION.md).
|
||||
|
||||
## Database rollout
|
||||
|
||||
The roster migration was applied to the development database on October 18, 2026,
|
||||
after the implementation tests and a fresh, verified backup. The development
|
||||
verification is recorded below. Existing accounts and passwords were preserved.
|
||||
|
||||
After backing up the target database, run from the project directory with the
|
||||
application's database configuration and PHP runtime:
|
||||
|
||||
```text
|
||||
php bin/migrate-roster.php
|
||||
```
|
||||
|
||||
The migration adds five InnoDB tables: clubs, memberships, seasons, dues, and
|
||||
payments. It preserves existing records, can be rerun, and uses foreign keys to
|
||||
prevent orphan records and cross-club dues assignments. It does not rebuild the
|
||||
database. The authentication migration remains a prerequisite for this version;
|
||||
it was already applied to development during the earlier authentication work.
|
||||
|
||||
The existing backup was restored locally, its SHA-256 and all ten original table
|
||||
counts were checked, then both migrations were rehearsed. Running the roster
|
||||
migration twice preserved all ten original counts. The restored copy was removed.
|
||||
On other installations, until the roster migration is applied, the home page
|
||||
explains that setup is needed.
|
||||
|
||||
Use the PHP version and Composer requirements in AUTHENTICATION.md. Report tests
|
||||
used the curl, zip, gd, fileinfo, mbstring, openssl, PDO MySQL, and XSL extensions.
|
||||
Run Composer's platform requirements check with the web server's PHP configuration.
|
||||
|
||||
## Security and deletion safeguards
|
||||
|
||||
- Dropdown usage metadata no longer selects arbitrary PHP callbacks or SQL
|
||||
identifiers. Only the supported no-reference rule is accepted; unsupported
|
||||
legacy rules fail closed rather than exposing settings or allowing deletion.
|
||||
- IDs and booleans are validated, and dropdown writes use bound parameters.
|
||||
A dropdown must belong to the requested type and be active to become default.
|
||||
Switching defaults is transactional and serialized by type. Deactivation clears
|
||||
the default. Default dropdowns and types containing dropdowns cannot be deleted.
|
||||
- Account deletion, disablement, and role changes protect the last active
|
||||
administrator, including simultaneous requests. Administrators cannot delete
|
||||
themselves; ordinary administrators cannot modify System Administrator accounts.
|
||||
Accounts with notes or club memberships must be retained. Reset tokens are
|
||||
removed transactionally when an otherwise unused account is deleted.
|
||||
- Status saves validate fields and enforce at most one default; inactive defaults
|
||||
and deletion of the current default are rejected. Removed dependencies on
|
||||
nonexistent requests and workorders tables from usage checks.
|
||||
- Notes validate type, text, target, and existing note on the server. Target user
|
||||
locks coordinate note creation with account deletion. Queries are bound and
|
||||
displayed note text is escaped.
|
||||
- Routing allows only supported actions, with administrative access enforced on
|
||||
maintenance and exports. Removed arbitrary helper dispatch and obsolete report
|
||||
dispatch. Failures return meaningful HTTP statuses and escaped messages;
|
||||
AJAX no longer treats an empty successful write as invalid JSON.
|
||||
|
||||
## Accounts, lists, navigation, and browser behavior
|
||||
|
||||
- Administrative account creation validates first and last names, username,
|
||||
email, and role. It stores an unknown random hashed password and sends a setup
|
||||
link. A mail failure reports that the account exists and offers a resend path;
|
||||
retrying cannot silently duplicate the account. No temporary password is exposed.
|
||||
- Repaired account summaries, notes, and login history without the missing
|
||||
Subscriptions dependency. Corrected username lookup and invitation resend.
|
||||
- Restored audit entries for successful login, reset requests, password resets,
|
||||
and password changes; club saves, dues, and payments also write journal entries.
|
||||
Audit write errors are logged without breaking authentication.
|
||||
- Pagination now uses correct last-page offsets, stable ordering, bounded page
|
||||
sizes, empty-list handling, and independent state per list. Fixed incorrect
|
||||
per-page fields, added status page-size refresh, escaped search patterns, and
|
||||
added last-name account search and display.
|
||||
- Replaced dead permit, zoning, subscription, support-ticket, and payment links
|
||||
with Clubs and dues, Help, and a working report catalog. Retired three legacy
|
||||
permit report implementations and obsolete metrics dependencies.
|
||||
- Converted synchronous browser requests to asynchronous requests and fixed their
|
||||
callers. Save/confirmation controls wait for requests, errors appear visibly,
|
||||
and failed deletion checks never open a confirmation dialog. Default-checkbox
|
||||
failures restore the prior selection.
|
||||
- Hidden form inputs are built as DOM text values; toast and error content use
|
||||
text rendering. Cached form restoration excludes hidden routing fields, IDs,
|
||||
CSRF tokens, and passwords. Fixed ZIP lookup routing, logout request handling,
|
||||
tooltip initialization, and jQuery callback compatibility.
|
||||
|
||||
## Multi-club roster features
|
||||
|
||||
- Site administrators create, rename, archive, and reactivate multiple clubs.
|
||||
They assign existing accounts to separate club memberships, maintain membership
|
||||
status and joined dates, and add dated seasons.
|
||||
- Ordinary members see active clubs to which they have active membership, their
|
||||
club's active contact roster, and only their own dues. Changing a URL or form ID
|
||||
cannot grant access to another club. Membership changes take effect in existing
|
||||
sessions. Signup alone grants no club membership.
|
||||
- Administrators record season dues and received payments in a **manual USD
|
||||
ledger**. Amounts use integer cents, reject fractional cents and negative values,
|
||||
and payments cannot exceed the remaining balance. Repeated payment submissions
|
||||
use an idempotency key to avoid duplicate entries. Dates and club relationships
|
||||
are checked on the server.
|
||||
- Archiving retains membership and financial history and prevents further writes
|
||||
until reactivation. History is not exposed through destructive delete controls.
|
||||
- Administrators can export a club roster as CSV, Excel, or PDF. Spreadsheet
|
||||
formula injection is neutralized, Excel cells are explicit text, and PDF fields
|
||||
are escaped.
|
||||
|
||||
This is a multi-club foundation managed by global site administrators. It does not
|
||||
provide delegated club administrators, online payment processing, refunds, ledger
|
||||
correction workflows, or automatic billing. These are separate features.
|
||||
|
||||
## Verification
|
||||
|
||||
All final suites passed against generated disposable local databases:
|
||||
|
||||
| Suite | Result |
|
||||
| --- | --- |
|
||||
| Authentication service and templates | 49 checks |
|
||||
| Authentication HTTP routes | 27 checks |
|
||||
| Maintenance validation and pagination units | 52 checks |
|
||||
| Project HTTP, access boundaries, ledger, exports, and paging | 88 checks |
|
||||
| Headless Chrome workflows | 15 checks |
|
||||
| Concurrent default and administrator updates | 2 scenarios |
|
||||
|
||||
Total: **231 checks plus 2 concurrency scenarios**. Browser tests verified account
|
||||
creation, visible invitation failure, account summary, blocked and successful
|
||||
deletion, restricted dropdown metadata, club/membership/season creation, dues,
|
||||
payments, and CSV download without unexpected JavaScript errors. Mail failure was
|
||||
deliberately simulated; this round did not retest real delivery.
|
||||
|
||||
Source checks also passed for 24 application PHP classes, four CLI scripts, four
|
||||
PHP test scripts, main.php, 54 JavaScript files, and 39 compiled XSL stylesheets.
|
||||
All disposable databases were cleaned up and the isolated database server stopped.
|
||||
|
||||
Tests require an explicitly configured isolated MySQL/MariaDB server through
|
||||
`HCR_TEST_DSN`, `HCR_TEST_USER`, and `HCR_TEST_PASSWORD`. HTTP tests additionally
|
||||
require matching `HCR_DB_HOST`, `HCR_DB_PORT`, `HCR_DB_USER`, and `HCR_DB_PASSWORD`.
|
||||
`PHP_TEST_COMMAND` accepts a JSON argument array for the test PHP runtime.
|
||||
`NODE_TEST_COMMAND` selects Node and `NODE_PATH` locates Playwright for browser
|
||||
tests. Do not point these tests at the application database.
|
||||
|
||||
```text
|
||||
php tests/auth_integration.php
|
||||
php tests/maintenance_unit.php
|
||||
python tests/auth_http.py
|
||||
python tests/project_http.py
|
||||
python tests/concurrency.py
|
||||
python tests/browser_runner.py
|
||||
```
|
||||
|
||||
These tests cover application behavior in isolation; deployment still needs the
|
||||
new migration on any other target and validation with its actual PHP, HTTPS, and
|
||||
mail configuration.
|
||||
|
||||
## Development database rollout and verification
|
||||
|
||||
At the user's request, the roster migration was applied to
|
||||
`192.168.1.190/huntingclubroster` on October 18, 2026 at 8:23 p.m. Eastern.
|
||||
The previously approved unencrypted database connection was used.
|
||||
|
||||
Before migration, a fresh complete SQL backup was saved at
|
||||
`.tools/backups/20261018-202150/huntingclubroster.sql` (37,317 bytes). Its SHA-256 is
|
||||
`f4458cce64404063d9760c2fe06f9779cf8904c0dc27d301541b24486382157a`.
|
||||
The backup was restored on an isolated local server; the checksum and row counts
|
||||
for all 12 original tables matched. All existing rows were fingerprinted before
|
||||
and after migration and were unchanged. Five new roster tables are ready.
|
||||
|
||||
Then **54 checks passed against the development database**, through a local HTTP
|
||||
application server using three temporary accounts, two temporary clubs, separate
|
||||
memberships, three dues records, and received payments. The checks covered:
|
||||
|
||||
- Creating multiple clubs, seasons, and memberships, including one account in two
|
||||
clubs and rejection of duplicate memberships and dues.
|
||||
- Membership and season boundaries, member financial privacy, administrative
|
||||
permissions, CSRF enforcement, and protection against account deletion.
|
||||
- Exact cents, partial payments, correct balances, idempotent payment retries,
|
||||
changed-key-payload rejection, overpayment rejection, and full settlement.
|
||||
- Immediate access revocation for inactive membership or archived clubs, blocked
|
||||
writes while archived, and successful reactivation with preserved ledger data.
|
||||
- Valid CSV, Excel, and PDF downloads.
|
||||
|
||||
An initial verification-helper session setup error was corrected before the
|
||||
successful run; its temporary records were also removed. This required no change
|
||||
to application code.
|
||||
|
||||
All temporary accounts, club records, dues, payments, test audit entries, rate
|
||||
limit records, and sessions were removed afterward. Every row across all 17
|
||||
tables matched the pre-test fingerprint. Auto-increment sequences may have
|
||||
advanced during testing. No existing passwords were changed and no emails or
|
||||
online payment transactions were sent. These are manually recorded payments.
|
||||
|
||||
Private backup metadata, migration results, and the check-by-check verification
|
||||
report are retained alongside the backup in `.tools/backups/20261018-202150/`.
|
||||
That directory is ignored by Git and blocked by the development router. The local
|
||||
restore copy was removed and the isolated local database server stopped.
|
||||
Reference in New Issue
Block a user