Fix tenant event form package selector so it no longer renders empty-value options, handles loading/empty
states, and pulls data from the authenticated /api/v1/tenant/packages endpoint.
(resources/js/admin/pages/EventFormPage.tsx, resources/js/admin/api.ts)
- Harden tenant-admin auth flow: prevent PKCE state loss, scope out StrictMode double-processing, add SPA
routes for /event-admin/login and /event-admin/logout, and tighten token/session clearing semantics (resources/js/admin/auth/{context,tokens}.tsx, resources/js/admin/pages/{AuthCallbackPage,LogoutPage}.tsx,
resources/js/admin/router.tsx, routes/web.php)
This commit is contained in:
28
docs/deployment/join-token-analytics.md
Normal file
28
docs/deployment/join-token-analytics.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# Join Token Analytics & Alerting (SEC-GT-02)
|
||||
|
||||
## Data Sources
|
||||
- Table `event_join_token_events` captures successes, failures, rate-limit hits, and uploads per join token.
|
||||
- Each row records route, device id, IP, HTTP status, and context for post-incident drill downs.
|
||||
- Logged automatically from `EventPublicController` for `/api/v1/events/*` and `/api/v1/gallery/*`.
|
||||
|
||||
- Super Admin: Event resource → “Join Link / QR” modal now summarises total successes/failures, rate-limit hits, 24h volume, and last activity timestamp per token.
|
||||
- Tenant Admin: identical modal surface so operators can monitor invite health.
|
||||
|
||||
## Alert Thresholds (initial)
|
||||
- **Rate limit spike**: >25 `token_rate_limited` entries for a token within 10 minutes → flag in monitoring (Grafana/Prometheus TODO).
|
||||
- **Failure ratio**: failure_count / success_count > 0.5 over rolling hour triggers warning for support follow-up.
|
||||
- **Inactivity**: tokens without access for >30 days should be reviewed; scheduled report TBD.
|
||||
|
||||
Rate-limiter knobs (see `.env.example`):
|
||||
- `JOIN_TOKEN_FAILURE_LIMIT` / `JOIN_TOKEN_FAILURE_DECAY` — repeated invalid attempts before temporary block (default 10 tries per 5 min).
|
||||
- `JOIN_TOKEN_ACCESS_LIMIT` / `JOIN_TOKEN_ACCESS_DECAY` — successful request ceiling per token/IP (default 120 req per minute).
|
||||
- `JOIN_TOKEN_DOWNLOAD_LIMIT` / `JOIN_TOKEN_DOWNLOAD_DECAY` — download ceiling per token/IP (default 60 downloads per minute).
|
||||
|
||||
## Follow-up Tasks
|
||||
1. Wire aggregated metrics into Grafana once metrics pipeline is ready (synthetic monitors pending SEC-GT-03).
|
||||
2. Implement scheduled command to email tenants a weekly digest of token activity and stale tokens.
|
||||
3. Consider anonymising device identifiers before long-term retention (privacy review).
|
||||
|
||||
## Runbook Notes
|
||||
- Analytics table may grow quickly for high-traffic events; plan nightly prune job (keep 90 days).
|
||||
- Use `php artisan tinker` to inspect token activity: `EventJoinTokenEvent::where('event_join_token_id', $id)->latest()->limit(20)->get()`.
|
||||
58
docs/deployment/oauth-key-rotation.md
Normal file
58
docs/deployment/oauth-key-rotation.md
Normal file
@@ -0,0 +1,58 @@
|
||||
# OAuth JWT Key Rotation Playbook (Dual-Key)
|
||||
|
||||
## Purpose
|
||||
Ensure marketing/tenant OAuth tokens remain valid during RSA key rotations by keeping the previous signing key available until all legacy tokens expire.
|
||||
|
||||
## Prerequisites
|
||||
- Environment variable `OAUTH_KEY_STORE` points to a shared filesystem (default `storage/app/oauth-keys`).
|
||||
- `OAUTH_JWT_KID` set to the current signing key id.
|
||||
- Application deploy tooling able to propagate `.env` changes promptly.
|
||||
- Operations access to run artisan commands in the target environment.
|
||||
|
||||
## Rotation Workflow
|
||||
|
||||
1. **Review existing keys**
|
||||
```bash
|
||||
php artisan oauth:list-keys
|
||||
```
|
||||
Confirm the `current` entry matches `OAUTH_JWT_KID`, note any legacy KIDs that should remain trusted until rotation completes.
|
||||
|
||||
2. **Generate new key pair**
|
||||
```bash
|
||||
php artisan oauth:rotate-keys --kid=fotospiel-jwt-$(date +%Y%m%d%H%M)
|
||||
```
|
||||
- The command now *copies* the existing key into the `/archive` folder but leaves it in-place for token verification.
|
||||
- After the command, run `php artisan oauth:list-keys` again to verify both the old and new KIDs exist.
|
||||
|
||||
3. **Update environment configuration**
|
||||
- Set `OAUTH_JWT_KID` to the newly generated value.
|
||||
- Deploy the updated config (restart queue workers/web instances if they cache config).
|
||||
|
||||
4. **Smoke test issuance**
|
||||
- Request a fresh OAuth token (PKCE flow) and inspect the JWT header — `kid` must match the new value.
|
||||
- Use an existing token issued **before** the rotation to hit a tenant API route; it should continue to verify because the old key remains present.
|
||||
|
||||
5. **Monitor**
|
||||
- Watch application logs for `Invalid token` / `JWT public key not found` errors over the next 24h.
|
||||
- Investigate any anomalies before pruning.
|
||||
|
||||
## Pruning Legacy Keys
|
||||
After the longest access-token + refresh-token lifetime (default: 30 days for refresh), prune the legacy signing directory.
|
||||
|
||||
```bash
|
||||
php artisan oauth:prune-keys --days=45 --force
|
||||
```
|
||||
|
||||
- Use `--dry-run` first to see which directories would be removed.
|
||||
- The prune command never deletes the `current` KID.
|
||||
- Archived copies remain under `storage/app/oauth-keys/archive/...` for forensics.
|
||||
|
||||
## Runbook Summary
|
||||
| Step | Command | Outcome |
|
||||
| --- | --- | --- |
|
||||
| Inspect | `php artisan oauth:list-keys` | Inventory current + legacy keys |
|
||||
| Rotate | `php artisan oauth:rotate-keys --kid=...` | Creates new key while keeping legacy key active |
|
||||
| Verify | Issue new token + test old token | Ensures dual-key window works |
|
||||
| Prune | `php artisan oauth:prune-keys --days=45` | Removes legacy key once safe |
|
||||
|
||||
Document completion of `SEC-IO-01` in `docs/todo/security-hardening-epic.md` when the rotation runbook has been rehearsed in staging.
|
||||
106
docs/deployment/public-api-incident-playbook.md
Normal file
106
docs/deployment/public-api-incident-playbook.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Public API Incident Response Playbook (SEC-API-02)
|
||||
|
||||
Scope: Guest-facing API endpoints that rely on join tokens and power the guest PWA plus the public gallery. This includes:
|
||||
|
||||
- `/api/v1/events/{token}/*` (stats, tasks, uploads, photos)
|
||||
- `/api/v1/gallery/{token}/*`
|
||||
- Signed download/asset routes generated via `EventPublicController`
|
||||
|
||||
The playbook focuses on abuse, availability loss, and leaked content.
|
||||
|
||||
---
|
||||
|
||||
## 1. Detection & Alerting
|
||||
|
||||
| Signal | Where to Watch | Notes |
|
||||
| --- | --- | --- |
|
||||
| 4xx/5xx spikes | Application logs (`storage/logs/laravel.log`), centralized logging | Look for repeated `Join token access denied` / `token_rate_limited` or unexpected 5xx. |
|
||||
| Rate-limit triggers | Laravel log lines emitted from `EventPublicController::handleTokenFailure` | Contains IP + truncated token preview. |
|
||||
| CDN/WAF alerts | Reverse proxy (if enabled) | Ensure 429/403 anomalies are forwarded to incident channel. |
|
||||
| Synthetic monitors | Planned via `SEC-API-03` | Placeholder until monitors exist. |
|
||||
|
||||
Manual check commands:
|
||||
|
||||
```bash
|
||||
php artisan log:tail --lines=200 | grep "Join token"
|
||||
php artisan log:tail --lines=200 | grep "gallery"
|
||||
```
|
||||
|
||||
## 2. Severity Classification
|
||||
|
||||
| Level | Criteria | Examples |
|
||||
| --- | --- | --- |
|
||||
| SEV-1 | Wide outage (>50% error rate), confirmed data leak or malicious mass-download | Gallery downloads serving wrong event, join-token table compromised. |
|
||||
| SEV-2 | Localised outage (single tenant/event) or targeted brute force attempting to enumerate tokens | Single event returning 500, repeated `invalid_token` from single IP range. |
|
||||
| SEV-3 | Minor functional regression or cosmetic issue | Rate limit misconfiguration causing occasional 429 for legitimate users. |
|
||||
|
||||
Escalate SEV-1/2 immediately to on-call via Slack `#incident-response` and open PagerDuty incident (if configured).
|
||||
|
||||
## 3. Immediate Response Checklist
|
||||
|
||||
1. **Confirm availability**
|
||||
- `curl -I https://app.test/api/v1/gallery/{known_good_token}`
|
||||
- Use tenant-provided test token to validate `/events/{token}` flow.
|
||||
2. **Snapshot logs**
|
||||
- Export last 15 minutes from log aggregator or `storage/logs`. Attach to incident ticket.
|
||||
3. **Assess scope**
|
||||
- Identify affected tenant/event IDs via log context.
|
||||
- Note IP addresses triggering rate limits.
|
||||
4. **Decide mitigation**
|
||||
- Brute force? → throttle/bock offending IPs.
|
||||
- Compromised token? → revoke token via Filament or `php artisan tenant:join-tokens:revoke {id}` (once command exists).
|
||||
- Endpoint regression? → begin rolling fix or feature flag toggle.
|
||||
|
||||
## 4. Mitigation Tactics
|
||||
|
||||
### 4.1 Abuse / Brute force
|
||||
- Increase rate-limiter strictness temporarily by editing `config/limiting.php` (if available) or applying runtime block in the load balancer.
|
||||
- Use fail2ban/WAF rules to block offending IPs. For quick local action:
|
||||
```bash
|
||||
sudo ufw deny from <ip_address>
|
||||
```
|
||||
- Consider temporarily disabling gallery download by setting `PUBLIC_GALLERY_ENABLED=false` (feature flag planned) and clearing cache.
|
||||
|
||||
### 4.2 Token Compromise
|
||||
- Revoke specific token via Filament “Join Tokens” modal (Event → Join Tokens → revoke).
|
||||
- Notify tenant with replacement token instructions.
|
||||
- Audit join-token logs for additional suspicious use and consider rotating all tokens for the event.
|
||||
|
||||
### 4.3 Internal Failure (500s)
|
||||
- Tail logs for stack traces.
|
||||
- If due to downstream storage, fail closed: return 503 with maintenance banner while running `php artisan storage:diagnostics`.
|
||||
- Roll back recent deployment or disable new feature flag if traced to release.
|
||||
|
||||
## 5. Communication
|
||||
|
||||
| Audience | Channel | Cadence |
|
||||
| --- | --- | --- |
|
||||
| Internal on-call | Slack `#incident-response`, PagerDuty | Initial alert, hourly updates. |
|
||||
| Customer Support | Slack `#support` with summary | Once per significant change (mitigation applied, issue resolved). |
|
||||
| Tenants | Email template “Public gallery disruption” (see `resources/lang/*/emails.php`) | Only for SEV-1 or impactful SEV-2 after mitigation. |
|
||||
|
||||
Document timeline, impact, and mitigation in the incident ticket.
|
||||
|
||||
## 6. Verification & Recovery
|
||||
|
||||
After applying mitigation:
|
||||
|
||||
1. Re-run test requests for affected endpoints.
|
||||
2. Validate join-token creation/revocation via Filament.
|
||||
3. Confirm error rates return to baseline in monitoring/dashboard.
|
||||
4. Remove temporary firewall blocks once threat subsides.
|
||||
|
||||
## 7. Post-Incident Actions
|
||||
|
||||
- File RCA within 48 hours including: root cause, detection gaps, follow-up tasks (e.g., enabling synthetic monitors, adding audit fields).
|
||||
- Update documentation if new procedures are required (`docs/prp/11-public-gallery.md`, `docs/prp/03-api.md`).
|
||||
- Schedule backlog items for long-term fixes (e.g., better anomaly alerting, token analytics dashboards).
|
||||
|
||||
## 8. References & Tools
|
||||
|
||||
- Log aggregation: `storage/logs/laravel.log` (local), Stackdriver/Splunk (staging/prod).
|
||||
- Rate limit config: `App\Providers\AppServiceProvider` → `RateLimiter::for('tenant-api')` and `EventPublicController::handleTokenFailure`.
|
||||
- Token management UI: Filament → Events → Join Tokens.
|
||||
- Signed URL generation: `app/Http/Controllers/Api/EventPublicController` (for tracing download issues).
|
||||
|
||||
Keep this document alongside the other deployment runbooks and review quarterly.
|
||||
@@ -1,6 +1,32 @@
|
||||
### Update 2025-10-21
|
||||
- Phase 3 credit scope delivered: tenant event creation now honours package allowances *and* credit balances (middleware + ledger logging), RevenueCat webhook signature checks ship with queue/backoff + env config, idempotency covered via unit tests.
|
||||
- Follow-up (separate): evaluate photo upload quota enforcement + SuperAdmin ledger visualisations once package analytics stabilise.
|
||||
|
||||
### Upcoming (Next Weeks — Security Hardening)
|
||||
- Week 1
|
||||
- `SEC-IO-01` dual-key rollout playbook.
|
||||
- `SEC-GT-01` hashed join tokens migration.
|
||||
- `SEC-API-01` signed asset URLs.
|
||||
- `SEC-MS-01` AV/EXIF worker integration.
|
||||
- `SEC-BILL-01` checkout session linkage.
|
||||
- `SEC-FE-01` CSP nonce utility.
|
||||
- Week 2
|
||||
- `SEC-IO-02` refresh-token management UI. *(delivered 2025-10-23)*
|
||||
- `SEC-GT-02` token analytics dashboards.
|
||||
- `SEC-API-02` incident response playbook.
|
||||
- `SEC-MS-02` streaming upload refactor.
|
||||
- `SEC-BILL-02` webhook signature freshness.
|
||||
- `SEC-FE-02` consent-gated analytics loader.
|
||||
- Week 3
|
||||
- `SEC-IO-03` subnet/device configuration.
|
||||
- `SEC-GT-03` gallery rate-limit alerts.
|
||||
- `SEC-API-03` synthetic monitoring.
|
||||
- `SEC-MS-03` checksum validation alerts.
|
||||
- `SEC-BILL-03` failed capture notifications.
|
||||
- `SEC-FE-03` cookie banner localisation refresh.
|
||||
- Week 4
|
||||
- `SEC-MS-04` storage health dashboard widget (Media Services).
|
||||
|
||||
# Backend-Erweiterung Implementation Roadmap (Aktualisiert: 2025-09-15 - Fortschritt)
|
||||
|
||||
## Implementierungsstand (Aktualisiert: 2025-09-15)
|
||||
|
||||
@@ -10,13 +10,14 @@
|
||||
## 2025 Hardening Priorities
|
||||
|
||||
- **Identity & OAuth** — *Owner: Backend Platform*
|
||||
Track JWT key rotation via `oauth:rotate-keys`, roll out dual-key support (old/new KID overlap), surface refresh-token revocation tooling, and extend IP/device binding rules for long-lived sessions.
|
||||
Track JWT key rotation via `oauth:rotate-keys`, roll out dual-key support (old/new KID overlap), surface refresh-token revocation tooling, and extend IP/device binding rules for long-lived sessions. See `docs/deployment/oauth-key-rotation.md` for the rotation playbook. Filament now offers a refresh-token console with per-device revocation and audit history.
|
||||
- **Guest Join Tokens** — *Owner: Guest Platform*
|
||||
Hash stored join tokens, add anomaly metrics (usage spikes, stale tokens), and tighten gallery/photo rate limits with visibility in storage dashboards.
|
||||
Hash stored join tokens, add anomaly metrics (usage spikes, stale tokens), and tighten gallery/photo rate limits with visibility in storage dashboards. Join-token access is now logged to `event_join_token_events` with summaries surfaced in the Event admin modal.
|
||||
- **Public API Resilience** — *Owner: Core API*
|
||||
Ensure gallery/download endpoints serve signed URLs, expand abuse throttles (token + IP), and document incident response runbooks in ops guides.
|
||||
Ensure gallery/download endpoints serve signed URLs, expand abuse throttles (token + IP), and document incident response runbooks in ops guides. See `docs/deployment/public-api-incident-playbook.md` for the response checklist.
|
||||
- **Media Pipeline & Storage** — *Owner: Media Services*
|
||||
Introduce antivirus + EXIF scrubbing workers, stream uploads to disk to avoid buffering, and enforce checksum verification during hot→archive transfers with configurable alerts from `StorageHealthService`.
|
||||
- Queue `media-security` (job: `ProcessPhotoSecurityScan`) performs antivirus + EXIF sanitisation per upload; configure via `config/security.php`.
|
||||
- **Payments & Webhooks** — *Owner: Billing*
|
||||
Align legacy Stripe hooks with checkout sessions, add idempotency locks/signature expiry checks, and plug failed capture notifications into the credit ledger audit trail.
|
||||
- **Frontend & CSP** — *Owner: Marketing Frontend*
|
||||
|
||||
@@ -45,6 +45,19 @@ services:
|
||||
QUEUE_SLEEP: 5
|
||||
command: >
|
||||
/var/www/html/docs/queue-supervisor/queue-worker.sh media-storage
|
||||
|
||||
media-security-worker:
|
||||
image: fotospiel-app
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
APP_ENV: ${APP_ENV:-production}
|
||||
QUEUE_CONNECTION: redis
|
||||
QUEUE_TRIES: 3
|
||||
QUEUE_SLEEP: 5
|
||||
command: >
|
||||
/var/www/html/docs/queue-supervisor/queue-worker.sh media-security
|
||||
```
|
||||
|
||||
Scale workers by increasing `deploy.replicas` (Swarm) or adding `scale` counts (Compose v2).
|
||||
@@ -74,6 +87,7 @@ Expose Horizon via your web proxy and protect it with authentication (the app al
|
||||
- `QUEUE_CONNECTION` — should match the driver configured in `.env` (`redis` recommended).
|
||||
- `QUEUE_TRIES`, `QUEUE_SLEEP`, `QUEUE_TIMEOUT`, `QUEUE_MAX_TIME` — optional tuning knobs consumed by `queue-worker.sh`.
|
||||
- `STORAGE_ALERT_EMAIL` — enables upload failure notifications introduced in the new storage pipeline.
|
||||
- `SECURITY_SCAN_QUEUE` — overrides the queue name for the photo antivirus/EXIF worker (`media-security` by default).
|
||||
- Redis / database credentials must be available in the worker containers exactly like the web container.
|
||||
|
||||
### 5. Bootstrapping reminder
|
||||
|
||||
131
docs/todo/media-streaming-upload-refactor.md
Normal file
131
docs/todo/media-streaming-upload-refactor.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# SEC-MS-02 — Streaming Upload Refactor (Requirements Draft)
|
||||
|
||||
**Goal**
|
||||
Replace the current “single POST with multipart FormData” guest upload with a streaming / chunked pipeline that:
|
||||
|
||||
- avoids buffering entire files in PHP memory
|
||||
- supports larger assets (target 25 MB originals)
|
||||
- keeps antivirus/EXIF scrubbing and storage accounting intact
|
||||
- exposes clear retry semantics to the guest PWA
|
||||
|
||||
This document captures the scope for SEC-MS-02 and feeds into implementation tickets.
|
||||
|
||||
---
|
||||
|
||||
## 1. Current State (Baseline)
|
||||
|
||||
- Upload endpoint: `POST /api/v1/events/{token}/upload` handled by `EventPublicController::upload`.
|
||||
- Laravel validation enforces `image|max:6144` (≈6 MB). Entire file is received via `Request::file('photo')`.
|
||||
- Storage flow: `Storage::disk($hotDisk)->putFile(...)` followed by synchronous thumbnail creation and `event_media_assets` bookkeeping.
|
||||
- Device rate limiting: simple counter (`guest_name` = device id) per event.
|
||||
- Security: join token validation + IP rate limiting; antivirus/exif cleanup handled asynchronously by `ProcessPhotoSecurityScan` (queued).
|
||||
- Frontend: guest PWA uses `fetch` + FormData; progress handled by custom XHR queue for UI feedback.
|
||||
|
||||
Pain points:
|
||||
- Upload size ceiling due to PHP post_max_size + memory usage.
|
||||
- Slow devices stall the controller request; no streaming/chunk resume.
|
||||
- Throttling/locks only consider completed uploads; partial data still consumes bandwidth.
|
||||
|
||||
---
|
||||
|
||||
## 2. Target Architecture Overview
|
||||
|
||||
### 2.1 Session-Based Chunk Upload
|
||||
|
||||
1. **Create session**
|
||||
- `POST /api/v1/events/{token}/uploads` → returns `upload_id`, `upload_key`, storage target, chunk size.
|
||||
- Validate join token + device limits *before* accepting session. Record session in new table `event_upload_sessions`.
|
||||
|
||||
2. **Upload chunks**
|
||||
- `PUT /api/v1/events/{token}/uploads/{upload_id}/chunk` with headers: `Content-Range`, `Content-Length`, `Upload-Key`.
|
||||
- Chunks written to hot storage *stream* destination (e.g. `storage/app/uploads/{upload_id}/chunk_{index}`) via `StreamedResponse`/`fopen`.
|
||||
- Track received ranges in session record; enforce sequential or limited parallel chunks.
|
||||
|
||||
3. **Complete upload**
|
||||
- `POST /api/v1/events/{token}/uploads/{upload_id}/complete`
|
||||
- Assemble chunks → single file (use stream copy to final path), compute checksum, dispatch queue jobs (AV/EXIF, thumbnail).
|
||||
- Persist `photos` row + `event_media_assets` references (mirroring current logic).
|
||||
|
||||
4. **Abort**
|
||||
- `DELETE /api/v1/events/{token}/uploads/{upload_id}` to clean up partial data.
|
||||
|
||||
### 2.2 Storage Strategy
|
||||
|
||||
- Use `EventStorageManager` hot disk but with temporary “staging” directory.
|
||||
- After successful assembly, move to final `events/{eventId}/photos/{uuid}.ext`.
|
||||
- For S3 targets, evaluate direct multipart upload to S3 using pre-signed URLs:
|
||||
- Option A (short-term): stream into local disk, then background job pushes to S3.
|
||||
- Option B (stretch): delegate chunk upload directly to S3 using `createMultipartUpload`, storing uploadId + partETags.
|
||||
- Ensure staging cleanup job removes abandoned sessions (cron every hour).
|
||||
|
||||
### 2.3 Metadata & Limits
|
||||
|
||||
- New table `event_upload_sessions` fields:
|
||||
`id (uuid)`, `event_id`, `join_token_id`, `device_id`, `status (pending|uploading|assembling|failed|completed)`, `total_size`, `received_bytes`, `chunk_size`, `expires_at`, `failure_reason`, timestamps.
|
||||
- Device/upload limits: enforce daily cap per device via session creation; consider max concurrent sessions per device/token (default 2).
|
||||
- Maximum file size: 25 MB (configurable via `config/media.php`). Validate at `complete` by comparing expected vs actual bytes.
|
||||
|
||||
### 2.4 Validation & Security
|
||||
|
||||
- Require `Upload-Key` secret per session (stored hashed) to prevent hijacking.
|
||||
- Join token + device validations reused; log chunk IP + UA for anomaly detection.
|
||||
- Abort sessions on repeated integrity failures or mismatched `Content-Range`.
|
||||
- Update rate limiter to consider `PUT` chunk endpoints separately.
|
||||
|
||||
### 2.5 API Responses & Errors
|
||||
|
||||
- Provide consistent JSON:
|
||||
- `201` create: `{ upload_id, chunk_size, expires_at }`
|
||||
- chunk success: `204`
|
||||
- complete: `201 { photo_id, file_path, thumbnail_path }`
|
||||
- error codes: `upload_limit`, `chunk_out_of_order`, `range_mismatch`, `session_expired`.
|
||||
- Document in `docs/prp/03-api.md` + update guest SDK.
|
||||
|
||||
### 2.6 Backend Jobs
|
||||
|
||||
- Assembly job (if asynchronous) ensures chunk merge is offloaded for large files; update `ProcessPhotoSecurityScan` to depend on final asset record.
|
||||
- Add metric counters (Prometheus/Laravel events) for chunk throughput, failed sessions, average complete time.
|
||||
|
||||
---
|
||||
|
||||
## 3. Frontend Changes (Guest PWA)
|
||||
|
||||
- Replace current FormData POST with streaming uploader:
|
||||
- Request session, slice file into `chunk_size` (default 1 MB) using `Blob.slice`, upload sequentially with retry/backoff.
|
||||
- Show granular progress (bytes uploaded / total).
|
||||
- Support resume: store `upload_id` & received ranges in IndexedDB; on reconnect query session status from new endpoint `GET /api/v1/events/{token}/uploads/{upload_id}`.
|
||||
- Ensure compatibility fallback: if browser lacks required APIs (e.g. old Safari), fallback to legacy single POST (size-limited) with warning.
|
||||
- Update service worker/queue to pause/resume chunk uploads when offline.
|
||||
|
||||
---
|
||||
|
||||
## 4. Integration & Migration Tasks
|
||||
|
||||
1. **Schema**: create `event_upload_sessions` table + indices; optional `event_upload_chunks` if tracking per-part metadata.
|
||||
2. **Config**: new entries in `config/media.php` for chunk size, staging path, session TTL, max size.
|
||||
3. **Env**: add `.env` knobs (e.g. `MEDIA_UPLOAD_CHUNK_SIZE=1048576`, `MEDIA_UPLOAD_MAX_SIZE=26214400`).
|
||||
4. **Cleanup Command**: `php artisan media:prune-upload-sessions` to purge expired sessions & staging files. Hook into cron `/cron/media-prune-sessions.sh`.
|
||||
5. **Docs**: update PRP (sections 03, 10) and guest PWA README; add troubleshooting guide for chunk upload errors.
|
||||
6. **Testing**:
|
||||
- Unit: session creation, chunk validation, assembly with mocked storage.
|
||||
- Feature: end-to-end upload success + failure (PHPUnit).
|
||||
- Playwright: simulate chunked upload with network throttling.
|
||||
- Load: ensure concurrent uploads do not exhaust disk IO.
|
||||
|
||||
---
|
||||
|
||||
## 5. Open Questions
|
||||
|
||||
- **S3 Multipart vs. Local Assembly**: confirm timeline for direct-to-S3; MVP may prefer local assembly to limit complexity.
|
||||
- **Encryption**: decide whether staging chunks require at-rest encryption (likely yes if hot disk is shared).
|
||||
- **Quota Enforcement**: should device/event caps be session-based (limit sessions) or final photo count (existing)? Combine both?
|
||||
- **Backward Compatibility**: decide when to retire legacy endpoint; temporarily keep `/upload` fallback behind feature flag.
|
||||
|
||||
---
|
||||
|
||||
## 6. Next Steps
|
||||
|
||||
- Finalise design choices (S3 vs local) with Media Services.
|
||||
- Break down into implementation tasks (backend API, frontend uploader, cron cleanup, observability).
|
||||
- Schedule dry run in staging with large sample files (20+ MB) and monitor memory/CPU.
|
||||
- Update SEC-MS-02 ticket checklist with deliverables above.
|
||||
@@ -9,31 +9,56 @@ Raise the baseline security posture across guest APIs, checkout, media storage,
|
||||
- Dual-key rollout for JWT signing with rotation runbook and monitoring.
|
||||
- Refresh-token revocation tooling (per device/IP) and anomaly alerts.
|
||||
- Device fingerprint/subnet allowances documented and configurable.
|
||||
- **Tickets**
|
||||
- `SEC-IO-01` — Generate dual-key rollout playbook + automation (Week 1). *(Runbook: `docs/deployment/oauth-key-rotation.md`; commands: `oauth:list-keys`, `oauth:prune-keys`)*
|
||||
- `SEC-IO-02` — Build refresh-token management UI + audit logs (Week 2). *(Filament console + audit trail added 2025-10-23)*
|
||||
- `SEC-IO-03` — Implement subnet/device matching configuration & tests (Week 3).
|
||||
|
||||
2. **Guest Join Tokens (Guest Platform)**
|
||||
- Store hashed tokens with irreversible lookups; migrate legacy data.
|
||||
- Add per-token usage analytics, alerting on spikes or expiry churn.
|
||||
- Extend gallery/photo rate limits (token + IP) and surface breach telemetry in storage dashboards.
|
||||
- Extend gallery/photo rate limits (token + IP) and surface breach telemetry in storage dashboards.
|
||||
- **Tickets**
|
||||
- `SEC-GT-01` — Hash join tokens + data migration script (Week 1).
|
||||
- `SEC-GT-02` — Implement token analytics + Grafana dashboard (Week 2). *(Logging + Filament summaries delivered 2025-10-23; monitoring dashboard still pending)*
|
||||
- `SEC-GT-03` — Tighten gallery/photo rate limits + alerting (Week 3).
|
||||
|
||||
3. **Public API Resilience (Core API)**
|
||||
- Serve signed asset URLs instead of raw storage paths; expire appropriately.
|
||||
- Document incident response runbooks and playbooks for abuse mitigation.
|
||||
- Add synthetic monitors for `/api/v1/gallery/*` and upload endpoints.
|
||||
- **Tickets**
|
||||
- `SEC-API-01` — Signed URL middleware + asset migration (Week 1).
|
||||
- `SEC-API-02` — Incident response playbook draft + review (Week 2). *(Runbook: `docs/deployment/public-api-incident-playbook.md`, added 2025-10-23)*
|
||||
- `SEC-API-03` — Synthetic monitoring + alert config (Week 3).
|
||||
|
||||
4. **Media Pipeline & Storage (Media Services)**
|
||||
- Integrate antivirus/EXIF scrubbers and streaming upload paths to avoid buffering.
|
||||
- Verify checksum integrity on hot → archive transfers with alert thresholds.
|
||||
- Surface storage target health (capacity, latency) in Super Admin dashboards.
|
||||
- **Tickets**
|
||||
- `SEC-MS-01` — AV + EXIF scrubber worker integration (Week 1). *(Job: `ProcessPhotoSecurityScan`, queue: `media-security`)*
|
||||
- `SEC-MS-02` — Streaming upload refactor + tests (Week 2). *(Requirements draft: `docs/todo/media-streaming-upload-refactor.md`, 2025-10-23)*
|
||||
- `SEC-MS-03` — Checksum validation + alert thresholds (Week 3).
|
||||
- `SEC-MS-04` — Storage health widget in Super Admin (Week 4).
|
||||
|
||||
5. **Payments & Webhooks (Billing)**
|
||||
- Link Stripe/PayPal webhooks to checkout sessions with idempotency locks.
|
||||
- Add signature freshness validation + retry policies for provider outages.
|
||||
- Pipe failed capture events into credit ledger audits and operator alerts.
|
||||
- **Tickets**
|
||||
- `SEC-BILL-01` — Checkout session linkage + idempotency locks (Week 1).
|
||||
- `SEC-BILL-02` — Signature freshness + retry policy implementation (Week 2).
|
||||
- `SEC-BILL-03` — Failed capture notifications + ledger hook (Week 3).
|
||||
|
||||
6. **Frontend & CSP (Marketing Frontend)**
|
||||
- Replace `unsafe-inline` allowances with nonce/hash policies for Stripe + Matomo.
|
||||
- Gate analytics script injection behind consent with localised disclosures.
|
||||
- Broaden cookie banner layout to surface GDPR/legal copy clearly.
|
||||
- **Tickets**
|
||||
- `SEC-FE-01` — CSP nonce/hashing utility + rollout (Week 1).
|
||||
- `SEC-FE-02` — Consent-gated analytics loader refactor (Week 2).
|
||||
- `SEC-FE-03` — Cookie banner UX update + localisation (Week 3).
|
||||
|
||||
## Deliverables
|
||||
- Updated docs (`docs/prp/09-security-compliance.md`, runbooks) with ownership & SLAs.
|
||||
|
||||
Reference in New Issue
Block a user