🫡3
telegramdesktop/tdesktop/dev • 4ce9177 • 1 files, +1/-1
Update TooManyCooks for LoongArch support
#tdesktop
Update TooManyCooks for LoongArch support
#tdesktop
🫡4
telegramdesktop/tdesktop/dev • abdc116 • 1 files, +5/-9
Fix Linux action tdesktop cache update
#tdesktop
Fix Linux action tdesktop cache update
#tdesktop
🫡5
telegramdesktop/tdesktop/dev • afe2d0b • 2 files, +32/-22
Fix albums selection by click outside of bubble.
Fixes #30831.
#tdesktop
Fix albums selection by click outside of bubble.
Fixes #30831.
#tdesktop
🫡5
💅9🫡4🤨2
👍4🫡3🤝2
morethanwords/tweb/master • 13316cd • 1 files, +9/-1
fix: gate web_app_verify_age to the configured age-verification bot
morethanwords/tweb/master • a93fad0 • 3 files, +518/-8
fix: clear unread_reactions_count in forum topics
Forum-topic badge counters live on the ForumTopic, not the parent channel dialog, and reactions are the only one cleared solely via the readMessages path (onUpdateReadHistory has no reaction logic). Two bugs left it stuck in topics:
- readMessages read hadUnreadReactions from getAnyDialog(peerId) with no threadId — the parent dialog, always 0 in a forum — so the dedicated messages.readReactions server reset was skipped and the badge returned on reload.
- onUpdateReadMessagesContents re-dispatched updateMessageReactions without top_msg_id, so onUpdateMessageReactions decremented the parent dialog instead of the topic.
Derive the topic id from the message via getMessageThreadId and thread it through both paths: readMessages now reads the badge from the topic dialog and passes threadId to the readReactions/readMentions follow-ups, and the reaction re-dispatch carries top_msg_id. Also propagate the read to the parent forum dialog, mirroring the existing mention propagation. The mention branch is intentionally left untouched (it clears via onUpdateReadHistory; threading it here too would double-decrement).
Verified with synthetic tests (Bug 7 reactions + Bug 8 poll votes in a topic) and a dual-account e2e creating a real forum: all three topic counters drop to 0 on both server and client after reading, with readReactions/readMentions fired scoped to the topic.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#webk
fix: gate web_app_verify_age to the configured age-verification bot
morethanwords/tweb/master • a93fad0 • 3 files, +518/-8
fix: clear unread_reactions_count in forum topics
Forum-topic badge counters live on the ForumTopic, not the parent channel dialog, and reactions are the only one cleared solely via the readMessages path (onUpdateReadHistory has no reaction logic). Two bugs left it stuck in topics:
- readMessages read hadUnreadReactions from getAnyDialog(peerId) with no threadId — the parent dialog, always 0 in a forum — so the dedicated messages.readReactions server reset was skipped and the badge returned on reload.
- onUpdateReadMessagesContents re-dispatched updateMessageReactions without top_msg_id, so onUpdateMessageReactions decremented the parent dialog instead of the topic.
Derive the topic id from the message via getMessageThreadId and thread it through both paths: readMessages now reads the badge from the topic dialog and passes threadId to the readReactions/readMentions follow-ups, and the reaction re-dispatch carries top_msg_id. Also propagate the read to the parent forum dialog, mirroring the existing mention propagation. The mention branch is intentionally left untouched (it clears via onUpdateReadHistory; threading it here too would double-decrement).
Verified with synthetic tests (Bug 7 reactions + Bug 8 poll votes in a topic) and a dual-account e2e creating a real forum: all three topic counters drop to 0 on both server and client after reading, with readReactions/readMentions fired scoped to the topic.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#webk
🫡6
telegramdesktop/tdesktop/dev • 641a43d • 1 files, +2/-2
Fix random define tdesktop cache being used for no define
#tdesktop
Fix random define tdesktop cache being used for no define
#tdesktop
🫡3
🫡3
telegramdesktop/tdesktop/dev • 3d63f50 • 2 files, +17/-1
Fix channel stats initial UI toggles.
#tdesktop
Fix channel stats initial UI toggles.
#tdesktop
🫡3
🫡4
telegramdesktop/tdesktop/dev • 0152fa2 • 2 files, +3/-1
Redirected chat list typing to search field in screen reader mode.
#tdesktop
Redirected chat list typing to search field in screen reader mode.
#tdesktop
🫡3
telegramdesktop/tdesktop/dev • b9aad5d • 2 files, +15/-3
Engaged chat search on typing instead of focus in screen reader mode.
In screen reader mode, focusing the dialogs search field no longer opens
the suggestions panel or shows the cancel-search button. Search engages
only when the user types, stays engaged after clearing the query, and
disengages only on explicit Escape or the cancel-search button. Tab and
Backspace on an empty query no longer exit search in this mode.
Non-screen-reader behavior is unchanged.
#tdesktop
Engaged chat search on typing instead of focus in screen reader mode.
In screen reader mode, focusing the dialogs search field no longer opens
the suggestions panel or shows the cancel-search button. Search engages
only when the user types, stays engaged after clearing the query, and
disengages only on explicit Escape or the cancel-search button. Tab and
Backspace on an empty query no longer exit search in this mode.
Non-screen-reader behavior is unchanged.
#tdesktop
🫡3
🫡3
UnigramDev/Unigram/develop • 3d046d0 • 1 files, +1/-1
Update microtex
UnigramDev/Unigram/develop • 5d1a827 • 1 files, +2/-2
Fix null ref
UnigramDev/Unigram/develop • 596faf5 • 8 files, +69/-14
Accent improvements
UnigramDev/Unigram/develop • 2159edb • 1 files, +12/-2
Show error toast
UnigramDev/Unigram/develop • 0075f8a • 1 files, +1/-1
Update TDLib
UnigramDev/Unigram/develop • b6cd604 • 16 files, +3354/-743
Working on rich messages editor
UnigramDev/Unigram/develop • 2714fe0 • 3 files, +235/-310
Rich messages improvements
UnigramDev/Unigram/develop • 7dd814c • 1 files, +2/-2
Use cascadia if available
UnigramDev/Unigram/develop • a26c239 • 1 files, +1/-1
Bump version to 12.8.1
#unigram
Update microtex
UnigramDev/Unigram/develop • 5d1a827 • 1 files, +2/-2
Fix null ref
UnigramDev/Unigram/develop • 596faf5 • 8 files, +69/-14
Accent improvements
UnigramDev/Unigram/develop • 2159edb • 1 files, +12/-2
Show error toast
UnigramDev/Unigram/develop • 0075f8a • 1 files, +1/-1
Update TDLib
UnigramDev/Unigram/develop • b6cd604 • 16 files, +3354/-743
Working on rich messages editor
UnigramDev/Unigram/develop • 2714fe0 • 3 files, +235/-310
Rich messages improvements
UnigramDev/Unigram/develop • 7dd814c • 1 files, +2/-2
Use cascadia if available
UnigramDev/Unigram/develop • a26c239 • 1 files, +1/-1
Bump version to 12.8.1
#unigram
🫡2
telegramdesktop/tdesktop/dev • 34c91cc • 1 files, +1/-0
Fix clangd in vscode devcontainer
telegramdesktop/tdesktop/dev • 4fff6a1 • 1 files, +2/-0
Ensure cmake gets preferred binutils version from PATH
#tdesktop
Fix clangd in vscode devcontainer
telegramdesktop/tdesktop/dev • 4fff6a1 • 1 files, +2/-0
Ensure cmake gets preferred binutils version from PATH
#tdesktop
🫡3
telegramdesktop/tdesktop/dev • baa53ca • 6 files, +60/-6
Support alternative edited-on date display.
telegramdesktop/tdesktop/dev • cb97504 • 1 files, +1/-1
Fix pre-history visibility in manage group.
#tdesktop
Support alternative edited-on date display.
telegramdesktop/tdesktop/dev • cb97504 • 1 files, +1/-1
Fix pre-history visibility in manage group.
#tdesktop
🫡4
telegramdesktop/tdesktop/dev • e98856d • 2 files, +3/-3
One more attempt to restore context with ANGLE.
#tdesktop
One more attempt to restore context with ANGLE.
#tdesktop
🫡3
morethanwords/tweb/master • bcd2792 • 3 files, +67/-1
fix: detect group-call media-transport stall (ICE connected, DTLS hung)
GroupCallInstance.connectionState (and thus the call UI) reports only the
ICE connection state, so a call where ICE reaches `connected` but the
RTCPeerConnection never does — the DTLS handshake stalls, seen on
restrictive networks / some VPNs — looked "connected" while no media ever
flowed: black video tiles, silence, the SFU data channel never opening,
no error anywhere.
Watch the real RTCPeerConnection.connectionState in groupCallsController:
arm a 10s watchdog when ICE connects, and if connectionState hasn't
reached `connected` by then (or goes `failed` — which the existing ICE
`failed` branch never caught, since ICE stays `connected` while DTLS
fails), surface it via the existing conference-bug breadcrumb and hang up
the dead call instead of leaving the user on a silent black call.
Also log the DtlsTransport state on connectionstatechange so an exported
log pins a DTLS stall directly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
morethanwords/tweb/master • 007cf7c • 13 files, +821/-100
fix: harden E2E call crypto — DH param validation + block authorization
The server is the explicit adversary of Telegram's E2E calls, but WebK trusted
server-supplied data in two places, and the tde2e port had skipped several
validations the reference (tdlib/tdesktop) enforces.
1-on-1 calls (src/lib/crypto):
- Validate the DH config {p,g} from messages.getDhConfig: pin the known 2048-bit
safe prime (safe-prime + generator-congruence fallback) and range-check both
our g_a and the peer's g_b (1<x<p-1, 2^(2048-64) bounds) — mirrors tdesktop
mtproto_dh_utils. Defeats a malicious server's smooth prime (passive key
recovery, invisible to the emoji SAS) and degenerate peer values. Hang up on
any failure.
E2E group calls (src/lib/calls/e2e/blockchain.ts):
- Port tde2e State::apply per-change authorization: derive the signer's
permissions from the prior group state and reject changes it isn't entitled
to make (may_add_users / may_remove_users, no granting flags the signer lacks,
no widening external_permissions, may_change_shared_key requires membership).
- Make state-proof validation faithful to validate_state (group_state/shared_key
omitted-when-changed, present-when-not) and require >=1 SetValue/SetGroupState.
tde2e port hardening:
- TLReader.vector: reject a length larger than the remaining buffer (DoS).
- Reject trailing data after decodeBlock / decodeGroupBroadcast (fetch_end).
- serverToLocal: only strip the +1 magic when magic-1 is a known constructor.
- hydrateStateFromBlock: reject negative block height.
- Buffer future-height verification broadcasts and replay them when the chain
advances (delayed_broadcasts_), so SFU reordering can't suppress the emoji SAS.
- Re-check our pubkey<->user_id on every epoch; co-locate the SELF_PACKET guard.
Adds unit + adversarial tests: DH validation, block authorization, state-proof
shape, and broadcast reordering.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
#webk
fix: detect group-call media-transport stall (ICE connected, DTLS hung)
GroupCallInstance.connectionState (and thus the call UI) reports only the
ICE connection state, so a call where ICE reaches `connected` but the
RTCPeerConnection never does — the DTLS handshake stalls, seen on
restrictive networks / some VPNs — looked "connected" while no media ever
flowed: black video tiles, silence, the SFU data channel never opening,
no error anywhere.
Watch the real RTCPeerConnection.connectionState in groupCallsController:
arm a 10s watchdog when ICE connects, and if connectionState hasn't
reached `connected` by then (or goes `failed` — which the existing ICE
`failed` branch never caught, since ICE stays `connected` while DTLS
fails), surface it via the existing conference-bug breadcrumb and hang up
the dead call instead of leaving the user on a silent black call.
Also log the DtlsTransport state on connectionstatechange so an exported
log pins a DTLS stall directly.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
morethanwords/tweb/master • 007cf7c • 13 files, +821/-100
fix: harden E2E call crypto — DH param validation + block authorization
The server is the explicit adversary of Telegram's E2E calls, but WebK trusted
server-supplied data in two places, and the tde2e port had skipped several
validations the reference (tdlib/tdesktop) enforces.
1-on-1 calls (src/lib/crypto):
- Validate the DH config {p,g} from messages.getDhConfig: pin the known 2048-bit
safe prime (safe-prime + generator-congruence fallback) and range-check both
our g_a and the peer's g_b (1<x<p-1, 2^(2048-64) bounds) — mirrors tdesktop
mtproto_dh_utils. Defeats a malicious server's smooth prime (passive key
recovery, invisible to the emoji SAS) and degenerate peer values. Hang up on
any failure.
E2E group calls (src/lib/calls/e2e/blockchain.ts):
- Port tde2e State::apply per-change authorization: derive the signer's
permissions from the prior group state and reject changes it isn't entitled
to make (may_add_users / may_remove_users, no granting flags the signer lacks,
no widening external_permissions, may_change_shared_key requires membership).
- Make state-proof validation faithful to validate_state (group_state/shared_key
omitted-when-changed, present-when-not) and require >=1 SetValue/SetGroupState.
tde2e port hardening:
- TLReader.vector: reject a length larger than the remaining buffer (DoS).
- Reject trailing data after decodeBlock / decodeGroupBroadcast (fetch_end).
- serverToLocal: only strip the +1 magic when magic-1 is a known constructor.
- hydrateStateFromBlock: reject negative block height.
- Buffer future-height verification broadcasts and replay them when the chain
advances (delayed_broadcasts_), so SFU reordering can't suppress the emoji SAS.
- Re-check our pubkey<->user_id on every epoch; co-locate the SELF_PACKET guard.
Adds unit + adversarial tests: DH validation, block authorization, state-proof
shape, and broadcast reordering.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
#webk
👍3🫡1
morethanwords/tweb/master • 9d58fe1 • 117 files, +1371/-403
feat: Document Picture-in-Picture — pop the whole client into an always-on-top window
Move the live app DOM into a Document PiP window (same instance, instant) via the left-sidebar More submenu "Picture-in-Picture" entry, gated on Chromium support and toggling to "Exit" while popped out.
Core: appWindow.ts metrics/overlay rebind layer (getAppWindow / getOverlayRoot / bindActiveWindowListener / onAppWindowChange); clientPip move/restore + mirrorDocumentStyles + ClientPipPlaceholder for the vacated tab.
Plus a broad realm-coupling sweep so overlays, context menus, gestures, keyboard, paste/drop, IntersectionObserver, scroll preservation and cross-realm instanceof all keep working when the app lives in the PiP window.
Fullscreen from the media viewer is unavailable in PiP (forbidden by spec and activation cannot cross windows); the button shows a hint to return to the tab instead.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
morethanwords/tweb/master • 0fa2741 • 2 files, +53/-1
fix: deepEqual no longer leaks ignoreKeys into nested objects
Bug (discovery scan, src/helpers/object/deepEqual.ts)
-----------------------------------------------------
`deepEqual(x, y, ignoreKeys)` is meant to skip the listed keys at the
level being compared (e.g. drafts ignore `date`/`reply_to`; the chat
pattern renderer ignores `element`). But the recursive call passed the
SAME `ignoreKeys` down into every nested object:
ok(x).every((key) => deepEqual(x[key], y[key], ignoreKeys))
so any nested property whose name matched an ignored key was silently
skipped at every depth. Two objects that differed only inside a nested
object — under a same-named key — were wrongly reported equal.
Root cause (current code, line 12)
----------------------------------
`ignoreKeys` was forwarded unconditionally in the recursion, turning a
top-level filter into a global, all-depths filter.
Fix
---
Drop `ignoreKeys` from the recursive call so it applies only at the
comparison (top) level — the documented intent. One-token change plus a
doc note. Both existing callers (drafts `['date','reply_to']`, pattern
renderer `['element']`) compare flat shapes with no nested same-named
keys, so their behavior is unchanged; the fix is strictly more correct
and removes a footgun for any future caller.
Evidence
--------
New src/tests/deepEqual.test.ts (6 tests): flat compare, undefined-prop
skipping, nested recursion, top-level ignore, and the regression case
"does NOT ignore the keys inside nested objects". The regression test
FAILS on master (returns true, expected false) and PASSES after the fix;
the other 5 lock existing behavior. Full suite: 215 passed (the lone
unrelated failure, appGroupCallsManagerJoin.test.ts, is pre-existing on
master and in an off-limits area).
Gates: tsc --noEmit 0 · eslint 0 (both files) · vitest 6/6 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#webk
feat: Document Picture-in-Picture — pop the whole client into an always-on-top window
Move the live app DOM into a Document PiP window (same instance, instant) via the left-sidebar More submenu "Picture-in-Picture" entry, gated on Chromium support and toggling to "Exit" while popped out.
Core: appWindow.ts metrics/overlay rebind layer (getAppWindow / getOverlayRoot / bindActiveWindowListener / onAppWindowChange); clientPip move/restore + mirrorDocumentStyles + ClientPipPlaceholder for the vacated tab.
Plus a broad realm-coupling sweep so overlays, context menus, gestures, keyboard, paste/drop, IntersectionObserver, scroll preservation and cross-realm instanceof all keep working when the app lives in the PiP window.
Fullscreen from the media viewer is unavailable in PiP (forbidden by spec and activation cannot cross windows); the button shows a hint to return to the tab instead.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
morethanwords/tweb/master • 0fa2741 • 2 files, +53/-1
fix: deepEqual no longer leaks ignoreKeys into nested objects
Bug (discovery scan, src/helpers/object/deepEqual.ts)
-----------------------------------------------------
`deepEqual(x, y, ignoreKeys)` is meant to skip the listed keys at the
level being compared (e.g. drafts ignore `date`/`reply_to`; the chat
pattern renderer ignores `element`). But the recursive call passed the
SAME `ignoreKeys` down into every nested object:
ok(x).every((key) => deepEqual(x[key], y[key], ignoreKeys))
so any nested property whose name matched an ignored key was silently
skipped at every depth. Two objects that differed only inside a nested
object — under a same-named key — were wrongly reported equal.
Root cause (current code, line 12)
----------------------------------
`ignoreKeys` was forwarded unconditionally in the recursion, turning a
top-level filter into a global, all-depths filter.
Fix
---
Drop `ignoreKeys` from the recursive call so it applies only at the
comparison (top) level — the documented intent. One-token change plus a
doc note. Both existing callers (drafts `['date','reply_to']`, pattern
renderer `['element']`) compare flat shapes with no nested same-named
keys, so their behavior is unchanged; the fix is strictly more correct
and removes a footgun for any future caller.
Evidence
--------
New src/tests/deepEqual.test.ts (6 tests): flat compare, undefined-prop
skipping, nested recursion, top-level ignore, and the regression case
"does NOT ignore the keys inside nested objects". The regression test
FAILS on master (returns true, expected false) and PASSES after the fix;
the other 5 lock existing behavior. Full suite: 215 passed (the lone
unrelated failure, appGroupCallsManagerJoin.test.ts, is pre-existing on
master and in an off-limits area).
Gates: tsc --noEmit 0 · eslint 0 (both files) · vitest 6/6 green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#webk
👍3🫡2