From 598458f53cb4d272330da16386e09d446269f5f4 Mon Sep 17 00:00:00 2001 From: Yasen Pramatarov Date: Sat, 11 Apr 2026 19:14:26 +0300 Subject: [PATCH] adds docs --- doc/app-registry.md | 59 +++++++++++++++++ doc/security.md | 100 ++++++++++++++++++++++++++++ doc/url-canonicalization.md | 126 ++++++++++++++++++++++++++++++++++++ 3 files changed, 285 insertions(+) create mode 100644 doc/app-registry.md create mode 100644 doc/security.md create mode 100644 doc/url-canonicalization.md diff --git a/doc/app-registry.md b/doc/app-registry.md new file mode 100644 index 0000000..b04642e --- /dev/null +++ b/doc/app-registry.md @@ -0,0 +1,59 @@ +# App Registry Helper + +The `App\App` class provides a service locator to expose core services to +plugins without relying on globals or relative `require_once` paths. + +## Goals + +1. Provide a stable API surface for plugins and core modules. +2. Allow gradual refactors away from `$GLOBALS`. +3. Keep legacy code working by falling back to existing globals when no service + has been registered yet. + +## Usage + +```php +use App\App; + +// Register services during bootstrap +App::set('config', $config); +App::set('db', $dbConnection); +App::set('logger', $logger); + +// Use services anywhere later +$db = App::db(); +$config = App::config(); +$logger = App::get('logger'); +``` + +### Convenience Helpers + +The helper exposes shortcuts for the most common services: + +- `App::db()` – database connection +- `App::config()` – configuration array +- `App::user()` – authenticated user object (if any) + +All helper calls fall back to their legacy `$GLOBALS` equivalents so older code +can be migrated incrementally. + +### Resetting (Tests) + +Unit tests can call `App::reset()` (optionally with a service key) to clear the +registry and avoid old state bleed between test cases. + +## Bootstrap Integration + +`public_html/index.php` now registers runtime services as they are created: + +```php +App::set('config', $config); +App::set('config_path', $configFile); +App::set('app_root', $appRoot); +App::set('db', $db); +App::set('logger', $logger); +``` + +Plugins should prefer `App` over accessing globals directly. This ensures future +moves (like relocating call logic into `plugins/calls/`) do not require path rewrites +or global variables. diff --git a/doc/security.md b/doc/security.md new file mode 100644 index 0000000..977b79d --- /dev/null +++ b/doc/security.md @@ -0,0 +1,100 @@ +# Security Documentation + +## Overview + +This document outlines the security features and practices implemented in the system. + +## Authentication + +Authentication is handled through the user accounts system. See `user-accounts.md` for details on: +- User registration +- Login/logout functionality +- Password requirements +- Session management + +## Database Security + +1. **SQL Injection Prevention** + - All database queries use prepared statements with parameterized queries + - Input validation and sanitization + - Use of PDO for database access + +2. **Data Access Control** + - User ownership verification on all operations + - Permission checks before data access + - Proper error handling to prevent information leakage + +## Database Tables + +The security system uses the following tables: + +1. **Rate Limits (`rate_limit`)** + - Tracks rate limiting for various operations + - User and IP tracking + - Operation type identification + - Timestamp tracking + - Attempt counting + +2. **Security Events (`security_event`)** + - Records security-related events + - Event type and severity + - User and IP information + - Timestamp tracking + - Event details storage + +3. **Blocked IPs (`blocked_ip`)** + - Manages IP blocking + - Block reason tracking + - Block duration + - Administrator notes + +## Data Protection + +1. **Passwords** + - Stored using secure hashing + - Never stored or transmitted in plain text + - Password reset functionality with secure tokens + +2. **Session Security** + - Session tokens properly generated and managed + - Session timeout implementation + - Protection against session fixation + +3. **Input Validation** + - Data validation on both client and server side + - Protection against XSS attacks + - Content type verification + - Size limits on inputs + +## Access Control + +1. **Resource Protection** + - User ownership verification for all resources + - Permission checks before operations + - Proper error handling for unauthorized access + +2. **API Security** + - Authentication required for API access + - Rate limiting + - Input validation + - Error handling without information leakage + +## Best Practices + +1. **Code Security** + - Use of prepared statements + - Input validation and sanitization + - Proper error handling + - Secure configuration management + +2. **Data Security** + - User data protection + - Secure storage practices + - Access control implementation + - Error handling without leaks + +3. **Infrastructure Security** + - Configuration security + - Environment separation + - Secure deployment practices + - Regular security updates diff --git a/doc/url-canonicalization.md b/doc/url-canonicalization.md new file mode 100644 index 0000000..a4e0302 --- /dev/null +++ b/doc/url-canonicalization.md @@ -0,0 +1,126 @@ +# URL canonicalization and normalization guide + +This document defines the standard flow for query-string canonicalization in page/controllers. +Use it for all new route work and when touching existing page logic. + +## Why this exists + +Canonical URLs make route behavior predictable and secure by: +- removing unknown query parameters, +- normalizing known parameters to expected types, +- preventing duplicate URL variants for the same page state, +- reducing controller-specific ad-hoc redirect logic. + +## Shared helper + +All route canonicalization must use: +- `app/helpers/url_canonicalizer.php` + +Core functions: +- `app_url_build_query_from_policy(array $sourceQuery, array $policy): array` +- `app_url_redirect_to_canonical_query(string $appRoot, array $currentQuery, array $canonicalQuery): void` +- `app_url_build_internal(string $appRoot, array $query): string` +- `app_url_policy_value(string $targetKey, array $rule, array $sourceQuery)` + +## Standard controller flow + +For GET routes, follow this order: + +1. Resolve request context (`app_root`, user/session state, etc.). +2. Resolve a defensive GET guard (`$isGetRequest`) from `$_SERVER['REQUEST_METHOD']`. +3. Define canonical policy rules for the route. +4. Build canonical query from `$_GET`. +5. Redirect if current query differs from canonical query. +6. Continue regular page logic (rendering, DB loading, etc.). + +Reference pattern: + +```php +require_once APP_PATH . 'helpers/url_canonicalizer.php'; + +$isGetRequest = strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET')) === 'GET'; +if ($isGetRequest) { + $canonicalPolicy = [ + 'page' => [ + 'type' => 'literal', + 'value' => 'example', + ], + ]; + + $canonicalQuery = app_url_build_query_from_policy($_GET, $canonicalPolicy); + + // Keep example URLs constrained to supported route state. + app_url_redirect_to_canonical_query((string)$app_root, $_GET, $canonicalQuery); +} +``` + +## Policy rule types + +Supported rule `type` values: +- `literal`: fixed value from policy (`value`) +- `string`: trimmed scalar string +- `int`: integer with optional bounds (`min`, `max`) +- `enum`: string limited to `allowed` values +- `bool_flag`: emits `value_true` for truthy request inputs +- `string_list`: normalized list values (optionally `unique`) + +Useful options: +- `source`: map canonical key from another source key +- `default`: fallback value +- `include_if`: callable gate to include rule conditionally +- `omit_if`: drop key when value equals sentinel +- `transform`: callable value transformer +- `validator`: callable final validator + +## Route design rules + +When adding canonicalization: +- Always include `page` as `literal`. +- Keep allowed query set minimal. +- Use `enum` for fixed states (`tab`, `action`, `status`, etc.). +- Use `int` with bounds for IDs and pagination. +- Use `omit_if` to avoid noisy defaults in URLs (for example `p=1`). +- Preserve only query keys that materially represent page state. + +## What not to canonicalize as page URLs + +Do not force page-style canonicalization on non-page endpoints that intentionally behave as API/callback streams, for example: +- JSON suggestion endpoints, +- payment webhook/callback handlers, +- binary/document output handlers, +- static asset streaming handlers. + +For these endpoints, keep strict input validation and explicit allowlists as currently implemented. + +## Redirect behavior + +`app_url_redirect_to_canonical_query` compares normalized current and canonical queries. +If different, it sends a `Location` header and exits. + +Implications: +- Logic after the call runs only for canonical request URLs. +- Downstream code may continue reading `$_GET`; values are already canonicalized by redirect gate. +- If custom redirect URL construction is needed after POST actions, use `app_url_build_internal` with a policy-built query. + +## Update checklist for new/edited routes + +When changing a route: +1. Add/confirm `require_once` for `url_canonicalizer.php`. +2. Use the standardized defensive guard: + `$isGetRequest = strtoupper((string)($_SERVER['REQUEST_METHOD'] ?? 'GET')) === 'GET';` +3. Add/adjust GET canonical policy near route entry. +4. Keep existing business logic unchanged unless explicitly requested. +5. Add concise inline comment for non-trivial policy/condition blocks. +6. Update deployment-facing route documentation used in your environment. +7. Run syntax checks and PHPUnit as part of validation cadence. + +## Deployment notes + +Coverage is deployment-scoped. + +When auditing a specific environment: +- verify enabled route entry points use policy-based canonicalization, +- keep non-page API/callback/document/asset endpoints on strict allowlist + validation, +- keep local operational/developer documentation updated according to the + documentation set available in that installation.