Skip to content

Releases: GeiserX/Telegram-Archive

v7.4.2 — Correctness & Hygiene

31 Mar 11:47
dfa165b

Choose a tag to compare

Correctness & Release Hygiene

Fixes

  • Listener shutdown KeyError (Medium): _log_stats() referenced non-existent keys from MassOperationProtector.get_stats(). A clean shutdown would raise KeyError. 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 in main.py was missing, making the frontend handler dead code.
  • pyproject.toml version sync (Low): Was stuck at 7.2.0 since v7.2.0. Now synced with __init__.py at 7.4.2.
  • WebSocket subscribe ACL (Low): Server now sends subscribe_denied (instead of subscribed) when a restricted user attempts to subscribe to a chat outside their allowed list. Frontend logs the denial.

What's Changed

  • fix: correctness and release hygiene (v7.4.2) by @GeiserX in #100

Full Changelog: v7.4.1...v7.4.2

v7.4.1 — Security Hardening Round 2

31 Mar 11:22
1242bf1

Choose a tag to compare

Security Hardening (Round 2)

Fixes

  • Avatar ACL bypass (Medium): Restricted users can no longer access avatars outside their allowed chats. serve_media() and serve_thumbnail() now extract chat_id from avatar filenames and enforce per-chat scoping.
  • Push endpoint spoofing (Medium): /internal/push now supports an optional INTERNAL_PUSH_SECRET env 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, the return after a single retry silently dropped remaining reactions.
  • Push unsubscribe ownership (Low): POST /api/push/unsubscribe is now scoped to the requesting user's username, preventing cross-user endpoint removal.

New Environment Variable

  • INTERNAL_PUSH_SECRET: Optional shared secret for /internal/push endpoint. 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

  • fix: security hardening round 2 (v7.4.1) by @GeiserX in #99

Full Changelog: v7.4.0...v7.4.1

v7.4.0 — Security Hardening

31 Mar 11:06
0897f54

Choose a tag to compare

Security Hardening

Addresses multiple security findings from code review.

Fixes

  • XSS (High): linkifyText() now percent-encodes raw " and ' in URLs before inserting into href attributes. escapeHtml() via textContent/innerHTML does not escape quotes.
  • Stats filter (Medium): Fixed JSON string-key vs int type mismatch that caused per-chat filtering to silently fail. Also removes media_files/total_size_mb for 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/push accepts loopback + RFC1918/Docker private IPs to support split-container SQLite mode via VIEWER_HOST/VIEWER_PORT.

Breaking Changes

  • delete_message_by_id_any_chat() replaced by resolve_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

  • fix: security hardening — XSS, push spoofing, metadata leaks, deletion bugs by @GeiserX in #98

Full Changelog: v7.3.2...v7.4.0

v7.3.2

26 Mar 19:30

Choose a tag to compare

What's Changed

  • fix(viewer): display caption for album posts with grouped messages by @vadimvolk in #97

New Contributors

Full Changelog: v7.3.1...v7.3.2

v7.3.1

25 Mar 13:22

Choose a tag to compare

What's Changed

  • fix: skip get_dialogs() in whitelist mode to prevent hanging by @GeiserX in #96

Full Changelog: v7.1.7...v7.3.1

v7.3.0

15 Mar 11:53
a915c69

Choose a tag to compare

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=XXX parameter 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

13 Mar 17:25

Choose a tag to compare

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/health returns {"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 for OSError (covers socket.gaierror, ConnectionRefusedError, etc.)

Closes #92

v7.2.0 — Share Tokens, Download Restrictions, Thumbnails

10 Mar 15:09
923f021

Choose a tag to compare

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 restrictionsno_download flag 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_settings table 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_name for 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_id for precise invalidation
  • Session persistence includes restrictionsno_download and source_token_id are now persisted in viewer_sessions table, surviving container restarts. Previously no_download was lost after restart, silently granting download access
  • Export endpoint respects no_download — The GET /api/chats/{chat_id}/export endpoint now returns 403 for restricted users

Fixed

  • Create viewer passes all flagsis_active and no_download from the admin form are now correctly passed through to create_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, AND viewer_accounts.no_download before stamping migration 010 as complete

Changed

  • Migration 010 — Consolidated idempotent migration creates viewer_tokens, app_settings tables and adds no_download column to viewer_accounts. Also adds no_download and source_token_id columns to viewer_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 declarationspyproject.toml and src/__init__.py both set to 7.2.0
  • SECURITY.md — Added 7.x.x as a supported version
  • pyproject.toml — Added viewer optional dependency group for Pillow

📋 Full changelog: docs/CHANGELOG.md

v7.1.7

08 Mar 19:14

Choose a tag to compare

Bug Fixes

  • fix: add beautifulsoup4 to Docker imagebeautifulsoup4 was declared in pyproject.toml but missing from requirements.txt (used by Docker builds), causing No module named 'bs4' when running HTML imports.

Full Changelog: v7.1.6...v7.1.7

v7.1.6

08 Mar 17:09

Choose a tag to compare

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