Files
tinker_tickets/.env.example
T
jaredandClaude Sonnet 5 863f84f37e
Lint / PHP (phpcs PSR-12) (push) Successful in 18s
Lint / JS (eslint) (push) Successful in 7s
Lint / PHP requirements (version + extensions) (push) Successful in 28s
Lint / Notify on failure (push) Skipped
Security / PHP Security (semgrep) (push) Successful in 1m56s
Lint / Deploy (push) Successful in 3s
Switch LDAP avatar lookups to LDAPS (#95)
api/user_avatar.php connected via ldap://$ldapHost:$ldapPort — never
ldaps://, and there was no ldap_start_tls() call anywhere in the
codebase. LDAP_BIND_PW was sent over the wire unencrypted on every
avatar fetch.

Switched to ldaps://, and changed LDAP_HOST/LDAP_PORT's defaults to
ldap.lotusguild.org:6360 (lldap's LDAPS listener) instead of the bare
IP on port 3890 (plaintext). PHP's ldap extension verifies the server
cert's hostname by default, so a bare IP won't validate against the
LDAPS cert (issued for *.lotusguild.org) — LDAP_HOST has to be a
hostname the cert covers. This is deliberately not configurable back to
plaintext ldap://.

Infra change (pve-infra, separate repo/commit): added a Pi-hole
split-horizon override so ldap.lotusguild.org resolves internally to
the real LDAP server's LAN IP — its existing public DNS record points
elsewhere (an unrelated host), and there was no internal-only DNS entry
for it before this.

Verified against the real lldap server (pct 147, LDAPS on 6360, a live
Let's Encrypt *.lotusguild.org cert): confirmed the Pi-hole override
resolves correctly from hosts using it as their resolver, then ran the
exact ldap_connect/ldap_bind sequence via `php -r` directly on the
production tinker_tickets host (10.10.10.45) with a deliberately wrong
bind password — got "Invalid credentials" (a real LDAP protocol
response), not a transport/TLS error, proving the full connect + TLS
handshake + hostname verification + bind path works end-to-end in the
actual deployment environment.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0117oBw2jN4kALYeS8HPq4zV
2026-09-12 00:56:00 -04:00

97 lines
4.2 KiB
Bash

; Tinker Tickets Environment Configuration
; Copy this file to .env and fill in your values
;
; NOTE: This file is parsed with PHP's parse_ini_file. Any value containing
; special characters -- #, ;, =, quotes, spaces, etc. -- MUST be wrapped in
; double quotes, e.g. DB_PASS="p@ss;word#1". The application now fails loudly
; -- dies with a clear error -- if the .env file cannot be parsed, so an
; unquoted special character will take the whole app down rather than
; silently using a wrong value.
;
; Comments in this file use ";" rather than "#": PHP's ini parser treats "#"
; comments as fragile -- punctuation like parentheses or quotes inside a "#"
; comment can produce a syntax error even though the line is meant to be
; inert, silently breaking every value below it. ";" comments don't have this
; problem, so keep using ";" for any comment added to this file.
; Database Configuration
DB_HOST=10.10.10.50
DB_USER=tinkertickets
DB_PASS=your_password_here
DB_NAME=ticketing_system
; Matrix Webhook (optional - for notifications via matrix-hookshot)
; Set to your hookshot generic webhook URL, e.g.:
; https://matrix.lotusguild.org/webhook/uuid-goes-here
MATRIX_WEBHOOK_URL=
; Matrix users to @mention on every new ticket (comma-separated Matrix user IDs)
; e.g. @jared:matrix.lotusguild.org,@alice:matrix.lotusguild.org
MATRIX_NOTIFY_USERS=
; Matrix homeserver domain (used to build Matrix user IDs from LLDAP usernames)
MATRIX_DOMAIN=
; Synapse internal URL and admin token (used to resolve usernames -> Matrix IDs
; for watcher DMs)
SYNAPSE_ADMIN_URL=
SYNAPSE_ADMIN_TOKEN=
; Optional: send a Matrix notification on comments and/or assignments (0/1)
MATRIX_NOTIFY_COMMENTS=0
MATRIX_NOTIFY_ASSIGNMENTS=0
; Application Domain (required for Matrix webhook ticket links)
; Set this to your public domain, e.g. t.lotusguild.org
APP_DOMAIN=
; Allowed Hosts for HTTP_HOST validation (comma-separated)
; Include all domains that can access this application
ALLOWED_HOSTS=localhost,127.0.0.1
; ============================================================================
; REQUIRED FOR PRODUCTION -- READ BEFORE DEPLOYING -- TRUSTED_PROXIES
; ============================================================================
; Trusted reverse proxy IPs, comma-separated -- e.g. the Authelia/nginx proxy.
; Set this to the IP address(es) of your reverse proxy. Authelia forward-auth
; headers (Remote-User / Remote-Groups) and forwarded client IPs are only
; trusted when REMOTE_ADDR is in this list.
;
; Leaving this EMPTY disables reverse-proxy verification entirely: the app then
; trusts Remote-User / Remote-Groups headers from ANY source. If the PHP
; backend is reachable directly -- a misconfigured firewall rule, a container
; network accidentally exposing the port, SSRF from another internal service
; -- ANYONE can set Remote-User: admin themselves and fully impersonate any
; user, including an admin, with ZERO authentication. Only leave it empty when
; network topology guarantees PHP is reachable solely via the trusted proxy
; (e.g. local development), never in a real deployment.
;
; Exact IP match only (no CIDR). Example (single proxy): TRUSTED_PROXIES=10.10.10.27
; Example (multiple): TRUSTED_PROXIES=10.10.10.27,10.10.10.28
; ============================================================================
TRUSTED_PROXIES=
; Timezone (default: America/New_York)
TIMEZONE=America/New_York
; LDAP / lldap (for user avatar lookups). Connects over LDAPS — 6360 is
; lldap's default LDAPS port, NOT its plaintext port (3890), since
; LDAP_BIND_PW below would otherwise go over the wire unencrypted.
; LDAP_HOST must be a hostname matching the LDAPS cert (TLS hostname
; verification is not skipped), not a bare IP.
LDAP_ENABLED=true
LDAP_HOST=ldap.lotusguild.org
LDAP_PORT=6360
LDAP_BIND_DN="uid=tinker-tickets,ou=people,dc=example,dc=com"
LDAP_BIND_PW=
LDAP_BASE_DN="dc=example,dc=com"
LDAP_USER_BASE="ou=people,dc=example,dc=com"
; How long to cache avatar images locally (seconds, default 3600)
AVATAR_CACHE_TTL=3600
; Session-based rate limits (requests per 60s window). These govern
; browser/session traffic on general and API endpoints respectively;
; Bearer-key API traffic is rate-limited separately, per API key.
RATE_LIMIT_DEFAULT=100
RATE_LIMIT_API=60