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>
This commit is contained in:
105
Claude.md
105
Claude.md
@@ -17,6 +17,24 @@
|
||||
- Comment Edit/Delete (owner or admin can modify their comments)
|
||||
- Markdown Tables Support, Auto-linking URLs in Comments
|
||||
|
||||
**Security Features** (January 2026):
|
||||
- CSP with nonce-based script execution (no unsafe-inline)
|
||||
- IP-based rate limiting (prevents session bypass attacks)
|
||||
- Visibility checks on attachment downloads
|
||||
- Unique ticket ID generation with collision prevention
|
||||
- Internal visibility requires groups validation
|
||||
|
||||
## Design Decisions
|
||||
|
||||
**Not Planned / Out of Scope**:
|
||||
- Email integration - Discord webhooks are the notification method for this system
|
||||
- SLA management - Not required for internal infrastructure use
|
||||
- Time tracking - Out of scope for current requirements
|
||||
- OAuth2/External identity providers - Authelia is the only approved SSO method
|
||||
- GraphQL API - REST API is sufficient for current needs
|
||||
|
||||
**Wiki Documentation**: https://wiki.lotusguild.org/en/Services/service-tinker-tickets
|
||||
|
||||
## Project Overview
|
||||
|
||||
Tinker Tickets is a feature-rich, self-hosted ticket management system built for managing data center infrastructure issues. It features SSO integration with Authelia/LLDAP, workflow management, Discord notifications, and a retro terminal-style web interface.
|
||||
@@ -54,6 +72,7 @@ Controllers → Models → Database
|
||||
│ ├── check_duplicates.php # GET: Check for duplicate tickets
|
||||
│ ├── delete_attachment.php # POST/DELETE: Delete attachment
|
||||
│ ├── delete_comment.php # POST: Delete comment (owner/admin)
|
||||
│ ├── download_attachment.php # GET: Download attachment (with visibility check)
|
||||
│ ├── export_tickets.php # GET: Export tickets to CSV/JSON
|
||||
│ ├── generate_api_key.php # POST: Generate API key (admin)
|
||||
│ ├── get_template.php # GET: Fetch ticket template
|
||||
@@ -93,8 +112,8 @@ Controllers → Models → Database
|
||||
├── middleware/
|
||||
│ ├── AuthMiddleware.php # Authelia SSO integration
|
||||
│ ├── CsrfMiddleware.php # CSRF protection
|
||||
│ ├── RateLimitMiddleware.php # API rate limiting
|
||||
│ └── SecurityHeadersMiddleware.php # Security headers
|
||||
│ ├── RateLimitMiddleware.php # Session + IP-based rate limiting
|
||||
│ └── SecurityHeadersMiddleware.php # CSP with nonces, security headers
|
||||
├── models/
|
||||
│ ├── ApiKeyModel.php # API key generation/validation
|
||||
│ ├── AuditLogModel.php # Audit logging + timeline
|
||||
@@ -152,25 +171,41 @@ All admin pages are accessible via the **Admin dropdown** in the dashboard heade
|
||||
|
||||
### Core Tables
|
||||
|
||||
- `tickets` - Core ticket data with assignment and visibility
|
||||
- `ticket_comments` - Markdown-supported comments
|
||||
- `ticket_attachments` - File attachment metadata
|
||||
- `ticket_dependencies` - Ticket relationships
|
||||
- `users` - User accounts synced from LLDAP (includes groups)
|
||||
- `user_preferences` - User settings and preferences
|
||||
- `audit_log` - Complete audit trail
|
||||
- `status_transitions` - Workflow configuration
|
||||
- `ticket_templates` - Reusable ticket templates
|
||||
- `recurring_tickets` - Scheduled ticket definitions
|
||||
- `custom_field_definitions` - Custom field schemas
|
||||
- `custom_field_values` - Custom field data per ticket
|
||||
- `saved_filters` - User-saved dashboard filters
|
||||
- `bulk_operations` - Bulk operation tracking
|
||||
- `api_keys` - API key storage with hashes
|
||||
| Table | Description |
|
||||
|-------|-------------|
|
||||
| `tickets` | Core ticket data with assignment, visibility, and tracking |
|
||||
| `ticket_comments` | Markdown-supported comments with user_id reference |
|
||||
| `ticket_attachments` | File attachment metadata |
|
||||
| `ticket_dependencies` | Ticket relationships (blocks, blocked_by, relates_to, duplicates) |
|
||||
| `users` | User accounts synced from LLDAP (includes groups) |
|
||||
| `user_preferences` | User settings and preferences |
|
||||
| `audit_log` | Complete audit trail with indexed queries |
|
||||
| `status_transitions` | Workflow configuration |
|
||||
| `ticket_templates` | Reusable ticket templates |
|
||||
| `recurring_tickets` | Scheduled ticket definitions |
|
||||
| `custom_field_definitions` | Custom field schemas per category |
|
||||
| `custom_field_values` | Custom field data per ticket |
|
||||
| `saved_filters` | User-saved dashboard filters |
|
||||
| `bulk_operations` | Bulk operation tracking |
|
||||
| `api_keys` | API key storage with hashed keys |
|
||||
|
||||
### Ticket Visibility Columns
|
||||
- `visibility` - ENUM('public', 'internal', 'confidential')
|
||||
- `visibility_groups` - VARCHAR(500) comma-separated group names
|
||||
### tickets Table Key Columns
|
||||
|
||||
| Column | Type | Description |
|
||||
|--------|------|-------------|
|
||||
| `ticket_id` | varchar(9) | Unique 9-digit identifier |
|
||||
| `visibility` | enum | 'public', 'internal', 'confidential' |
|
||||
| `visibility_groups` | varchar(500) | Comma-separated group names (for internal) |
|
||||
| `created_by` | int | Foreign key to users |
|
||||
| `assigned_to` | int | Foreign key to users (nullable) |
|
||||
| `updated_by` | int | Foreign key to users |
|
||||
| `priority` | int | 1-5 (1=Critical, 5=Minimal) |
|
||||
| `status` | varchar(20) | Open, Pending, In Progress, Closed |
|
||||
|
||||
### Indexed Columns (for performance)
|
||||
|
||||
- `tickets`: ticket_id (unique), status, priority, created_at, created_by, assigned_to, visibility
|
||||
- `audit_log`: user_id, action_type, entity_type, created_at
|
||||
|
||||
## Dashboard Features
|
||||
|
||||
@@ -187,9 +222,11 @@ All admin pages are accessible via the **Admin dropdown** in the dashboard heade
|
||||
## Ticket Visibility Levels
|
||||
|
||||
- **Public**: All authenticated users can view
|
||||
- **Internal**: Only users in specified groups can view
|
||||
- **Internal**: Only users in specified groups can view (groups required)
|
||||
- **Confidential**: Only creator, assignee, and admins can view
|
||||
|
||||
**Important**: Internal visibility requires at least one group to be specified. Attempting to create/update a ticket with internal visibility but no groups will fail validation.
|
||||
|
||||
## Important Notes for AI Assistants
|
||||
|
||||
1. **Session format**: `$_SESSION['user']['user_id']` (not `$_SESSION['user_id']`)
|
||||
@@ -205,6 +242,9 @@ All admin pages are accessible via the **Admin dropdown** in the dashboard heade
|
||||
11. **Session in APIs**: RateLimitMiddleware starts session; don't call session_start() again
|
||||
12. **Database collation**: Use `utf8mb4_general_ci` (not unicode_ci) for new tables
|
||||
13. **Ticket ID extraction**: Use `getTicketIdFromUrl()` helper in JS files
|
||||
14. **CSP Nonces**: All inline scripts require `nonce="<?php echo $nonce; ?>"` attribute
|
||||
15. **Visibility validation**: Internal visibility requires groups; code validates this
|
||||
16. **Rate limiting**: Both session-based AND IP-based limits are enforced
|
||||
|
||||
## File Reference Quick Guide
|
||||
|
||||
@@ -212,14 +252,31 @@ All admin pages are accessible via the **Admin dropdown** in the dashboard heade
|
||||
|------|---------|
|
||||
| `index.php` | Main router for all routes |
|
||||
| `api/update_ticket.php` | Ticket updates with workflow + visibility |
|
||||
| `models/TicketModel.php` | Ticket CRUD, visibility filtering |
|
||||
| `api/download_attachment.php` | File downloads with visibility check |
|
||||
| `api/bulk_operation.php` | Bulk operations with visibility filtering |
|
||||
| `models/TicketModel.php` | Ticket CRUD, visibility filtering, collision-safe ID generation |
|
||||
| `models/ApiKeyModel.php` | API key generation and validation |
|
||||
| `middleware/SecurityHeadersMiddleware.php` | CSP headers with nonce generation |
|
||||
| `middleware/RateLimitMiddleware.php` | Session + IP-based rate limiting |
|
||||
| `assets/js/dashboard.js` | Dashboard UI, kanban, sidebar, bulk actions |
|
||||
| `assets/js/ticket.js` | Ticket UI, visibility editing |
|
||||
| `assets/js/markdown.js` | Markdown parsing + ticket linking |
|
||||
| `assets/js/markdown.js` | Markdown parsing + ticket linking (XSS-safe) |
|
||||
| `assets/css/dashboard.css` | Terminal styling, kanban, sidebar |
|
||||
|
||||
## Security Implementations
|
||||
|
||||
| Feature | Implementation |
|
||||
|---------|---------------|
|
||||
| SQL Injection | All queries use prepared statements with parameter binding |
|
||||
| XSS Prevention | HTML escaped in markdown parser, CSP with nonces |
|
||||
| CSRF Protection | Token-based with constant-time comparison |
|
||||
| Session Security | Fixation prevention, secure cookies, timeout |
|
||||
| Rate Limiting | Session-based + IP-based (file storage) |
|
||||
| File Security | Path traversal prevention, MIME validation |
|
||||
| Visibility | Enforced on views, downloads, and bulk operations |
|
||||
|
||||
## Repository
|
||||
|
||||
- **Gitea**: https://code.lotusguild.org/LotusGuild/tinker_tickets
|
||||
- **Production**: http://t.lotusguild.org
|
||||
- **Production**: https://t.lotusguild.org
|
||||
- **Wiki**: https://wiki.lotusguild.org/en/Services/service-tinker-tickets
|
||||
|
||||
Reference in New Issue
Block a user