- In-app notifications: a bell in the top bar backed by Laravel's database
notification channel, alongside existing e-mail notifications (same
per-trigger toggle drives both; ticket links now correctly point into the
recipient's own area instead of always linking to the client view).
- Drag-and-drop attachments on every upload form, plus inline image
thumbnails in the message thread instead of a plain download link.
- Customer satisfaction (CSAT) rating: clients rate a closed ticket 1-5 stars
with an optional comment; shown read-only to operators, surfaced as a KPI
on the stats dashboard, and linked from the "ticket closed" e-mail.
- Saved queue views: operators can save/apply/delete named filter+sort+
column presets in the ticket queue and mark one as their default.
- Full-text search (MySQL FULLTEXT, portable LIKE fallback) across ticket
subject/body and reply message bodies, now also on the client's own ticket
list.
- Stats CSV export for the currently filtered ticket set.
- Optional BookStack knowledge-base integration (off by default): suggests
articles by category/subcategory while creating a ticket and in a separate
sidebar for operators on an existing ticket (with a copy-link button).
Configurable connection/SSL bypass/search-type filter, plus two
independent per-shelf allow-lists so nothing is ever searched until an
admin opts specific shelves in.
- Closed tickets no longer show in "Moje zgłoszenia"/"Nieprzypisane"/team
queue tabs, only under "Zamknięte" (matching how "Otwarte" already worked).
- Wired up the Admin > About "Wersja" field to config('app.version')/VERSION
in .env instead of a stale hardcoded string.
- Fixed: TicketService::setStatus() now checks a status's stage rather than
the literal key 'closed' to decide whether to fire the "ticket closed"
notification/stop the timer.
- Updated README/ARCHITECTURE/CHANGELOG/install/SECURITY docs and all three
wiki/ role guides for the above; documented a root-vs-www-data file
ownership gotcha in CLAUDE.md (running artisan commands via a plain
`docker exec` can leave root-owned Blade cache files that later break
recompilation for the www-data Apache process).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
65 lines
3.5 KiB
Markdown
65 lines
3.5 KiB
Markdown
# Security Policy
|
|
|
|
This is an internally-run production helpdesk (not an open-source project with a
|
|
public disclosure program). If you find a vulnerability affecting this
|
|
deployment, report it directly rather than opening a public GitHub issue:
|
|
|
|
- **Contact**: the address configured as `AUTHOR_CONTACT` in `src/.env`
|
|
(surfaced in the app under Admin > O aplikacji).
|
|
- Please include steps to reproduce and, if applicable, which role/area
|
|
(Client/Operator/Admin/API) is affected.
|
|
|
|
Do not test against the production instance beyond what's needed to demonstrate
|
|
the issue — no automated scanning, load testing, or bulk data extraction.
|
|
|
|
## Scope & sensitive data
|
|
|
|
This system holds real ticket content, user PII (names/emails, and anything
|
|
submitted in ticket bodies/custom fields), and LDAP/SMTP connection credentials.
|
|
Treat access to the `admin` area, the `settings` table, and any `.env` file as
|
|
credential-equivalent.
|
|
|
|
## Notable design points relevant to security review
|
|
|
|
- **Auth**: LDAP bind is the primary login path (`config/auth.php`,
|
|
`directorytree/ldaprecord-laravel`); a local fallback account
|
|
(`admin@example.com`, seeded — **must** have its password changed after
|
|
install, see [install.md](install.md)) exists for when LDAP is unavailable or
|
|
misconfigured.
|
|
- **Settings override**: Admin > Konfiguracja values in the `settings` table
|
|
override `.env` for LDAP/SMTP/session/timezone config at runtime (see
|
|
[ARCHITECTURE.md](ARCHITECTURE.md) — "Settings override"). This means a
|
|
compromised admin account can redirect LDAP/SMTP traffic without touching the
|
|
filesystem — restrict Admin-role accounts accordingly.
|
|
- **API**: Sanctum tokens are ability-scoped (`tickets:read`, `tickets:write`,
|
|
`dictionaries:read`, `users:read`) and issued per `ApiClient` via the admin
|
|
panel; rate-limited per-client (authenticated) or per-IP (unauthenticated) —
|
|
see `AppServiceProvider::configureApiRateLimiting()`.
|
|
- **Role model**: roles are checked via `EnsureRole` middleware against
|
|
`$user->roles`; there's no per-object ACL beyond team-based ticket visibility
|
|
(`Ticket::scopeVisibleToOperator`) — any change to that scope directly changes
|
|
what an operator can see across teams.
|
|
- **Attachments**: size/count/type limits are admin-configurable
|
|
(`attachment_max_size_kb`, `attachment_allowed_types`, etc. in `Settings`) —
|
|
don't bypass them when adding new upload paths.
|
|
- **TLS**: production traffic terminates at Traefik with a private CA
|
|
certificate (not publicly trusted) — this is expected for this deployment, not
|
|
a misconfiguration.
|
|
- **BookStack integration** (`App\Services\BookStackClient`, optional, off by
|
|
default): the only outbound HTTP client in the codebase. The target
|
|
`bookstack_base_url` and the SSL-verification bypass (`bookstack_verify_ssl`)
|
|
are both admin-configurable — restrict Admin-role accounts accordingly, same
|
|
reasoning as the LDAP/SMTP settings override above (a compromised admin
|
|
account could point it at an arbitrary host, or disable TLS verification
|
|
against one). The API token secret is stored encrypted (same as the LDAP
|
|
bind/SMTP passwords). Nothing is ever searched/suggested until an admin
|
|
explicitly allow-lists specific BookStack shelves — the default (no shelves
|
|
allowed) returns no results without making any outbound request.
|
|
|
|
## Dependencies
|
|
|
|
No automated dependency-vulnerability scanning (e.g. Dependabot, `composer
|
|
audit` in CI) is currently configured — there is no CI pipeline for this repo at
|
|
all (see [TESTING.md](TESTING.md)). Run `composer audit` / `npm audit` manually
|
|
before major dependency bumps.
|