The new Telegram media types (Kurigram 2.2.23) escape every user string in
_format_special_media, but only CONTACT first_name + CHECKLIST task text were
regression-tested — the reviewer mutation-proved the other sinks were uncovered
(removing html.escape from VENUE title / GIVEAWAY description / CHECKLIST title kept
the suite green). Given this project's XSS history (#12 fail-open, #13 debug-title),
lock them.
Add 7 regression tests (mirroring test_contact_name_is_escaped): a <script> payload in
VENUE title, VENUE address label, DICE emoji, GAME title, CHECKLIST title, GIVEAWAY
description, and GIVEAWAY_WINNERS prize_description; each asserts the raw payload is
absent and the escaped form present. Mutation-verified: removing the escape on each sink
reds its test. 321 passed (314 + 7). Test-only — no production code touched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Upgrade Kurigram 2.2.22 -> 2.2.23 (no breaking API changes; whole suite
green on the new version unchanged).
New in 2.2.23 and now rendered by the bridge:
- LIVE_PHOTO: rendered as a looping video via the /media pipeline
- Poll media (description_media): photo/video/animation/sticker attached
to a poll is rendered above the poll block; find_file_id_in_message
searches poll description_media AND explanation_media instead of
early-returning None for polls
Previously silent media types now rendered:
- STORY: reposted story photo/video via the /media pipeline (render and
URL derive from the same helper-selected object)
- GIVEAWAY / GIVEAWAY_WINNERS: info blocks with quantity/prize/date
- PAID_MEDIA: info block with star amount (content is not downloadable)
- CHECKLIST: title + tasks with done marks
- CONTACT, LOCATION, VENUE (with OSM links), DICE, GAME, INVOICE,
UNSUPPORTED: info blocks, all user-controlled strings html-escaped
Supporting changes:
- titles for all new types in _media_message_title
- no_image flag covers info-block types; poll with media is not no_image;
LIVE_PHOTO counts as video for the video flag
- _save_media_file_ids collects live_photo/story/poll media for the
background cache warmer, honoring the >100MB video guard; paid media
is never collected
- info-block types no longer emit an empty message-media div
- 53 new tests (media URLs with digest, download symmetry, XSS escaping,
flags, size guard); 314 total
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>