ZaStoGram/Tools/check_proxy_link_input.py
loop-uh cfafa0c98c
Some checks failed
ZaStoGram source guards / guards (push) Failing after 48s
Build three ZaStoGram APKs / build (armeabi-v7a, ZaStoGram-standalone-armeabi-v7a, Armv7, armv7) (push) Failing after 2m46s
Build three ZaStoGram APKs / build (x86, ZaStoGram-standalone-x86, X86, x86) (push) Failing after 2m59s
Build three ZaStoGram APKs / build (arm64-v8a, ZaStoGram-standalone-arm64-v8a, Arm64, arm64) (push) Failing after 3m14s
Обновить Telegram до 12.10.3 и подключить WEB-прокси
Влит DrKLO/Telegram master 9552e5541 (12.10.2 7086, 12.10.3 7089,
update submodules, PR #1833 с вибрацией звонков на Android 13+).
Сабмодули td, boringssl и media добавлены, tlottie обновлён, как в апстриме.

WEB-прокси из апстрима встроен в прокси-слой ZaStoGram: ProxyInfo хранит
ProxySettings, список прокси получил схему V5 с типом (V3 уже занят старыми
WSS-полями), ссылки tg://webproxy и t.me/webproxy разбираются ProxyLinkHelper,
тип WEB есть в редакторе прокси. Нативный слой видит WEB как обычный MTProxy
на локальном мосте с секретом самого прокси и MtProxyOptions.disabled(): без
FakeTLS, фрагментации, WSS и soft mux. Страж check_web_proxy_isolation.py
держит этот контракт.

Standalone оставлен без shrinkResources: плагины ищут ресурсы по имени.
2026-09-23 16:31:29 +03:00

135 lines
5.7 KiB
Python

#!/usr/bin/env python3
from pathlib import Path
import re
import sys
ROOT = Path(__file__).resolve().parents[1]
PROXY_SETTINGS = ROOT / "TMessagesProj/src/main/java/org/telegram/ui/ProxySettingsActivity.java"
ANDROID_UTILITIES = ROOT / "TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java"
PROXY_LINK_HELPER = ROOT / "TMessagesProj/src/main/java/org/telegram/messenger/ProxyLinkHelper.java"
LAUNCH_ACTIVITY = ROOT / "TMessagesProj/src/main/java/org/telegram/ui/LaunchActivity.java"
STRINGS = ROOT / "TMessagesProj/src/main/res/values/strings.xml"
STRINGS_RU = ROOT / "TMessagesProj/src/main/res/values-ru/strings.xml"
def fail(message: str) -> None:
raise SystemExit(f"proxy link input check failed: {message}")
def slice_between(text: str, start: str, end: str) -> str:
start_index = text.find(start)
if start_index < 0:
fail(f"missing block start {start!r}")
end_index = text.find(end, start_index)
if end_index < 0:
fail(f"missing block end {end!r}")
return text[start_index:end_index]
def main() -> int:
java = PROXY_SETTINGS.read_text(encoding="utf-8")
android_utilities = ANDROID_UTILITIES.read_text(encoding="utf-8")
launch_activity = LAUNCH_ACTIVITY.read_text(encoding="utf-8")
if not PROXY_LINK_HELPER.exists():
fail("shared ProxyLinkHelper.java must exist")
proxy_link_helper = PROXY_LINK_HELPER.read_text(encoding="utf-8")
strings = STRINGS.read_text(encoding="utf-8")
strings_ru = STRINGS_RU.read_text(encoding="utf-8")
if 'name="UseProxyLink"' not in strings:
fail("base strings must define UseProxyLink")
if 'name="UseProxyLink"' not in strings_ru:
fail("Russian strings must define UseProxyLink")
for needle in (
"private EditTextBoldCursor quickProxyLinkField;",
"private boolean ignoreQuickProxyLinkChange;",
"quickProxyLinkField.setHintText(LocaleController.getString(R.string.UseProxyLink));",
"applyParsedProxyLink(parsedProxyLink, true);",
):
if needle not in java:
fail(f"ProxySettingsActivity missing {needle}")
for needle in (
"public final class ProxyLinkHelper",
"public static ProxyLink parse(String text)",
"public static ProxyLink firstFromText(String text)",
"public static ProxyLink firstFromClipboard(Context context)",
"public static String dedupeKey(ProxyLink link)",
"public static final class ProxyLink",
"public static final int TYPE_SOCKS5",
"public static final int TYPE_MTPROTO",
):
if needle not in proxy_link_helper:
fail(f"ProxyLinkHelper missing {needle}")
for link_marker in (
"t.me/socks?",
"tg://socks?",
"tg:socks?",
"t.me/proxy?",
"tg://proxy?",
"tg:proxy?",
):
if link_marker not in proxy_link_helper:
fail(f"shared parser must recognize {link_marker}")
for forbidden in ("TYPE_WSS", "zastogram://wss?", "tg://wss?"):
if forbidden in proxy_link_helper:
fail(f"WSS must not be parsed as proxy link data: {forbidden}")
if "android.content.ClipboardManager" not in proxy_link_helper or "getPrimaryClip()" not in proxy_link_helper:
fail("shared helper must own safe clipboard extraction")
if "URLDecoder.decode" not in proxy_link_helper:
fail("shared parser must URL-decode server, port, secret, user and pass values")
if "IDN.toASCII" not in proxy_link_helper:
fail("shared parser must normalize punycode hosts")
if "private static final class ParsedProxyLink" in java or "URLDecoder.decode" in java:
fail("ProxySettingsActivity must not keep a duplicate proxy link parser")
parse_body = slice_between(
java,
"private ProxyLinkHelper.ProxyLink parseProxyLink(String text)",
"private void applyParsedProxyLink",
)
if "ProxyLinkHelper.parse(text)" not in parse_body:
fail("ProxySettingsActivity parser wrapper must delegate to ProxyLinkHelper")
apply_body = slice_between(
java,
"private void applyParsedProxyLink(ProxyLinkHelper.ProxyLink parsedProxyLink, boolean animated)",
"private void updatePasteCell()",
)
for assignment in (
"inputFields[i].setText(proxyLinkField(parsedProxyLink, i));",
"setProxyType(parsedProxyLink.type, animated",
"inputFields[FIELD_IP].setSelection(inputFields[FIELD_IP].length());",
"AndroidUtilities.hideKeyboard(inputFieldsContainer.findFocus());",
):
if assignment not in apply_body:
fail(f"link application must contain {assignment}")
paste_body = slice_between(java, "private void updatePasteCell()", "private void setShareDoneEnabled")
if "ProxyLinkHelper.ProxyLink parsedProxyLink = parseProxyLink(clipText);" not in paste_body:
fail("clipboard paste flow must reuse the same parser as the visible link field")
if "pasteProxyLink = parsedProxyLink;" not in paste_body:
fail("clipboard paste flow must keep the shared ProxyLink object")
for needle in (
"public static boolean showClipboardProxyAlertIfNeeded(Activity activity)",
"ProxyLinkHelper.firstFromClipboard(activity)",
"lastClipboardProxyAlertKey",
"ProxyLinkHelper.dedupeKey(link)",
"showProxyAlert(activity, link.toSettings())",
):
if needle not in android_utilities:
fail(f"AndroidUtilities clipboard prompt missing {needle}")
if "AndroidUtilities.showClipboardProxyAlertIfNeeded(this);" not in launch_activity:
fail("LaunchActivity.onResume must check clipboard proxy links")
print("proxy link input check passed")
return 0
if __name__ == "__main__":
sys.exit(main())