Releases: GeiserX/Telegram-Archive
Releases · GeiserX/Telegram-Archive
v7.4.2 — Correctness & Hygiene
Correctness & Release Hygiene
Fixes
- Listener shutdown KeyError (Medium):
_log_stats()referenced non-existent keys fromMassOperationProtector.get_stats(). A clean shutdown would raiseKeyError. Fixed to use actual keys (rate_limits_triggered,operations_blocked,chats_rate_limited). - Pin/unpin realtime (Low): Full pipeline now works end-to-end: listener emits
PIN→ notifier delivers →handle_realtime_notification()forwards to WebSocket → browser reloads pinned messages. Previously the relay inmain.pywas missing, making the frontend handler dead code. - pyproject.toml version sync (Low): Was stuck at
7.2.0since v7.2.0. Now synced with__init__.pyat7.4.2. - WebSocket subscribe ACL (Low): Server now sends
subscribe_denied(instead ofsubscribed) when a restricted user attempts to subscribe to a chat outside their allowed list. Frontend logs the denial.
What's Changed
Full Changelog: v7.4.1...v7.4.2
v7.4.1 — Security Hardening Round 2
Security Hardening (Round 2)
Fixes
- Avatar ACL bypass (Medium): Restricted users can no longer access avatars outside their allowed chats.
serve_media()andserve_thumbnail()now extractchat_idfrom avatar filenames and enforce per-chat scoping. - Push endpoint spoofing (Medium):
/internal/pushnow supports an optionalINTERNAL_PUSH_SECRETenv var as a bearer token. Prevents co-tenant containers from spoofing live events to connected browsers. - Reaction recovery data loss (Medium):
insert_reactions()now retries ALL reactions after a sequence reset, not just the row that triggered the duplicate-key error. Previously, thereturnafter a single retry silently dropped remaining reactions. - Push unsubscribe ownership (Low):
POST /api/push/unsubscribeis now scoped to the requesting user'susername, preventing cross-user endpoint removal.
New Environment Variable
INTERNAL_PUSH_SECRET: Optional shared secret for/internal/pushendpoint. Set the same value on both backup and viewer containers in multi-tenant Docker environments. If unset, IP-only auth is used (backward compatible).
What's Changed
Full Changelog: v7.4.0...v7.4.1
v7.4.0 — Security Hardening
Security Hardening
Addresses multiple security findings from code review.
Fixes
- XSS (High):
linkifyText()now percent-encodes raw"and'in URLs before inserting intohrefattributes.escapeHtml()viatextContent/innerHTMLdoes not escape quotes. - Stats filter (Medium): Fixed JSON string-key vs
inttype mismatch that caused per-chat filtering to silently fail. Also removesmedia_files/total_size_mbfor restricted users (no per-chat breakdown available). - Deletion path (Medium): Unknown-chat deletions now resolve the chat ID from DB first, apply rate limiting, skip ambiguous message IDs (same ID in multiple chats), and send viewer notifications.
- Folders (Low): Restricted users no longer see empty folder names/emoticons for folders with 0 accessible chats.
- Push endpoint (Low):
/internal/pushaccepts loopback + RFC1918/Docker private IPs to support split-container SQLite mode viaVIEWER_HOST/VIEWER_PORT.
Breaking Changes
delete_message_by_id_any_chat()replaced byresolve_message_chat_id()in the database adapter. The old method deleted from ALL chats with a matching message ID — the new approach resolves to a single chat first and skips ambiguous cases.
What's Changed
Full Changelog: v7.3.2...v7.4.0
v7.3.2
What's Changed
- fix(viewer): display caption for album posts with grouped messages by @vadimvolk in #97
New Contributors
- @vadimvolk made their first contribution in #97
Full Changelog: v7.3.1...v7.3.2
v7.3.1
What's Changed
Full Changelog: v7.1.7...v7.3.1
v7.3.0
What's New
Gap-fill recovery
- Detects gaps in message ID sequences using SQL
LAG()window function - Recovers skipped messages from Telegram API automatically
- Available as CLI subcommand (
fill-gaps --chat-id --threshold) and scheduler option (FILL_GAPS=true) - Respects all backup config rules (CHAT_IDS, CHAT_TYPES, exclude lists)
- Robust error handling: continues on per-chat/per-gap errors, reports summary with error count
- Stats automatically recalculated after recovery
Token URL auto-login
- Shareable links with
?token=XXXparameter for direct viewer access - Token is stripped from URL after login via
history.replaceState - Warning note about token exposure in server access logs
UX improvements
- @username display in chat list and message headers
- Shareable link generation UI in admin panel
Testing
- 31 new tests for gap-fill (detect gaps, fill gaps, config, edge cases)
- Full async test coverage with real SQLite + AsyncMock for Telegram client
v7.2.1 — Database Error Handling
Bug Fixes
- Login: When the database is unreachable, the login endpoint now falls through to master env var credentials instead of returning a generic "Unexpected error". Viewer-only users see a clear "Database temporarily unavailable" message (HTTP 503).
- All data endpoints: Connection errors now return HTTP 503 "Database temporarily unavailable" instead of generic HTTP 500 "Internal server error".
- Audit log resilience: Audit log writes in the login flow are wrapped in try/except so they never crash the response.
New Features
- Global exception handler: Catches unhandled DB connection errors across all endpoints (including admin) and returns 503.
- Health endpoint:
GET /api/healthreturns{"status": "ok", "database": "connected"}(200) or{"status": "degraded", "database": "unreachable"}(503). Useful for Docker healthchecks and monitoring.
Internal
- Added
_is_db_connection_error()helper that walks the exception chain looking forOSError(coverssocket.gaierror,ConnectionRefusedError, etc.)
Closes #92
v7.2.0 — Share Tokens, Download Restrictions, Thumbnails
Added
- Share tokens — Admins can create link-shareable tokens scoped to specific chats. Recipients authenticate via token without needing an account. Tokens support expiry dates, revocation, and use tracking
- Download restrictions —
no_downloadflag on both viewer accounts and share tokens. Restricted users can still view media inline but cannot explicitly download files or export chat history. Download buttons hidden in the UI for restricted users - On-demand thumbnails — WebP thumbnail generation at whitelisted sizes (200px, 400px) with disk caching under
{media_root}/.thumbs/. Includes Pillow decompression bomb protection and path traversal guards - App settings — Key-value
app_settingstable for cross-container configuration, with admin CRUD endpoints - Audit log improvements — Action-based filtering in admin panel (prefix match for suffixed events like
viewer_updated:username), token auth events tracked (token_auth_success,token_auth_failed,token_created, etc.) - Admin chat picker metadata — Chat picker now returns
username,first_name,last_namefor better display - Token management UI — New "Share Tokens" tab in admin panel with create, revoke, and delete controls. Plaintext token shown once at creation with copy button
- Token login UI — Login page has a "Share Token" tab for token-based authentication
Security
- Token revocation enforced on active sessions — Revoking, deleting, or changing scope/permissions of a share token immediately invalidates all sessions created from that token. Sessions track
source_token_idfor precise invalidation - Session persistence includes restrictions —
no_downloadandsource_token_idare now persisted inviewer_sessionstable, surviving container restarts. Previouslyno_downloadwas lost after restart, silently granting download access - Export endpoint respects no_download — The
GET /api/chats/{chat_id}/exportendpoint now returns 403 for restricted users
Fixed
- Create viewer passes all flags —
is_activeandno_downloadfrom the admin form are now correctly passed through tocreate_viewer_account(). Previously both flags were silently ignored on creation - Token expiry timezone handling — Frontend now converts local datetime to UTC ISO before sending to the backend, fixing early/late expiry for non-UTC admins
- Audit filter matches suffixed actions — Filter now uses prefix matching so "viewer_updated" catches "viewer_updated:username"
- Migration stamping checks all artifacts — Entrypoint now checks
viewer_tokens,app_settings, ANDviewer_accounts.no_downloadbefore stamping migration 010 as complete
Changed
- Migration 010 — Consolidated idempotent migration creates
viewer_tokens,app_settingstables and addsno_downloadcolumn toviewer_accounts. Also addsno_downloadandsource_token_idcolumns toviewer_sessions - Entrypoint stamping — Updated both PostgreSQL and SQLite stamping blocks to detect all migration 010 artifacts
- Dockerfile.viewer — Added Pillow system dependencies (libjpeg, libwebp) for thumbnail generation
- Version declarations —
pyproject.tomlandsrc/__init__.pyboth set to 7.2.0 - SECURITY.md — Added 7.x.x as a supported version
- pyproject.toml — Added
vieweroptional dependency group for Pillow
📋 Full changelog: docs/CHANGELOG.md
v7.1.7
Bug Fixes
- fix: add beautifulsoup4 to Docker image —
beautifulsoup4was declared inpyproject.tomlbut missing fromrequirements.txt(used by Docker builds), causingNo module named 'bs4'when running HTML imports.
Full Changelog: v7.1.6...v7.1.7
v7.1.6
Bug Fixes
- fix: make migrations 007-009 idempotent — When
create_all()runs before Alembic (fresh SQLite databases), tables and columns may already exist. Migrations now inspect the schema before altering, preventing "duplicate column name: username" crashes on upgrade. Fixes #81.
Full Changelog: v7.1.5...v7.1.6