Commit Graph

21 Commits

Author SHA1 Message Date
1979cab5ec feat: anonymous ticket tracking as standalone public page
- tracking: promoted to public route (before auth gate) with full single-ticket view
- backend: GET /tickets/tracking/:id validates cookie tracking_token, returns responses/attachments/transfers
- tracking.js: rewrite - token list + chat-flow detail (player/staff bubbles) + processing log + anon reply
- ticket-create: anon submit now lands on #/tracking instead of home
- home: tracking tab navigates to standalone page
2026-08-23 17:50:42 +08:00
c5ceba7cf0 fix: data-action buttons, sources enabled, email notify, ticket detail single-page
- app.js: mount page objects via inline script (CSP blocks eval → data-action buttons dead)
- app.js: add tickets list entry to sidebar nav (admin could not find claimed tickets)
- sources: GET /sources?manage=1 returns enabled field for admin view
- mailer: sendNotifyEmail consumes email-type notification_configs (webhook_url = recipients)
- tickets: trigger notify on created/claimed/transferred/updated/status-change
- notifications: email type shows recipient field, validates email list
- ticket-detail: single-page chat flow (player/staff bubbles) + processing log timeline
- css: chat bubble styles
2026-08-22 20:00:12 +08:00
da26dd5f69 fix: anonymous ticket submit 500 - undefined rgu param
Root cause: after UID internalization, anonymous form no longer
sends reporter_game_uid, so req.body.reporter_game_uid was
undefined. The countRow query (outside try/catch) passed undefined
to mysql2 which throws 'Bind parameters must not contain undefined'
- escaping to the global error middleware -> 500 '服务器内部错误'
for ALL anonymous ticket types (appeal/report/suggestion).

Fix: default rgn/rgu to '' when absent.
2026-08-22 12:21:58 +08:00
c4363deb46 feat: ticket create - sub-server selector
- ticket-create.js: added 子服务器 dropdown (group/server from
  /polls/server-list, supports anonymous users), sends 'server' field
- tickets.js POST: accept server param, resolve 'group/server' or
  alias/server_name from server_groups, store into tickets.server_name
- polls.js: new public GET /server-list (group_name+server_name only,
  no auth required) for ticket create page
- verified: 13 checks (frontend/backend/db/column/syntax)
2026-08-21 22:02:06 +08:00
e1cdff2b4a security: backend validation for all inputs
- router.param('id'): all :id path params must be positive ints
  (tickets/features/polls/auth/users; external/bans/notifications already
  had parseInt - now consistent)
- notifications: type enum + webhook URL format + SSRF (isPrivateUrl
  exported) + events whitelist + active boolean check on PUT
- bans: type enum + player_name length
- external: all-tickets type/status enums, bans status/type enums,
  page/limit floor protection, ticket field length caps, clients active
  boolean + id validation
- verified: 28 checks (syntax + validation coverage)
2026-08-21 20:10:05 +08:00
8c5ce78fd0 chore: add AGPLv3 copyright header to all source files
- 52 JS files (backend + public/js): header with
  Copyright (C) 2026 Sea Network Technology Studio
  Author: CangLan <admin@sea-studio.top>
  + AGPLv3 notice
- idempotent (skips if header present), all syntax-checked
2026-08-19 20:27:05 +08:00
65edbaf157 refactor: session-based external auth, dynamic sources, drop netease UID
Auth (external API):
- ID: 16-digit random (non-sequential); Secret: SeaReport- + 32 hex
- POST /auth/session: ID+Secret -> Bearer SESSION (24h, single-session,
  old session invalidated on re-issue, disabled client invalidates)
- clientAuth now validates Bearer SESSION via api_sessions JOIN api_clients

Sources (dynamic, no default, open-source friendly):
- sources table + CRUD route (/api/sources, owner; delete guarded by usage)
- users/user_identities.source ENUM -> VARCHAR, seeded netease/skin
- register/admin create/identity bind: validate against enabled sources
- UI: 来源管理 page; source dropdowns loaded dynamically everywhere
  (register, dashboard identity, users admin, bans), labels dynamic

UID removal:
- game_uid/reporter_game_uid no longer required (db default '', validations
  dropped, frontend fields optional)

Docs: EXTERNAL-API.md session flow + new credential format; API.md updated
Verified: 37 checks (syntax, session logic, source CRUD, UID removal, docs)
2026-08-19 20:08:06 +08:00
559970c5b7 feat: one account can bind both netease + skin identities
- db: user_identities table (UNIQUE user_id+source), migrate backfill from users
- auth: GET/POST/DELETE /api/auth/identities - bind/unbind/list identities
  (netease requires UID, one per source, name uniqueness, keep >=1)
- register/external/plugin/admin-created users auto-write primary identity
- tickets: submit uses selected identity (validated belongs to user)
- dashboard: 我的身份 card with bind/unbind UI
- ticket-create: identity selector when >1 identity
2026-08-17 01:17:09 +08:00
6e9101a506 fix: deploy crash + multiple bug fixes + cleanup
- server.js: fix getSiteName() returning string when not installed causing
  'getSiteName(...).then is not a function' crash on homepage (deploy blocker)
- server.js: auto-load business routes after install completes (no restart needed),
  HTML cache keyed by api_key
- install: validate db name/email/password, trigger route loading after complete
- app.js: fix forgot/reset/verify pages rendering HomePage (missing page mapping)
- verify.js: support URL token auto-verification for external registration links
- auth: new email_code template for 6-digit code, reset_password template
  (forgot-password was using verify_email template)
- upload.js: fix MP4 magic-bytes check using undefined buf variable
- tickets.js: status enum validation, anonymous submission rate limit
- security.js: XSS whitelist preserves email template HTML, strips scripts,
  blocks javascript:/data: hrefs; CORS reject returns 403
- bans.js: allow clearing reason/duration, status enum validation
- users.js: fix req.user.role ReferenceError in create user modal
- home.js: tracking results now have detail view button
- .gitignore: ignore data/ (db credentials), logs, session files, temp scripts
2026-08-16 21:21:25 +08:00
5497de9aac feat: batch ticket operations (close/delete/change status) 2026-07-17 21:55:15 +08:00
96e55d8715 feat: anonymous ticket reply via tracking cookie 2026-07-17 14:16:21 +08:00
9e5967d6ea fix: reuse tracking cookie for multiple anonymous submissions 2026-07-17 14:14:02 +08:00
8d9e154ce1 fix: restrict PUT /tickets to admin's own claims (enforce claim system) 2026-07-13 18:19:28 +08:00
532efb962f fix: HIGH+MEDIUM bugs from full audit - listen error, JWT, upload, mailer, webhook 2026-07-13 03:49:02 +08:00
8ae02dd115 fix: add appealing to active_count, limit check, export processing count 2026-07-12 23:28:52 +08:00
6fa1a65843 fix: admin cant view admin_complaint/result_appeal via URL, appeal close also closes parent 2026-07-12 21:02:21 +08:00
f87411b3b4 feat: auto-close resolved/rejected after 7 days, closed only owner can modify 2026-07-12 18:15:10 +08:00
33078855cb feat: appealing status, auto-close parent on appeal resolved, closed=final 2026-07-12 17:42:42 +08:00
7bd23b6bcf fix: result_appeal had wrong respContent label 2026-07-12 17:34:02 +08:00
10b6ff94ed feat: admin complaint (owner only) + result appeal (one per ticket, owner only) 2026-07-12 15:19:09 +08:00
247a4e851d feat: MC Report System - MySQL + Express + Vanilla JS SPA 2026-07-12 01:23:19 +08:00