Commit Graph
23 Commits
Author SHA1 Message Date
jaredandClaude Opus 4.8 9941fd2dfa Address remaining review items: Synapse caching, cycle detection, cache/ratelimit/kanban
Security / PHP Security (semgrep) (push) Successful in 1m45s
Lint / Deploy (push) Successful in 3s
Lint / Notify on failure (push) Has been skipped
Lint / PHP (phpcs PSR-12) (push) Successful in 21s
Lint / JS (eslint) (push) Successful in 9s
Lint / PHP requirements (version + extensions) (push) Successful in 26s
- SynapseHelper: memoize username->Matrix-ID lookups per-request (incl. negative
  results) and add an overall time budget to resolveUsernames() plus a 2s connect
  timeout, so notifying N watchers with a slow/unreachable Synapse can't stall the
  request for N x 5s. (Chosen over async/queue per maintainer.)
- DependencyModel: fix cycle detection treating 'blocks' and 'blocked_by' as the
  same edge direction. They are inverse relationships (single row each, no mirror
  row), so the traversal now walks a unified precedence graph (blocks: ticket->
  depends_on; blocked_by: depends_on->ticket) and wouldCreateCycle normalizes the
  new edge's direction. Prevents both false-positive and missed cycles.
- CacheHelper: anchor prefix-delete to exact key boundaries (bare prefix or
  prefix + '_' + md5) so delete('workflow') can't wipe a 'workflow_rules' cache.
- RateLimitMiddleware: hold an exclusive flock across the per-IP counter's
  read-modify-write so concurrent requests can't both read N and write N+1
  (undercounting past the limit). Fails open if the file can't be locked.
- dashboard.js: kanban status update now uses lt.api.post (per no-raw-fetch
  convention) and reverts the card AND the optimistic column counts on failure
  (the old raw-fetch catch left the card moved without reverting).
- BulkOperationsModel: document that bulk_status/bulk_close intentionally bypass
  workflow transition validation (admin override, by design).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:55:50 -04:00
jaredandClaude Opus 4.8 4164f85051 Fix bugs found in second multi-agent review
Security / PHP Security (semgrep) (push) Successful in 1m14s
Lint / Deploy (push) Successful in 3s
Lint / PHP (phpcs PSR-12) (push) Successful in 19s
Lint / JS (eslint) (push) Successful in 8s
Lint / PHP requirements (version + extensions) (push) Successful in 24s
Lint / Notify on failure (push) Has been skipped
XSS / security:
- markdown.js: sanitize footnote labels to a safe slug before using them in
  id/href attributes. Labels are captured before the HTML-escape pass, so a
  label like x"><img onerror=...> broke out → stored XSS (the earlier quote-
  escape fix didn't cover this path). Verified neutralized.
- RateLimitMiddleware: only trust X-Forwarded-For / X-Real-IP when REMOTE_ADDR
  is a configured trusted proxy, and use the rightmost (proxy-appended) entry.
  Previously any client could rotate XFF to escape the per-IP rate limit.
- .env.example: document TRUSTED_PROXIES so fresh deploys aren't fail-open on
  the Authelia forward-auth spoofing protection.

Correctness:
- notifications.php: my previous assigned-to LIKE fix anchored only on '}', so
  BULK assignments (logged {"assigned_to":N,"bulk_operation_id":..}) produced
  no "assigned to you" notification — now matches both '}' and ',' delimiters.
- notifications.php: implement the documented @mention notifications (query
  action_type='mention' rows for the current user); they were never delivered.
- NotificationHelper::notifyWatchers: guard unchecked prepare() so a missing
  ticket_watchers table can't fatal the request after its DB write committed.
- AuditLogModel::getTicketTimeline: JSON_UNQUOTE the extracted ticket_id so
  comment events actually match (string vs JSON-number comparison never did).
- AuditLogModel/audit_log.php: CSV export no longer silently truncates to the
  1000-row UI cap; uses a dedicated higher export limit.
- DashboardView: quick-preview drawer read .ticket-link from the title cell
  (which has none), so the title was always blank — use the cell text.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 12:00:36 -04:00
jaredandClaude Opus 4.8 b2c19745eb Add trusted-proxy auth hardening + PHP requirements checks
Lint / PHP (phpcs PSR-12) (push) Successful in 20s
Lint / JS (eslint) (push) Successful in 11s
Lint / PHP requirements (version + extensions) (push) Successful in 52s
Security / PHP Security (semgrep) (push) Successful in 2m6s
Lint / Deploy (push) Successful in 13s
Lint / Notify on failure (push) Has been skipped
Trusted-proxy hardening (defense-in-depth for Authelia forward-auth):
- AuthMiddleware now only honors Remote-* identity headers when REMOTE_ADDR
  is in a configured TRUSTED_PROXIES allowlist; otherwise it refuses with 403
  and logs an 'untrusted_proxy' security event. Previously anything that could
  reach PHP directly could spoof Remote-User/Remote-Groups and log in as admin.
- New config TRUSTED_PROXIES (comma-separated, from .env). Empty = enforcement
  off, so this is backward compatible until the allowlist is set on a host.

Requirements checks (so a PHP upgrade dropping an extension can't silently
break features like avatars again):
- config/requirements.php: single source of truth for min PHP version and
  required extensions (ldap, mysqli, curl, mbstring, fileinfo, json).
- scripts/check_requirements.php: CI script that fails the build if the
  environment doesn't satisfy them.
- New 'requirements' CI job installs those extensions and runs the check;
  deploy now depends on it.
- api/health.php: adds php_extensions + php_version checks so production
  monitoring surfaces the drift (returns 503 if a required extension is gone).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-30 10:22:53 -04:00
jared c90bdc8ac8 style: auto-fix 1340 phpcs PSR-12 violations via phpcbf; exclude MissingNamespace and SideEffects
Lint / PHP (phpcs PSR-12) (push) Failing after 29s
Lint / JS (eslint) (push) Successful in 12s
2026-04-13 20:56:10 -04:00
jaredandClaude Sonnet 4.6 50e6ee749e Fix image rendering in markdown comments
- markdown.js: add renderMarkdownComments() called on DOMContentLoaded to
  process [data-markdown] elements that were never being rendered on page load
- CSP: allow https: in img-src so external images in markdown aren't blocked

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 00:05:37 -04:00
jaredandClaude Sonnet 4.6 ac05b212b2 Fix performAdvancedSearch ReferenceError, settings save, sort reset, notifications 500, CSP
DashboardView.php: wrap performAdvancedSearch in a closure so it is
resolved at event-fire time rather than listener-registration time
(advanced-search.js loads later via pageScripts so the bare identifier
reference caused ReferenceError).

DashboardView.php: reset sort URL to page=1 so sorting all pages
instead of staying on the current page.

dashboard.js: add missing save-settings and close-settings cases to
the click delegation handler (were removed in a prior session under
the assumption they were in dashboard.js, but they were not).

notifications.php: replace JSON_EXTRACT-based comment join (not
universally supported) with a two-step PHP filter: fetch owner/watcher
ticket IDs first, then filter raw comment rows in PHP. Also fix the
status change LIKE pattern to match the actual logTicketUpdate format
{"status": {"from": ..., "to": ...}}.

SecurityHeadersMiddleware.php: add https://cdn.jsdelivr.net to
connect-src so Chart.js source maps load without CSP violations.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 10:53:06 -04:00
jaredandClaude Sonnet 4.6 04b019a8e1 feat: Chart.js donut/bar charts, Flatpickr dates, skeleton loaders, CSP update
- DashboardView: Charts row with 3 panels (priority donut, status donut, category bar)
  using Chart.js from CDN; data passed inline from PHP stats; TDS color palette
- DashboardView: Flatpickr date picker on advanced search date fields with TDS theme overrides
- dashboard.js: showTableSkeleton() shows lt-skeleton-row during filter-triggered reloads
  and auto-refresh; called before all location.reload() with delay
- dashboard.css: Flatpickr TDS theme overrides (dark BG, monospace font, TDS accent colors)
- SecurityHeadersMiddleware: Added cdn.jsdelivr.net to script-src and style-src CSP
  to allow Chart.js and Flatpickr from CDN

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 17:45:02 -04:00
jaredandClaude Sonnet 4.6 e6b6a2a88c Security/correctness: visibility filtering, Content-Type headers, group validation
- TicketModel::getAllTickets() now accepts optional $user param and applies
  getVisibilityFilter() so non-admin users cannot see internal/confidential
  tickets they lack access to from the dashboard listing
- DashboardController passes $GLOBALS['currentUser'] to getAllTickets()
- clone_ticket.php: move Content-Type header to top so all error paths send
  correct JSON content type
- AuthMiddleware: filter group names from HTTP header to [a-z0-9_-] only,
  preventing header injection via malformed group names
- add_comment.php: return HTTP 201 on success, 500 in catch block
- update_comment.php, delete_comment.php: return 500 in catch blocks

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 18:23:16 -04:00
jaredandClaude Sonnet 4.6 f983269f93 Fix file upload security, bind_param mismatch, and cookie flags
- upload_attachment.php: derive stored file extension from validated MIME type
  instead of user-supplied filename, preventing executable extension attacks
  (e.g. a PHP file renamed to evil.txt would now be stored as .txt)
- CustomFieldModel.php: fix bind_param type string in updateDefinition()
  'sssssiiiii' (10 chars) → 'sssssiiii' (9 chars) to match 9 SQL placeholders
- RateLimitMiddleware.php: replace MD5 with SHA256 for rate limit file hashing
- user_preferences.php: add httponly, secure, samesite=Lax flags to ticketsPerPage
  cookie to prevent XSS/CSRF cookie theft

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 18:14:18 -04:00
jaredandClaude Sonnet 4.6 2e450dc01d Apply web_template gap analysis improvements (P1-P3)
P1-A: Fix CSP - add fonts.googleapis.com to style-src, fonts.gstatic.com to font-src
P1-B: CSRF token rotation - add rotateToken() to CsrfMiddleware; bootstrap.php rotates
      after successful validation and stores in $GLOBALS['_new_csrf_token']; add
      apiRespond() helper to append token to responses; lt.api interceptor in
      layout_footer.php auto-updates window.CSRF_TOKEN from responses
P1-C: Styled 403/404 error views with TDS layout instead of raw text; index.php now
      uses requireAdmin() helper eliminating 7 duplicated guard blocks (P3-D)
P2-A: Remove duplicate JS-generated keyboard help modal from keyboard-shortcuts.js;
      '?' key now routes to static #lt-keys-help modal in footer
P2-B: Asset versioning driven by config ASSET_VERSION key; base.css and base.js get
      ?v= cache-busting in layout_header.php
P2-C: Add data-theme="dark" to <html> tag to prevent FOUC on light-mode users
P2-E: Escape status value in dashboard.js hover preview class attribute via lt.escHtml()
P2-F: Replace bespoke showLoadingOverlay() with lt-spinner / lt-loading-text from
      base.css; add .lt-loading-overlay wrapper CSS to dashboard.css
P2-G: Add keyboard-shortcuts.js to all 7 admin views so J/K nav and ? help work
P3-A: APP_NAME, APP_SUBTITLE, APP_VERSION driven from config.php; layout header/footer
      use config values instead of hardcoded strings
P3-G: Replace custom initTableSorting() with lt.sortTable.init() which manages aria-sort

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-29 17:02:40 -04:00
jaredandClaude Opus 4.6 bcc163bc77 Audit fixes: security, dead code removal, API consolidation, JS dedup
Security:
- Fix IDOR in delete/update comment (add ticket visibility check)
- XSS defense-in-depth in DashboardView active filters
- Replace innerHTML with DOM construction in toast.js
- Remove redundant real_escape_string in check_duplicates
- Add rate limiting to get_template, download_attachment, audit_log,
  saved_filters, user_preferences endpoints

Bug fixes:
- Session timeout now reads from config instead of hardcoded 18000
- TicketController uses $GLOBALS['config'] instead of duplicate .env parsing
- Add DISCORD_WEBHOOK_URL to centralized config
- Cleanup script uses hashmap for O(1) ticket ID lookups

Dead code removal (~100 lines):
- Remove dead getTicketComments() from TicketModel (wrong bind_param type)
- Remove dead getCategories()/getTypes() from DashboardController
- Remove ~80 lines dead Discord webhook code from update_ticket API

Consolidation:
- Create api/bootstrap.php for shared API setup (auth, CSRF, rate limit)
- Convert 6 API endpoints to use bootstrap
- Extract escapeHtml/getTicketIdFromUrl into shared utils.js
- Batch save for user preferences (1 request instead of 7)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-11 14:50:06 -05:00
jaredandClaude Opus 4.5 5b2a2c271e Add security logging, domain validation, and output helpers
- Add authentication failure logging to AuthMiddleware (session expiry,
  access denied, unauthenticated access attempts)
- Add UrlHelper for secure URL generation with host validation against
  configurable ALLOWED_HOSTS whitelist
- Add OutputHelper with consistent XSS-safe escaping functions (h, attr,
  json, url, css, truncate, date, cssClass)
- Add validation to AuditLogModel query parameters (pagination limits,
  date format validation, action/entity type validation, IP sanitization)
- Add APP_DOMAIN and ALLOWED_HOSTS configuration options

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 18:51:16 -05:00
jaredandClaude Opus 4.5 7575d6a277 Add performance, security, and reliability improvements
- Consolidate all 20 API files to use centralized Database helper
- Add optimistic locking to ticket updates to prevent concurrent conflicts
- Add caching to StatsModel (60s TTL) for dashboard performance
- Add health check endpoint (api/health.php) for monitoring
- Improve rate limit cleanup with cron script and efficient DirectoryIterator
- Enable rate limit response headers (X-RateLimit-*)
- Add audit logging for workflow transitions
- Log Discord webhook failures instead of silencing
- Fix visibility check on export_tickets.php
- Add database migration system with performance indexes
- Fix cron recurring tickets to use assignTicket method

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 14:39:13 -05:00
jaredandClaude Opus 4.5 c3f7593f3c Harden CSP by removing unsafe-inline for scripts
Refactored all inline event handlers (onclick, onchange, onsubmit) to use
addEventListener with data-action attributes and event delegation pattern.

Changes:
- views/*.php: Replaced inline handlers with data-action attributes
- views/admin/*.php: Same refactoring for all admin views
- assets/js/dashboard.js: Added event delegation for bulk/quick action modals
- assets/js/ticket.js: Added event delegation for dynamic elements
- assets/js/markdown.js: Refactored toolbar button handlers
- assets/js/keyboard-shortcuts.js: Refactored modal close button
- SecurityHeadersMiddleware.php: Enabled strict CSP with nonces

The CSP now uses script-src 'self' 'nonce-{nonce}' instead of 'unsafe-inline',
significantly improving XSS protection.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 13:15:55 -05:00
jaredandClaude Opus 4.5 37be81b3e2 Add PHP 7.4+ type hints to helpers, models, and middleware
Added strict typing with parameter types, return types, and property
types across all core classes:
- helpers: Database, ErrorHandler, CacheHelper
- models: TicketModel, UserModel, WorkflowModel, TemplateModel, UserPreferencesModel
- middleware: RateLimitMiddleware, CsrfMiddleware, SecurityHeadersMiddleware

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 11:04:36 -05:00
jaredandClaude Opus 4.5 1101558fca Remove nonce from CSP to allow unsafe-inline to work
Browsers ignore 'unsafe-inline' when a nonce is present. Reverting to
unsafe-inline only until all inline handlers are refactored.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 10:46:06 -05:00
jaredandClaude Opus 4.5 55209e0b05 Fix CSP blocking inline handlers - add unsafe-inline fallback
- Refactored TicketView.php to use event listeners instead of onclick
- Added unsafe-inline to CSP as fallback for legacy handlers in other views
- TODO: Complete refactoring of DashboardView and admin views

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 10:42:09 -05:00
jaredandClaude Opus 4.5 fa40010287 Security hardening and performance improvements
- Add visibility check to attachment downloads (prevents unauthorized access)
- Fix ticket ID collision with uniqueness verification loop
- Harden CSP: replace unsafe-inline with nonce-based script execution
- Add IP-based rate limiting (supplements session-based)
- Add visibility checks to bulk operations
- Validate internal visibility requires groups
- Optimize user activity query (JOINs vs subqueries)
- Update documentation with design decisions and security info

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 20:27:15 -05:00
jaredandClaude Opus 4.5 6d03f9c89b fix: Session auth, sidebar toggle, and dependencies table
- Change session.cookie_samesite from Strict to Lax for Authelia compatibility
- Redesign sidebar toggle with separate collapse/expand buttons
- Add script to create missing ticket_dependencies table
- Add .env.example template
- Add check for missing .env with helpful error message

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-23 21:16:29 -05:00
jaredandClaude Opus 4.5 be505b7312 Implement comprehensive improvement plan (Phases 1-6)
Security (Phase 1-2):
- Add SecurityHeadersMiddleware with CSP, X-Frame-Options, etc.
- Add RateLimitMiddleware for API rate limiting
- Add security event logging to AuditLogModel
- Add ResponseHelper for standardized API responses
- Update config.php with security constants

Database (Phase 3):
- Add migration 014 for additional indexes
- Add migration 015 for ticket dependencies
- Add migration 016 for ticket attachments
- Add migration 017 for recurring tickets
- Add migration 018 for custom fields

Features (Phase 4-5):
- Add ticket dependencies with DependencyModel and API
- Add duplicate detection with check_duplicates API
- Add file attachments with AttachmentModel and upload/download APIs
- Add @mentions with autocomplete and highlighting
- Add quick actions on dashboard rows

Collaboration (Phase 5):
- Add mention extraction in CommentModel
- Add mention autocomplete dropdown in ticket.js
- Add mention highlighting CSS styles

Admin & Export (Phase 6):
- Add StatsModel for dashboard widgets
- Add dashboard stats cards (open, critical, unassigned, etc.)
- Add CSV/JSON export via export_tickets API
- Add rich text editor toolbar in markdown.js
- Add RecurringTicketModel with cron job
- Add CustomFieldModel for per-category fields
- Add admin views: RecurringTickets, CustomFields, Workflow,
  Templates, AuditLog, UserActivity
- Add admin APIs: manage_workflows, manage_templates,
  manage_recurring, custom_fields, get_users
- Add admin routes in index.php

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 09:55:01 -05:00
jaredandClaude Sonnet 4.5 e801eee6ee feat: Add session security and fixation prevention
Session security improvements in AuthMiddleware:

1. Secure Cookie Configuration:
   - HttpOnly flag prevents JavaScript access to session cookies
   - Secure flag requires HTTPS (protects from MITM)
   - SameSite=Strict prevents CSRF via cookie inclusion
   - Strict mode rejects uninitialized session IDs

2. Session Fixation Prevention:
   - session_regenerate_id(true) called after successful authentication
   - Old session ID destroyed, new one generated
   - Prevents attacker from using pre-set session ID

3. CSRF Token Regeneration:
   - New CSRF token generated on login
   - Ensures fresh token for each session

These changes protect against session hijacking, fixation, and
cross-site attacks while maintaining existing 5-hour timeout.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 16:23:09 -05:00
jaredandClaude Sonnet 4.5 f096766e5d feat: Add CSRF middleware and performance index migrations
- Create CsrfMiddleware.php with token generation and validation
- Add database indexes for ticket_comments and audit_log
- Includes rollback script for safe deployment

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-09 11:45:23 -05:00
jared 7b25ec1dd1 SSO Update :) 2026-01-01 15:40:32 -05:00