Mesajlardaki widget'lar — doğrudan sohbet içinde HTML, CSS ve JavaScript'ten oluşan etkileşimli bloklar — Telegram'ın Android ve iOS betalarına ulaştı. 25 Ekim'de Android 13.2.0 (7254) ve iOS 13.2 (35726) sürümlerinde ortaya çıktılar ve Android'de özel yapım bir widget şimdiden JavaScript çalıştırıyor. 27 Ekim tarihli Android 13.2.0 (7260) yapısı, bunun nasıl çalıştığını gösteriyor: bir tarayıcı motoru olmadan, kendi işlemci kotasına sahip yorumlayıcısı üzerinde, bir dokunuşun gerçek olup olmadığına karar veren ayrı bir hakemle. Widget'ın istek gönderdiği bot, dokunanın ID'sini öğreniyor. Telegram Desktop'ta ve genel Bot API'sında widget'lar hala mevcut değil.

macOS betası için bot isteklerinin mekaniği, 27 Ekim tarihli bir makalede incelenmişti; burada ise Android yapısının ekledikleri yer alıyor.

Widget'lar Nerede Mevcut

İstemciYapıGörünen
macOS, beta13.1.0sandbox, bot istekleri, test sayfaları — Ekim ortasından beri
Android, beta13.2.0 (7254, 7260)şema, sandbox, arayüz metinleri; widget'lar çalışıyor
iOS, beta13.2 (35726)mesajlardaki widget'lar ve bunları kontrol etme araçları
Telegram Desktop7.3.3yok: ne kodda ne de layer 232 şemasında
Bot API10.3yok

Android betası, resmi kanal ve Telegram web sitesinden doğrudan bir bağlantı aracılığıyla dağıtılıyor. Bu yapıdaki istemci protokolü, genel protokolden bir layer daha yeni olan layer 233'tür.

Widget Mesajda Nasıl Yer Alır

Widget, messageMediaWidget adında yeni bir medya türüdür. Kendi kodu (payload) ve boyutlarının yanı sıra iki veri kümesi içerir: chat_data — bu mesajın verileri ve public_data (hash ile birlikte) — botun gönderdikten sonra değiştirebileceği genel widget verileri (messages.editMessageWidgetData, updateMessageWidgetData). can_query ve background_query bayrakları, widget'tan bota dokunarak veya dokunmadan yazılıp yazılamayacağını belirtir; is_copy ise iletilen bir kopyayı işaretler. Widget, botun bir inline sonucu olarak da gelebilir — botInlineMessageWidget.

İzinler gönderen tarafından belirlenir. İstemcinin yerel kısmından gelen hata mesajlarında allow_queries ve fwd_allow_queries sunucu bayrakları belirtilmiştir: birincisi olmadan widget bota hiç yazmaz, ikincisi olmadan iletilen kopyası sessiz kalır. Arka plan isteği ayrıca background_query gerektirir ve yalnızca widget ekrandayken gönderilir.

Bot Ne Alır

Bir dokunuş, sohbet, mesaj ve data (64 bayta kadar) alanlarıyla birlikte bir messages.getBotWidgetQueryAnswer isteğine dönüşür. Bot bir updateBotWidgetQuery güncellemesi alır ve messages.setBotWidgetQueryAnswer metodunu tek bir result dizesiyle yanıtlar.

Bot için gelen güncellemede user_id alanı zorunludur, bayraksızdır: bot her zaman kimin dokunduğunu bilir. Yanında chat_type, chat_instance (sıradan inline düğmelerdekiyle aynı anonim sohbet tanımlayıcısı), mesaj numarası ve widget_id gelir. İletilen kopyalar ve inline mesajlar için kendi güncellemeleri vardır — updateBotWidgetCopyQuery ve updateInlineBotWidgetQuery.

Bu, bir callback'li inline düğmeye dokunmaya benzer, ancak düğmeyi bir script çizer ve verileri de o toplar.

Widget Kodu Nasıl Çalıştırılır

Android'de widget altında ne WebView ne de Chromium bulunur. Kod, istemcinin ana kütüphanesi içindeki yerel twidget kütüphanesi tarafından çalıştırılır — macOS betasında Twidget* türleri ve kaynak kodlarına bağlı kapalı bir GitHub deposu da aynı adı taşır. Sandbox scriptleri istemcide iki kez bulunur: kaynak kodu ve yerleşik JavaScript yorumlayıcısının çalıştırdığı .qbc bytecode olarak. Görüntüyü kendi renderer'ı doğrudan Android penceresine çizer — tarayıcı düzeni yoktur, ancak bunun bir ayrıştırması vardır: ayrı bir validator paketi HTML ve CSS'i kontrol eder.

Kısıtlamalar geliştirici kurallarında değil, kodda belirtilmiştir:

  • işlemci — widget'ın bir zaman kotası (cpuQuotaMs) vardır, aşılması «CPU limit exceeded» hatasıyla sonuçlanır;
  • zamanlayıcılar — eşzamanlı zamanlayıcı sayısı sınırlıdır, fazlası motor tarafından reddedilir;
  • ağ — fetch, XMLHttpRequest, WebSocket ve navigator.sendBeacon engellenmiştir, navigator.onLine her zaman yanlıştır, userAgent — TelegramWidget/1.0;
  • depolama — her widget boş bir depolama ile başlar;
  • dışa çıkışlar — openLink yalnızca 256 karaktere kadar https adresini alır ve «This widget wants to open:» diye sorar, copyText — 256 karaktere kadardır;
  • istemciye köprü — başlatıldıktan sonra __host, __hostOps ve ilgili hizmet fonksiyonları global nesneden kaldırılır ve widget kodu bunlara erişemez.

İstemci, sandbox dosyalarını manifest.txt dosyasındaki kontrol toplamlarıyla karşılaştırır; bir uyuşmazlık «Bundle checksum mismatch» şeklinde ayrı bir hatadır.

İstemci Dokunuşu Taklitten Nasıl Ayırır

Arka plan izni olmayan bir bot isteği, yalnızca dokunma işleyicisinden gönderilir — hata mesajında belirtildiği gibi, "görünür bir widget'a yapılan her dokunuş için bir çağrı". Dokunuşun gerçek olup olmadığına script değil, yerel bir dokunma hakemi karar verir: arbiterDown, arbiterMove, arbiterUp ve arbiterHoldDeadline fonksiyonları parmağın koordinatlarını ve basılı tutma süresini alır. Tasarıma göre, JavaScript'ten gelen sentetik bir tıklama, bir zamanlayıcı veya sürükleme bir istek göndermez.

Betada bu sınırı kontrol etmek için araçlar da bulunur: uyumluluk ekranı (WidgetConformanceActivity) ve bir dizi saldırı testi (attackScan, WidgetAttacks). macOS için saldırı test sayfaları — dokunmadan mesaj göndermeye veya bir bağlantıya yönlendirmeye çalışan 28 sayfa — istemcinin açık kodunda yer almaktadır.

Kullanıcı Ne Görür

Arayüz metinleri zaten istemcinin İngilizce sözlüğünde yer alıyor: «Loading widget…», «Widget failed to load», «Widget stopped», «Preview of the widget» ve «This widget can send data to its bot's server when you tap it.» uyarısı.

Betanın ayarlarında widget'ları devre dışı bırakacak ayrı bir anahtar bulunmuyor — testçiler buna dikkat çekiyor. Widget gönderme yeteneği henüz herkese açık değil ve Bot API'sında bunlar için metodlar bulunmuyor.