Releases: GeiserX/Telegram-Archive
Releases · GeiserX/Telegram-Archive
v7.6.1
Fixed
- Forwarded media from private channels no longer creates broken placeholders — When a message forwarded from a private channel contains a document with an inaccessible file reference (
media.document=None),_get_media_type()now correctly returnsNoneinstead of"document". Previously this caused a brokentelegram_file_idof"None", a failed download attempt, and a misleading "Will download on next backup" placeholder that would never resolve. Applies to both scheduled backup and real-time listener (#125)
📋 Full changelog: docs/CHANGELOG.md
v7.6.0 — Topic Filtering & Symlink Fix
Added
- Topic filtering for forum supergroups — New
SKIP_TOPIC_IDSenvironment variable to exclude specific topics from backup while keeping the rest of the chat. Format:chat_id:topic_id,.... Works in both scheduled backup and real-time listener flows (#117)
Fixed
- Dangling dedup symlinks no longer cause infinite redownload loops — When
DEDUPLICATE_MEDIAis enabled andVERIFY_MEDIAruns, dangling symlinks (where the target was renamed by Telethon) are now detected viaos.path.lexists()instead ofos.path.exists(), which follows symlinks. The download return value is now captured to use the actual on-disk filename for symlink targets. Stale symlinks are removed before recreation to preventErrno 17(file exists) errors. Applies to both scheduled backup and real-time listener (#115)
📋 Full changelog: docs/CHANGELOG.md
v7.5.0 — SOCKS5 Proxy Support
What's New
SOCKS5 Proxy Support (#104)
You can now route all Telegram connections through a SOCKS5 proxy — useful in regions where Telegram is blocked or behind corporate firewalls.
Configuration (all optional):
TELEGRAM_PROXY_TYPE=socks5
TELEGRAM_PROXY_ADDR=127.0.0.1
TELEGRAM_PROXY_PORT=1080
TELEGRAM_PROXY_USERNAME=
TELEGRAM_PROXY_PASSWORD=
TELEGRAM_PROXY_RDNS=false
Proxy support is applied consistently across all code paths: backup, real-time listener, auth setup, and standalone scripts.
Improvements
- Validation hardening: port range (1–65535), username/password pairing, boolean RDNS parsing, and case-insensitive proxy type
- Security: proxy endpoint details logged at DEBUG (not INFO) to avoid exposing infrastructure topology
- Test isolation: proxy integration tests use scoped fixtures instead of global
sys.modulesmutation - Dependency: added
python-socks[asyncio]>=2.7.1(required by Telethon for SOCKS5 transport)
Contributors
Thanks to @samnyan for the proxy feature contribution!
What's Changed
- Add Supporters section to README by @GeiserX in #102
- Add Codecov coverage badge to README by @GeiserX in #103
- feat: Add proxy support for telegram client. by @samnyan in #104
New Contributors
Full Changelog: v7.4.2...v7.5.0
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