refactor: remove local storing tg js
This commit is contained in:
@@ -29,3 +29,5 @@ __pycache__/
|
||||
locales/ru_backup.json
|
||||
locales/en_backup.json
|
||||
db/models_old.py
|
||||
config/tariffs.json
|
||||
docker-compose-dev.yml
|
||||
|
||||
@@ -303,19 +303,6 @@ Web App запускается в том же контейнере, что и б
|
||||
|
||||
Для email-регистраций пользователь в панели Remnawave создается с анонимным username вида `em_<referral_code>`; email добавляется в описание пользователя панели и, если API панели принимает поле email, передается отдельным полем. Для Telegram-регистраций сохраняется существующая схема `tg_<telegram_id>`.
|
||||
|
||||
Шапка и модальные окна Web App учитывают Telegram safe area через `--tg-content-safe-area-inset-top` и `--tg-safe-area-inset-top`, а сверху добавлен повышенный дополнительный буфер, чтобы интерфейс не уезжал под панель Telegram при открытии из списка чатов.
|
||||
|
||||
Для настройки внешнего вида без запуска бота можно открыть файл `bot/app/web/templates/subscription_webapp.html` напрямую в браузере. Рядом с ним лежат `telegram-web-app.js`, `telegram-widget.js`, `subscription_webapp.css` и `subscription_webapp.js`, поэтому локальный предпросмотр работает без сервера и без внешнего CDN. При отдаче страницы через Web App сервер dev-mock автоматически вырезается и не попадает пользователям.
|
||||
|
||||
Локальная копия Telegram Web App SDK хранится в `bot/app/web/templates/telegram-web-app.js`, а локальная копия Telegram Login Widget - в `bot/app/web/templates/telegram-widget.js`. В контейнере обе копии автоматически обновляются при старте Web App и затем раз в 24 часа; если источник временно недоступен, используется уже сохраненная версия. У локального `telegram-widget.js` есть минимальная нормализация, чтобы при загрузке с вашего домена виджет все равно открывал iframe на Telegram-origin, а не на `/embed/...` вашего сайта. Для ручного обновления можно запустить команды:
|
||||
|
||||
```bash
|
||||
python scripts/update_telegram_web_app_js.py
|
||||
python scripts/update_telegram_widget_js.py
|
||||
```
|
||||
|
||||
При необходимости оба скрипта принимают `--source-url` и `--target`, если нужно скачать файл в другое место или проверить альтернативный источник.
|
||||
|
||||
## Подробная инструкция для развертывания на сервере с панелью Remnawave
|
||||
|
||||
### 1. Клонирование репозитория
|
||||
|
||||
@@ -48,13 +48,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
TEMPLATE_PATH = Path(__file__).resolve().parent / "templates" / "subscription_webapp.html"
|
||||
ASSET_DIR = TEMPLATE_PATH.parent
|
||||
TELEGRAM_WEB_APP_SDK_URL = "https://telegram.org/js/telegram-web-app.js"
|
||||
TELEGRAM_WEB_APP_SDK_PATH = ASSET_DIR / "telegram-web-app.js"
|
||||
TELEGRAM_WIDGET_SDK_URL = "https://telegram.org/js/telegram-widget.js?23"
|
||||
TELEGRAM_WIDGET_SDK_PATH = ASSET_DIR / "telegram-widget.js"
|
||||
WEBAPP_LOGO_PROXY_PATH = "/webapp-logo"
|
||||
_UNPATCHED_WIDGET_ORIGIN_SNIPPET = """ if (origin == 'https://telegram.org') {\n origin = default_origin;\n } else if (origin == 'https://telegram-js.azureedge.net' || origin == 'https://tg.dev') {\n origin = dev_origin;\n }\n"""
|
||||
_PATCHED_WIDGET_ORIGIN_SNIPPET = """ if (origin == 'https://telegram.org') {\n origin = default_origin;\n } else if (origin == 'https://telegram-js.azureedge.net' || origin == 'https://tg.dev') {\n origin = dev_origin;\n } else {\n origin = default_origin;\n }\n"""
|
||||
WEBAPP_CONFIG_PLACEHOLDER = "<!-- WEBAPP_CONFIG_SCRIPT -->"
|
||||
WEBAPP_I18N_PLACEHOLDER = "<!-- WEBAPP_I18N_SCRIPT -->"
|
||||
WEBAPP_JS_PLACEHOLDER = "<!-- WEBAPP_JS_SCRIPT -->"
|
||||
@@ -164,8 +158,6 @@ def create_subscription_webapp_application(
|
||||
def setup_subscription_webapp_routes(app: web.Application) -> None:
|
||||
app.router.add_get("/", index_route)
|
||||
app.router.add_get("/health", health_route)
|
||||
app.router.add_get("/telegram-web-app.js", telegram_web_app_asset_route)
|
||||
app.router.add_get("/telegram-widget.js", telegram_widget_asset_route)
|
||||
app.router.add_get(WEBAPP_LOGO_PROXY_PATH, webapp_logo_route)
|
||||
app.router.add_get("/subscription_webapp.css", css_asset_route)
|
||||
app.router.add_get("/subscription_webapp.min.{asset_hash}.js", js_asset_route)
|
||||
@@ -467,144 +459,6 @@ async def _enforce_webapp_rate_limit(
|
||||
return None
|
||||
|
||||
|
||||
async def telegram_web_app_asset_route(request: web.Request) -> web.Response:
|
||||
if not TELEGRAM_WEB_APP_SDK_PATH.exists():
|
||||
await refresh_telegram_web_app_sdk()
|
||||
|
||||
try:
|
||||
response = await _serve_template_asset(
|
||||
request,
|
||||
"telegram-web-app.js",
|
||||
"application/javascript",
|
||||
)
|
||||
except FileNotFoundError:
|
||||
logger.exception(
|
||||
"Telegram Web App SDK is unavailable at %s",
|
||||
TELEGRAM_WEB_APP_SDK_PATH,
|
||||
)
|
||||
raise web.HTTPServiceUnavailable(text="telegram_web_app_sdk_unavailable")
|
||||
|
||||
response.headers["Cache-Control"] = "no-cache"
|
||||
return response
|
||||
|
||||
|
||||
async def telegram_widget_asset_route(request: web.Request) -> web.Response:
|
||||
if not TELEGRAM_WIDGET_SDK_PATH.exists():
|
||||
await refresh_telegram_login_widget_sdk()
|
||||
|
||||
try:
|
||||
data = TELEGRAM_WIDGET_SDK_PATH.read_bytes()
|
||||
except FileNotFoundError:
|
||||
logger.exception(
|
||||
"Telegram Login Widget SDK is unavailable at %s",
|
||||
TELEGRAM_WIDGET_SDK_PATH,
|
||||
)
|
||||
raise web.HTTPServiceUnavailable(text="telegram_widget_sdk_unavailable")
|
||||
|
||||
data = _normalize_telegram_login_widget_sdk(data)
|
||||
response = web.Response(body=data, content_type="application/javascript")
|
||||
response.headers["Cache-Control"] = "no-cache"
|
||||
return response
|
||||
|
||||
|
||||
async def refresh_telegram_web_app_sdk() -> bool:
|
||||
"""Best-effort refresh of the vendored Telegram Web App SDK."""
|
||||
try:
|
||||
session = await _get_shared_http_session()
|
||||
async with session.get(TELEGRAM_WEB_APP_SDK_URL) as response:
|
||||
if response.status != 200:
|
||||
logger.warning(
|
||||
"Telegram Web App SDK refresh returned HTTP %s; keeping the bundled copy.",
|
||||
response.status,
|
||||
)
|
||||
return False
|
||||
data = await response.read()
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to refresh Telegram Web App SDK: %s", exc)
|
||||
return False
|
||||
|
||||
try:
|
||||
TELEGRAM_WEB_APP_SDK_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
existing_data = (
|
||||
TELEGRAM_WEB_APP_SDK_PATH.read_bytes()
|
||||
if TELEGRAM_WEB_APP_SDK_PATH.exists()
|
||||
else None
|
||||
)
|
||||
if existing_data == data:
|
||||
logger.info("Telegram Web App SDK is already up to date.")
|
||||
return True
|
||||
|
||||
temp_path = TELEGRAM_WEB_APP_SDK_PATH.with_name(
|
||||
f"{TELEGRAM_WEB_APP_SDK_PATH.name}.tmp"
|
||||
)
|
||||
temp_path.write_bytes(data)
|
||||
temp_path.replace(TELEGRAM_WEB_APP_SDK_PATH)
|
||||
logger.info(
|
||||
"Telegram Web App SDK updated at %s (%d bytes).",
|
||||
TELEGRAM_WEB_APP_SDK_PATH,
|
||||
len(data),
|
||||
)
|
||||
return True
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to store Telegram Web App SDK locally: %s", exc)
|
||||
return False
|
||||
|
||||
|
||||
async def refresh_telegram_login_widget_sdk() -> bool:
|
||||
"""Best-effort refresh of the vendored Telegram Login Widget SDK."""
|
||||
try:
|
||||
session = await _get_shared_http_session()
|
||||
async with session.get(TELEGRAM_WIDGET_SDK_URL) as response:
|
||||
if response.status != 200:
|
||||
logger.warning(
|
||||
"Telegram Login Widget SDK refresh returned HTTP %s; keeping the bundled copy.",
|
||||
response.status,
|
||||
)
|
||||
return False
|
||||
data = await response.read()
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to refresh Telegram Login Widget SDK: %s", exc)
|
||||
return False
|
||||
|
||||
try:
|
||||
data = _normalize_telegram_login_widget_sdk(data)
|
||||
TELEGRAM_WIDGET_SDK_PATH.parent.mkdir(parents=True, exist_ok=True)
|
||||
existing_data = (
|
||||
TELEGRAM_WIDGET_SDK_PATH.read_bytes()
|
||||
if TELEGRAM_WIDGET_SDK_PATH.exists()
|
||||
else None
|
||||
)
|
||||
if existing_data == data:
|
||||
logger.info("Telegram Login Widget SDK is already up to date.")
|
||||
return True
|
||||
|
||||
temp_path = TELEGRAM_WIDGET_SDK_PATH.with_name(
|
||||
f"{TELEGRAM_WIDGET_SDK_PATH.name}.tmp"
|
||||
)
|
||||
temp_path.write_bytes(data)
|
||||
temp_path.replace(TELEGRAM_WIDGET_SDK_PATH)
|
||||
logger.info(
|
||||
"Telegram Login Widget SDK updated at %s (%d bytes).",
|
||||
TELEGRAM_WIDGET_SDK_PATH,
|
||||
len(data),
|
||||
)
|
||||
return True
|
||||
except Exception as exc:
|
||||
logger.warning("Failed to store Telegram Login Widget SDK locally: %s", exc)
|
||||
return False
|
||||
|
||||
|
||||
def _normalize_telegram_login_widget_sdk(data: bytes) -> bytes:
|
||||
# Keep the vendored widget pointing to Telegram's OAuth host instead of the local origin.
|
||||
text = data.decode("utf-8")
|
||||
normalized = text.replace(
|
||||
_UNPATCHED_WIDGET_ORIGIN_SNIPPET,
|
||||
_PATCHED_WIDGET_ORIGIN_SNIPPET,
|
||||
1,
|
||||
)
|
||||
return normalized.encode("utf-8")
|
||||
|
||||
|
||||
async def js_asset_route(request: web.Request) -> web.Response:
|
||||
asset_hash = request.match_info.get("asset_hash")
|
||||
filename = (
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
font-display: swap;
|
||||
}
|
||||
</style>
|
||||
<script src="./telegram-web-app.js"></script>
|
||||
<script src="https://telegram.org/js/telegram-web-app.js"></script>
|
||||
<link rel="stylesheet" href="./subscription_webapp.css">
|
||||
</head>
|
||||
|
||||
|
||||
@@ -91,7 +91,8 @@ const MOCK = (() => {
|
||||
|
||||
const CFG = readJsonScript('webapp-config') || (MOCK && MOCK.config) || {};
|
||||
const tg = window.Telegram && window.Telegram.WebApp ? window.Telegram.WebApp : null;
|
||||
const TELEGRAM_LOGIN_WIDGET_URL = './telegram-widget.js';
|
||||
const TELEGRAM_LOGIN_WIDGET_URL = 'https://telegram.org/js/telegram-widget.js?23';
|
||||
const TELEGRAM_LOGIN_WIDGET_RENDER_TIMEOUT_MS = 8000;
|
||||
const MANUAL_LOGOUT_FLAG_KEY = 'rw_webapp_manual_logout';
|
||||
const state = {
|
||||
token: MOCK ? 'local-preview' : (localStorage.getItem('rw_webapp_token') || ''),
|
||||
@@ -241,7 +242,8 @@ const MOCK = (() => {
|
||||
telegram_auth: 'Telegram auth',
|
||||
telegram_auth_verifying: 'Проверяю вход...',
|
||||
telegram_auth_failed: 'Не удалось подтвердить Telegram-вход. Попробуйте еще раз.',
|
||||
telegram_auth_unavailable: 'Telegram Login Widget недоступен. Проверьте username бота и доступ к telegram.org.',
|
||||
telegram_auth_unavailable: 'Сервер Telegram сейчас недоступен. Попробуйте позже или войдите по email.',
|
||||
telegram_bot_unavailable: 'Telegram Login Widget недоступен. Попробуйте позже или войдите по email.',
|
||||
telegram_auth_access_denied: 'Доступ запрещен.',
|
||||
active: 'Активна',
|
||||
inactive: 'Не активна',
|
||||
@@ -381,7 +383,8 @@ const MOCK = (() => {
|
||||
telegram_auth: 'Telegram auth',
|
||||
telegram_auth_verifying: 'Verifying login...',
|
||||
telegram_auth_failed: 'Could not verify Telegram login. Try again.',
|
||||
telegram_auth_unavailable: 'Telegram Login Widget is unavailable. Check the bot username and access to telegram.org.',
|
||||
telegram_auth_unavailable: 'Telegram server is unavailable right now. Try again later or sign in by email.',
|
||||
telegram_bot_unavailable: 'Telegram Login Widget is unavailable. Try again later or sign in by email.',
|
||||
telegram_auth_access_denied: 'Access denied.',
|
||||
active: 'Active',
|
||||
inactive: 'Inactive',
|
||||
@@ -701,6 +704,32 @@ const MOCK = (() => {
|
||||
await finalizeTelegramAuth(user, 'auth_data');
|
||||
}
|
||||
|
||||
function appendTelegramLoginWidget(container, botUsername, callbackName, onUnavailable) {
|
||||
const script = document.createElement('script');
|
||||
let unavailableShown = false;
|
||||
const showUnavailable = () => {
|
||||
if (unavailableShown) return;
|
||||
unavailableShown = true;
|
||||
onUnavailable();
|
||||
};
|
||||
|
||||
script.async = true;
|
||||
script.src = TELEGRAM_LOGIN_WIDGET_URL;
|
||||
script.setAttribute('data-telegram-login', botUsername);
|
||||
script.setAttribute('data-size', 'large');
|
||||
script.setAttribute('data-userpic', 'true');
|
||||
script.setAttribute('data-request-access', 'write');
|
||||
script.setAttribute('data-onauth', `${callbackName}(user)`);
|
||||
script.onerror = showUnavailable;
|
||||
script.onload = () => {
|
||||
window.setTimeout(() => {
|
||||
if (!container.contains(script) || container.querySelector('iframe')) return;
|
||||
showUnavailable();
|
||||
}, TELEGRAM_LOGIN_WIDGET_RENDER_TIMEOUT_MS);
|
||||
};
|
||||
container.appendChild(script);
|
||||
}
|
||||
|
||||
function setAuthMode(mode) {
|
||||
state.authMode = mode === 'telegram' ? 'telegram' : 'email';
|
||||
renderAuthMode();
|
||||
@@ -740,7 +769,7 @@ const MOCK = (() => {
|
||||
container.innerHTML = '';
|
||||
const botUsername = String(CFG.telegramLoginBotUsername || '').trim();
|
||||
if (!botUsername) {
|
||||
setAuthStatus(t('telegram_auth_unavailable'), true);
|
||||
setAuthStatus(t('telegram_bot_unavailable'), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -750,16 +779,13 @@ const MOCK = (() => {
|
||||
};
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.async = true;
|
||||
script.src = TELEGRAM_LOGIN_WIDGET_URL;
|
||||
script.setAttribute('data-telegram-login', botUsername);
|
||||
script.setAttribute('data-size', 'large');
|
||||
script.setAttribute('data-userpic', 'true');
|
||||
script.setAttribute('data-request-access', 'write');
|
||||
script.setAttribute('data-onauth', 'onTelegramAuth(user)');
|
||||
script.onerror = () => setAuthStatus(t('telegram_auth_unavailable'), true);
|
||||
container.appendChild(script);
|
||||
setAuthStatus('');
|
||||
appendTelegramLoginWidget(
|
||||
container,
|
||||
botUsername,
|
||||
'onTelegramAuth',
|
||||
() => setAuthStatus(t('telegram_auth_unavailable'), true)
|
||||
);
|
||||
}
|
||||
|
||||
function bindEmailLoginInput() {
|
||||
@@ -1864,7 +1890,7 @@ const MOCK = (() => {
|
||||
container.innerHTML = '';
|
||||
const botUsername = String(CFG.telegramLoginBotUsername || '').trim();
|
||||
if (!botUsername) {
|
||||
setTelegramLinkStatus(t('telegram_auth_unavailable'), true);
|
||||
setTelegramLinkStatus(t('telegram_bot_unavailable'), true);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1872,16 +1898,13 @@ const MOCK = (() => {
|
||||
await linkTelegramAccount(user);
|
||||
};
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.async = true;
|
||||
script.src = TELEGRAM_LOGIN_WIDGET_URL;
|
||||
script.setAttribute('data-telegram-login', botUsername);
|
||||
script.setAttribute('data-size', 'large');
|
||||
script.setAttribute('data-userpic', 'true');
|
||||
script.setAttribute('data-request-access', 'write');
|
||||
script.setAttribute('data-onauth', 'onTelegramLinkAuth(user)');
|
||||
script.onerror = () => setTelegramLinkStatus(t('telegram_auth_unavailable'), true);
|
||||
container.appendChild(script);
|
||||
setTelegramLinkStatus('');
|
||||
appendTelegramLoginWidget(
|
||||
container,
|
||||
botUsername,
|
||||
'onTelegramLinkAuth',
|
||||
() => setTelegramLinkStatus(t('telegram_auth_unavailable'), true)
|
||||
);
|
||||
state.telegramLinkRendered = true;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,575 +0,0 @@
|
||||
(function(window) {
|
||||
(function(window){
|
||||
window.__parseFunction = function(__func, __attrs) {
|
||||
__attrs = __attrs || [];
|
||||
__func = '(function(' + __attrs.join(',') + '){' + __func + '})';
|
||||
return window.execScript ? window.execScript(__func) : eval(__func);
|
||||
}
|
||||
}(window));
|
||||
(function(window){
|
||||
|
||||
function addEvent(el, event, handler) {
|
||||
var events = event.split(/\s+/);
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
if (el.addEventListener) {
|
||||
el.addEventListener(events[i], handler);
|
||||
} else {
|
||||
el.attachEvent('on' + events[i], handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
function removeEvent(el, event, handler) {
|
||||
var events = event.split(/\s+/);
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
if (el.removeEventListener) {
|
||||
el.removeEventListener(events[i], handler);
|
||||
} else {
|
||||
el.detachEvent('on' + events[i], handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
function getCssProperty(el, prop) {
|
||||
if (window.getComputedStyle) {
|
||||
return window.getComputedStyle(el, '').getPropertyValue(prop) || null;
|
||||
} else if (el.currentStyle) {
|
||||
return el.currentStyle[prop] || null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function geById(el_or_id) {
|
||||
if (typeof el_or_id == 'string' || el_or_id instanceof String) {
|
||||
return document.getElementById(el_or_id);
|
||||
} else if (el_or_id instanceof HTMLElement) {
|
||||
return el_or_id;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var getWidgetsOrigin = function(default_origin, dev_origin) {
|
||||
var link = document.createElement('A'), origin;
|
||||
link.href = document.currentScript && document.currentScript.src || default_origin;
|
||||
origin = link.origin || link.protocol + '//' + link.hostname;
|
||||
if (origin == 'https://telegram.org') {
|
||||
origin = default_origin;
|
||||
} else if (origin == 'https://telegram-js.azureedge.net' || origin == 'https://tg.dev') {
|
||||
origin = dev_origin;
|
||||
} else {
|
||||
origin = default_origin;
|
||||
}
|
||||
return origin;
|
||||
};
|
||||
|
||||
var getPageCanonical = function() {
|
||||
var a = document.createElement('A'), link, href;
|
||||
if (document.querySelector) {
|
||||
link = document.querySelector('link[rel="canonical"]');
|
||||
if (link && (href = link.getAttribute('href'))) {
|
||||
a.href = href;
|
||||
return a.href;
|
||||
}
|
||||
} else {
|
||||
var links = document.getElementsByTagName('LINK');
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
if ((link = links[i]) &&
|
||||
(link.getAttribute('rel') == 'canonical') &&
|
||||
(href = link.getAttribute('href'))) {
|
||||
a.href = href;
|
||||
return a.href;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
function haveTgAuthResult() {
|
||||
var locationHash = '', re = /[#\?\&]tgAuthResult=([A-Za-z0-9\-_=]*)$/, match;
|
||||
try {
|
||||
locationHash = location.hash.toString();
|
||||
if (match = locationHash.match(re)) {
|
||||
location.hash = locationHash.replace(re, '');
|
||||
var data = match[1] || '';
|
||||
data = data.replace(/-/g, '+').replace(/_/g, '/');
|
||||
var pad = data.length % 4;
|
||||
if (pad > 1) {
|
||||
data += new Array(5 - pad).join('=');
|
||||
}
|
||||
return JSON.parse(window.atob(data));
|
||||
}
|
||||
} catch (e) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getXHR() {
|
||||
if (navigator.appName == "Microsoft Internet Explorer"){
|
||||
return new ActiveXObject("Microsoft.XMLHTTP");
|
||||
} else {
|
||||
return new XMLHttpRequest();
|
||||
}
|
||||
}
|
||||
|
||||
if (!window.Telegram) {
|
||||
window.Telegram = {};
|
||||
}
|
||||
if (!window.Telegram.__WidgetUuid) {
|
||||
window.Telegram.__WidgetUuid = 0;
|
||||
}
|
||||
if (!window.Telegram.__WidgetLastId) {
|
||||
window.Telegram.__WidgetLastId = 0;
|
||||
}
|
||||
if (!window.Telegram.__WidgetCallbacks) {
|
||||
window.Telegram.__WidgetCallbacks = {};
|
||||
}
|
||||
|
||||
function postMessageToIframe(iframe, event, data, callback) {
|
||||
if (!iframe._ready) {
|
||||
if (!iframe._readyQueue) iframe._readyQueue = [];
|
||||
iframe._readyQueue.push([event, data, callback]);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
data = data || {};
|
||||
data.event = event;
|
||||
if (callback) {
|
||||
data._cb = ++window.Telegram.__WidgetLastId;
|
||||
window.Telegram.__WidgetCallbacks[data._cb] = {
|
||||
iframe: iframe,
|
||||
callback: callback
|
||||
};
|
||||
}
|
||||
iframe.contentWindow.postMessage(JSON.stringify(data), '*');
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
function initWidget(widgetEl) {
|
||||
var widgetId, widgetElId, widgetsOrigin, existsEl,
|
||||
src, styles = {}, allowedAttrs = [],
|
||||
defWidth, defHeight, scrollable = false, onInitAuthUser, onAuthUser, onUnauth;
|
||||
if (!widgetEl.tagName ||
|
||||
!(widgetEl.tagName.toUpperCase() == 'SCRIPT' ||
|
||||
widgetEl.tagName.toUpperCase() == 'BLOCKQUOTE' &&
|
||||
widgetEl.classList.contains('telegram-post'))) {
|
||||
return null;
|
||||
}
|
||||
if (widgetEl._iframe) {
|
||||
return widgetEl._iframe;
|
||||
}
|
||||
if (widgetId = widgetEl.getAttribute('data-telegram-post')) {
|
||||
var comment = widgetEl.getAttribute('data-comment') || '';
|
||||
widgetsOrigin = getWidgetsOrigin('https://t.me', 'https://post.tg.dev');
|
||||
widgetElId = 'telegram-post-' + widgetId.replace(/[^a-z0-9_]/ig, '-') + (comment ? '-comment' + comment : '');
|
||||
src = widgetsOrigin + '/' + widgetId + '?embed=1';
|
||||
allowedAttrs = ['comment', 'userpic', 'mode', 'single?', 'color', 'dark', 'dark_color'];
|
||||
defWidth = widgetEl.getAttribute('data-width') || '100%';
|
||||
defHeight = '';
|
||||
styles.minWidth = '320px';
|
||||
}
|
||||
else if (widgetId = widgetEl.getAttribute('data-telegram-discussion')) {
|
||||
widgetsOrigin = getWidgetsOrigin('https://t.me', 'https://post.tg.dev');
|
||||
widgetElId = 'telegram-discussion-' + widgetId.replace(/[^a-z0-9_]/ig, '-') + '-' + (++window.Telegram.__WidgetUuid);
|
||||
var websitePageUrl = widgetEl.getAttribute('data-page-url');
|
||||
if (!websitePageUrl) {
|
||||
websitePageUrl = getPageCanonical();
|
||||
}
|
||||
src = widgetsOrigin + '/' + widgetId + '?embed=1&discussion=1' + (websitePageUrl ? '&page_url=' + encodeURIComponent(websitePageUrl) : '');
|
||||
allowedAttrs = ['comments_limit', 'color', 'colorful', 'dark', 'dark_color', 'width', 'height'];
|
||||
defWidth = widgetEl.getAttribute('data-width') || '100%';
|
||||
defHeight = widgetEl.getAttribute('data-height') || 0;
|
||||
styles.minWidth = '320px';
|
||||
if (defHeight > 0) {
|
||||
scrollable = true;
|
||||
}
|
||||
}
|
||||
else if (widgetEl.hasAttribute('data-telegram-login')) {
|
||||
widgetId = widgetEl.getAttribute('data-telegram-login');
|
||||
widgetsOrigin = getWidgetsOrigin('https://oauth.telegram.org', 'https://oauth.tg.dev');
|
||||
widgetElId = 'telegram-login-' + widgetId.replace(/[^a-z0-9_]/ig, '-');
|
||||
src = widgetsOrigin + '/embed/' + widgetId + '?origin=' + encodeURIComponent(location.origin || location.protocol + '//' + location.hostname) + '&return_to=' + encodeURIComponent(location.href);
|
||||
allowedAttrs = ['size', 'userpic', 'init_auth', 'request_access', 'radius', 'min_width', 'max_width', 'lang'];
|
||||
defWidth = 186;
|
||||
defHeight = 28;
|
||||
if (widgetEl.hasAttribute('data-size')) {
|
||||
var size = widgetEl.getAttribute('data-size');
|
||||
if (size == 'small') defWidth = 148, defHeight = 20;
|
||||
else if (size == 'large') defWidth = 238, defHeight = 40;
|
||||
}
|
||||
if (widgetEl.hasAttribute('data-onauth')) {
|
||||
onInitAuthUser = onAuthUser = __parseFunction(widgetEl.getAttribute('data-onauth'), ['user']);
|
||||
}
|
||||
else if (widgetEl.hasAttribute('data-auth-url')) {
|
||||
var a = document.createElement('A');
|
||||
a.href = widgetEl.getAttribute('data-auth-url');
|
||||
onAuthUser = function(user) {
|
||||
var authUrl = a.href;
|
||||
authUrl += (authUrl.indexOf('?') >= 0) ? '&' : '?';
|
||||
var params = [];
|
||||
for (var key in user) {
|
||||
params.push(key + '=' + encodeURIComponent(user[key]));
|
||||
}
|
||||
authUrl += params.join('&');
|
||||
location.href = authUrl;
|
||||
};
|
||||
}
|
||||
if (widgetEl.hasAttribute('data-onunauth')) {
|
||||
onUnauth = __parseFunction(widgetEl.getAttribute('data-onunauth'));
|
||||
}
|
||||
var auth_result = haveTgAuthResult();
|
||||
if (auth_result && onAuthUser) {
|
||||
onAuthUser(auth_result);
|
||||
}
|
||||
}
|
||||
else if (widgetId = widgetEl.getAttribute('data-telegram-share-url')) {
|
||||
widgetsOrigin = getWidgetsOrigin('https://t.me', 'https://post.tg.dev');
|
||||
widgetElId = 'telegram-share-' + window.btoa(widgetId);
|
||||
src = widgetsOrigin + '/share/embed?origin=' + encodeURIComponent(location.origin || location.protocol + '//' + location.hostname);
|
||||
allowedAttrs = ['telegram-share-url', 'comment', 'size', 'text'];
|
||||
defWidth = 60;
|
||||
defHeight = 20;
|
||||
if (widgetEl.getAttribute('data-size') == 'large') {
|
||||
defWidth = 76;
|
||||
defHeight = 28;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
existsEl = document.getElementById(widgetElId);
|
||||
if (existsEl) {
|
||||
return existsEl;
|
||||
}
|
||||
for (var i = 0; i < allowedAttrs.length; i++) {
|
||||
var attr = allowedAttrs[i];
|
||||
var novalue = attr.substr(-1) == '?';
|
||||
if (novalue) {
|
||||
attr = attr.slice(0, -1);
|
||||
}
|
||||
var data_attr = 'data-' + attr.replace(/_/g, '-');
|
||||
if (widgetEl.hasAttribute(data_attr)) {
|
||||
var attr_value = novalue ? '1' : encodeURIComponent(widgetEl.getAttribute(data_attr));
|
||||
src += '&' + attr + '=' + attr_value;
|
||||
}
|
||||
}
|
||||
function getCurCoords(iframe) {
|
||||
var docEl = document.documentElement;
|
||||
var frect = iframe.getBoundingClientRect();
|
||||
return {
|
||||
frameTop: frect.top,
|
||||
frameBottom: frect.bottom,
|
||||
frameLeft: frect.left,
|
||||
frameRight: frect.right,
|
||||
frameWidth: frect.width,
|
||||
frameHeight: frect.height,
|
||||
scrollTop: window.pageYOffset,
|
||||
scrollLeft: window.pageXOffset,
|
||||
clientWidth: docEl.clientWidth,
|
||||
clientHeight: docEl.clientHeight
|
||||
};
|
||||
}
|
||||
function visibilityHandler() {
|
||||
if (isVisible(iframe, 50)) {
|
||||
postMessageToIframe(iframe, 'visible', {frame: widgetElId});
|
||||
}
|
||||
}
|
||||
function focusHandler() {
|
||||
postMessageToIframe(iframe, 'focus', {has_focus: document.hasFocus()});
|
||||
}
|
||||
function postMessageHandler(event) {
|
||||
if (event.source !== iframe.contentWindow ||
|
||||
event.origin != widgetsOrigin) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var data = JSON.parse(event.data);
|
||||
} catch(e) {
|
||||
var data = {};
|
||||
}
|
||||
if (data.event == 'resize') {
|
||||
if (data.height) {
|
||||
iframe.style.height = data.height + 'px';
|
||||
}
|
||||
if (data.width) {
|
||||
iframe.style.width = data.width + 'px';
|
||||
}
|
||||
}
|
||||
else if (data.event == 'ready') {
|
||||
iframe._ready = true;
|
||||
focusHandler();
|
||||
for (var i = 0; i < iframe._readyQueue.length; i++) {
|
||||
var queue_item = iframe._readyQueue[i];
|
||||
postMessageToIframe(iframe, queue_item[0], queue_item[1], queue_item[2]);
|
||||
}
|
||||
iframe._readyQueue = [];
|
||||
}
|
||||
else if (data.event == 'visible_off') {
|
||||
removeEvent(window, 'scroll', visibilityHandler);
|
||||
removeEvent(window, 'resize', visibilityHandler);
|
||||
}
|
||||
else if (data.event == 'get_coords') {
|
||||
postMessageToIframe(iframe, 'callback', {
|
||||
_cb: data._cb,
|
||||
value: getCurCoords(iframe)
|
||||
});
|
||||
}
|
||||
else if (data.event == 'scroll_to') {
|
||||
try {
|
||||
window.scrollTo(data.x || 0, data.y || 0);
|
||||
} catch(e) {}
|
||||
}
|
||||
else if (data.event == 'auth_user') {
|
||||
if (data.init) {
|
||||
onInitAuthUser && onInitAuthUser(data.auth_data);
|
||||
} else {
|
||||
onAuthUser && onAuthUser(data.auth_data);
|
||||
}
|
||||
}
|
||||
else if (data.event == 'unauthorized') {
|
||||
onUnauth && onUnauth();
|
||||
}
|
||||
else if (data.event == 'callback') {
|
||||
var cb_data = null;
|
||||
if (cb_data = window.Telegram.__WidgetCallbacks[data._cb]) {
|
||||
if (cb_data.iframe === iframe) {
|
||||
cb_data.callback(data.value);
|
||||
delete window.Telegram.__WidgetCallbacks[data._cb];
|
||||
}
|
||||
} else {
|
||||
console.warn('Callback #' + data._cb + ' not found');
|
||||
}
|
||||
}
|
||||
}
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.id = widgetElId;
|
||||
iframe.src = src;
|
||||
iframe.width = defWidth;
|
||||
iframe.height = defHeight;
|
||||
iframe.setAttribute('frameborder', '0');
|
||||
if (!scrollable) {
|
||||
iframe.setAttribute('scrolling', 'no');
|
||||
iframe.style.overflow = 'hidden';
|
||||
}
|
||||
iframe.style.colorScheme = 'light dark';
|
||||
iframe.style.border = 'none';
|
||||
for (var prop in styles) {
|
||||
iframe.style[prop] = styles[prop];
|
||||
}
|
||||
if (widgetEl.parentNode) {
|
||||
widgetEl.parentNode.insertBefore(iframe, widgetEl);
|
||||
if (widgetEl.tagName.toUpperCase() == 'BLOCKQUOTE') {
|
||||
widgetEl.parentNode.removeChild(widgetEl);
|
||||
}
|
||||
}
|
||||
iframe._ready = false;
|
||||
iframe._readyQueue = [];
|
||||
widgetEl._iframe = iframe;
|
||||
addEvent(iframe, 'load', function() {
|
||||
removeEvent(iframe, 'load', visibilityHandler);
|
||||
addEvent(window, 'scroll', visibilityHandler);
|
||||
addEvent(window, 'resize', visibilityHandler);
|
||||
visibilityHandler();
|
||||
});
|
||||
addEvent(window, 'focus blur', focusHandler);
|
||||
addEvent(window, 'message', postMessageHandler);
|
||||
return iframe;
|
||||
}
|
||||
function isVisible(el, padding) {
|
||||
var node = el, val;
|
||||
var visibility = getCssProperty(node, 'visibility');
|
||||
if (visibility == 'hidden') return false;
|
||||
while (node) {
|
||||
if (node === document.documentElement) break;
|
||||
var display = getCssProperty(node, 'display');
|
||||
if (display == 'none') return false;
|
||||
var opacity = getCssProperty(node, 'opacity');
|
||||
if (opacity !== null && opacity < 0.1) return false;
|
||||
node = node.parentNode;
|
||||
}
|
||||
if (el.getBoundingClientRect) {
|
||||
padding = +padding || 0;
|
||||
var rect = el.getBoundingClientRect();
|
||||
var html = document.documentElement;
|
||||
if (rect.bottom < padding ||
|
||||
rect.right < padding ||
|
||||
rect.top > (window.innerHeight || html.clientHeight) - padding ||
|
||||
rect.left > (window.innerWidth || html.clientWidth) - padding) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getAllWidgets() {
|
||||
var widgets = [];
|
||||
if (document.querySelectorAll) {
|
||||
widgets = document.querySelectorAll('script[data-telegram-post],blockquote.telegram-post,script[data-telegram-discussion],script[data-telegram-login],script[data-telegram-share-url]');
|
||||
} else {
|
||||
widgets = Array.prototype.slice.apply(document.getElementsByTagName('SCRIPT'));
|
||||
widgets = widgets.concat(Array.prototype.slice.apply(document.getElementsByTagName('BLOCKQUOTE')));
|
||||
}
|
||||
return widgets;
|
||||
}
|
||||
|
||||
function getWidgetInfo(el_or_id, callback) {
|
||||
var e = null, iframe = null;
|
||||
if (el = geById(el_or_id)) {
|
||||
if (el.tagName &&
|
||||
el.tagName.toUpperCase() == 'IFRAME') {
|
||||
iframe = el;
|
||||
} else if (el._iframe) {
|
||||
iframe = el._iframe;
|
||||
}
|
||||
if (iframe && callback) {
|
||||
postMessageToIframe(iframe, 'get_info', {}, callback);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setWidgetOptions(options, el_or_id) {
|
||||
var e = null, iframe = null;
|
||||
if (typeof el_or_id === 'undefined') {
|
||||
var widgets = getAllWidgets();
|
||||
for (var i = 0; i < widgets.length; i++) {
|
||||
if (iframe = widgets[i]._iframe) {
|
||||
postMessageToIframe(iframe, 'set_options', {options: options});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (el = geById(el_or_id)) {
|
||||
if (el.tagName &&
|
||||
el.tagName.toUpperCase() == 'IFRAME') {
|
||||
iframe = el;
|
||||
} else if (el._iframe) {
|
||||
iframe = el._iframe;
|
||||
}
|
||||
if (iframe) {
|
||||
postMessageToIframe(iframe, 'set_options', {options: options});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!document.currentScript ||
|
||||
!initWidget(document.currentScript)) {
|
||||
var widgets = getAllWidgets();
|
||||
for (var i = 0; i < widgets.length; i++) {
|
||||
initWidget(widgets[i]);
|
||||
}
|
||||
}
|
||||
|
||||
var TelegramLogin = {
|
||||
popups: {},
|
||||
options: null,
|
||||
auth_callback: null,
|
||||
_init: function(options, auth_callback) {
|
||||
TelegramLogin.options = options;
|
||||
TelegramLogin.auth_callback = auth_callback;
|
||||
var auth_result = haveTgAuthResult();
|
||||
if (auth_result && auth_callback) {
|
||||
auth_callback(auth_result);
|
||||
}
|
||||
},
|
||||
_open: function(callback) {
|
||||
TelegramLogin._auth(TelegramLogin.options, function(authData) {
|
||||
if (TelegramLogin.auth_callback) {
|
||||
TelegramLogin.auth_callback(authData);
|
||||
}
|
||||
if (callback) {
|
||||
callback(authData);
|
||||
}
|
||||
});
|
||||
},
|
||||
_auth: function(options, callback) {
|
||||
var bot_id = parseInt(options.bot_id);
|
||||
if (!bot_id) {
|
||||
throw new Error('Bot id required');
|
||||
}
|
||||
var width = 550;
|
||||
var height = 470;
|
||||
var left = Math.max(0, (screen.width - width) / 2) + (screen.availLeft | 0),
|
||||
top = Math.max(0, (screen.height - height) / 2) + (screen.availTop | 0);
|
||||
var onMessage = function (event) {
|
||||
try {
|
||||
var data = JSON.parse(event.data);
|
||||
} catch(e) {
|
||||
var data = {};
|
||||
}
|
||||
if (!TelegramLogin.popups[bot_id]) return;
|
||||
if (event.source !== TelegramLogin.popups[bot_id].window) return;
|
||||
if (data.event == 'auth_result') {
|
||||
onAuthDone(data.result);
|
||||
}
|
||||
};
|
||||
var onAuthDone = function (authData) {
|
||||
if (!TelegramLogin.popups[bot_id]) return;
|
||||
if (TelegramLogin.popups[bot_id].authFinished) return;
|
||||
callback && callback(authData);
|
||||
TelegramLogin.popups[bot_id].authFinished = true;
|
||||
removeEvent(window, 'message', onMessage);
|
||||
};
|
||||
var checkClose = function(bot_id) {
|
||||
if (!TelegramLogin.popups[bot_id]) return;
|
||||
if (!TelegramLogin.popups[bot_id].window ||
|
||||
TelegramLogin.popups[bot_id].window.closed) {
|
||||
return TelegramLogin.getAuthData(options, function(origin, authData) {
|
||||
onAuthDone(authData);
|
||||
});
|
||||
}
|
||||
setTimeout(checkClose, 100, bot_id);
|
||||
}
|
||||
var popup_url = Telegram.Login.widgetsOrigin + '/auth?bot_id=' + encodeURIComponent(options.bot_id) + '&origin=' + encodeURIComponent(location.origin || location.protocol + '//' + location.hostname) + (options.request_access ? '&request_access=' + encodeURIComponent(options.request_access) : '') + (options.lang ? '&lang=' + encodeURIComponent(options.lang) : '') + '&return_to=' + encodeURIComponent(location.href);
|
||||
var popup = window.open(popup_url, 'telegram_oauth_bot' + bot_id, 'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',status=0,location=0,menubar=0,toolbar=0');
|
||||
TelegramLogin.popups[bot_id] = {
|
||||
window: popup,
|
||||
authFinished: false
|
||||
};
|
||||
if (popup) {
|
||||
addEvent(window, 'message', onMessage);
|
||||
popup.focus();
|
||||
checkClose(bot_id);
|
||||
}
|
||||
},
|
||||
getAuthData: function(options, callback) {
|
||||
var bot_id = parseInt(options.bot_id);
|
||||
if (!bot_id) {
|
||||
throw new Error('Bot id required');
|
||||
}
|
||||
var xhr = getXHR();
|
||||
var url = Telegram.Login.widgetsOrigin + '/auth/get';
|
||||
xhr.open('POST', url);
|
||||
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
|
||||
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState == 4) {
|
||||
if (typeof xhr.responseBody == 'undefined' && xhr.responseText) {
|
||||
try {
|
||||
var result = JSON.parse(xhr.responseText);
|
||||
} catch(e) {
|
||||
var result = {};
|
||||
}
|
||||
if (result.user) {
|
||||
callback(result.origin, result.user);
|
||||
} else {
|
||||
callback(result.origin, false);
|
||||
}
|
||||
} else {
|
||||
callback('*', false);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhr.onerror = function() {
|
||||
callback('*', false);
|
||||
};
|
||||
xhr.withCredentials = true;
|
||||
xhr.send('bot_id=' + encodeURIComponent(options.bot_id) + (options.lang ? '&lang=' + encodeURIComponent(options.lang) : ''));
|
||||
}
|
||||
};
|
||||
|
||||
window.Telegram.getWidgetInfo = getWidgetInfo;
|
||||
window.Telegram.setWidgetOptions = setWidgetOptions;
|
||||
window.Telegram.Login = {
|
||||
init: TelegramLogin._init,
|
||||
open: TelegramLogin._open,
|
||||
auth: TelegramLogin._auth,
|
||||
widgetsOrigin: getWidgetsOrigin('https://oauth.telegram.org', 'https://oauth.tg.dev')
|
||||
};
|
||||
|
||||
}(window));
|
||||
})(window);
|
||||
@@ -1,7 +1,6 @@
|
||||
import hmac
|
||||
import asyncio
|
||||
import logging
|
||||
from contextlib import suppress
|
||||
|
||||
from aiohttp import web
|
||||
from aiogram import Bot, Dispatcher
|
||||
@@ -17,8 +16,6 @@ class SecureSimpleRequestHandler(SimpleRequestHandler):
|
||||
return False
|
||||
return hmac.compare_digest(telegram_secret_token, self.secret_token)
|
||||
|
||||
TELEGRAM_WEB_APP_SDK_REFRESH_INTERVAL_SECONDS = 24 * 60 * 60
|
||||
|
||||
|
||||
def _inject_shared_instances(
|
||||
app: web.Application,
|
||||
@@ -132,13 +129,8 @@ async def build_and_start_web_app(
|
||||
f"AIOHTTP server started on http://{settings.WEB_SERVER_HOST}:{settings.WEB_SERVER_PORT}"
|
||||
)
|
||||
|
||||
telegram_web_app_sdk_refresh_task = None
|
||||
if settings.WEBAPP_ENABLED:
|
||||
from bot.app.web.subscription_webapp import (
|
||||
create_subscription_webapp_application,
|
||||
refresh_telegram_login_widget_sdk,
|
||||
refresh_telegram_web_app_sdk,
|
||||
)
|
||||
from bot.app.web.subscription_webapp import create_subscription_webapp_application
|
||||
|
||||
subscription_app = create_subscription_webapp_application(
|
||||
dp,
|
||||
@@ -161,25 +153,9 @@ async def build_and_start_web_app(
|
||||
settings.WEBAPP_SERVER_PORT,
|
||||
)
|
||||
|
||||
async def _refresh_telegram_web_assets_forever() -> None:
|
||||
while True:
|
||||
await refresh_telegram_web_app_sdk()
|
||||
await refresh_telegram_login_widget_sdk()
|
||||
await asyncio.sleep(TELEGRAM_WEB_APP_SDK_REFRESH_INTERVAL_SECONDS)
|
||||
|
||||
telegram_web_app_sdk_refresh_task = asyncio.create_task(
|
||||
_refresh_telegram_web_assets_forever(),
|
||||
name="TelegramWebAssetsRefreshTask",
|
||||
)
|
||||
|
||||
try:
|
||||
await asyncio.Event().wait()
|
||||
finally:
|
||||
if telegram_web_app_sdk_refresh_task is not None:
|
||||
telegram_web_app_sdk_refresh_task.cancel()
|
||||
with suppress(asyncio.CancelledError):
|
||||
await telegram_web_app_sdk_refresh_task
|
||||
|
||||
for runner in reversed(runners):
|
||||
try:
|
||||
await runner.cleanup()
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
|
||||
SOURCE_URL = "https://telegram.org/js/telegram-web-app.js"
|
||||
TARGET_PATH = (
|
||||
Path(__file__).resolve().parents[1]
|
||||
/ "bot"
|
||||
/ "app"
|
||||
/ "web"
|
||||
/ "templates"
|
||||
/ "telegram-web-app.js"
|
||||
)
|
||||
|
||||
|
||||
def _download(source_url: str) -> bytes:
|
||||
request = Request(
|
||||
source_url,
|
||||
headers={
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
"Accept": "application/javascript,text/javascript,*/*;q=0.8",
|
||||
},
|
||||
)
|
||||
with urlopen(request, timeout=30) as response:
|
||||
return response.read()
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Download the latest Telegram Web App SDK into the local templates directory."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--source-url",
|
||||
default=SOURCE_URL,
|
||||
help="Telegram Web App SDK URL to download from.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target",
|
||||
type=Path,
|
||||
default=TARGET_PATH,
|
||||
help="Output path for the vendored SDK.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
data = _download(args.source_url)
|
||||
args.target.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.target.write_bytes(data)
|
||||
print(f"Wrote {len(data)} bytes to {args.target}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -1,70 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
|
||||
SOURCE_URL = "https://telegram.org/js/telegram-widget.js?23"
|
||||
TARGET_PATH = (
|
||||
Path(__file__).resolve().parents[1]
|
||||
/ "bot"
|
||||
/ "app"
|
||||
/ "web"
|
||||
/ "templates"
|
||||
/ "telegram-widget.js"
|
||||
)
|
||||
_UNPATCHED_WIDGET_ORIGIN_SNIPPET = """ if (origin == 'https://telegram.org') {\n origin = default_origin;\n } else if (origin == 'https://telegram-js.azureedge.net' || origin == 'https://tg.dev') {\n origin = dev_origin;\n }\n"""
|
||||
_PATCHED_WIDGET_ORIGIN_SNIPPET = """ if (origin == 'https://telegram.org') {\n origin = default_origin;\n } else if (origin == 'https://telegram-js.azureedge.net' || origin == 'https://tg.dev') {\n origin = dev_origin;\n } else {\n origin = default_origin;\n }\n"""
|
||||
|
||||
|
||||
def _download(source_url: str) -> bytes:
|
||||
request = Request(
|
||||
source_url,
|
||||
headers={
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
"Accept": "application/javascript,text/javascript,*/*;q=0.8",
|
||||
},
|
||||
)
|
||||
with urlopen(request, timeout=30) as response:
|
||||
return response.read()
|
||||
|
||||
|
||||
def _normalize_widget_sdk(data: bytes) -> bytes:
|
||||
# Keep the vendored widget pointing to Telegram's OAuth host instead of the local origin.
|
||||
text = data.decode("utf-8")
|
||||
normalized = text.replace(
|
||||
_UNPATCHED_WIDGET_ORIGIN_SNIPPET,
|
||||
_PATCHED_WIDGET_ORIGIN_SNIPPET,
|
||||
1,
|
||||
)
|
||||
return normalized.encode("utf-8")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Download the latest Telegram Login Widget SDK into the local templates directory."
|
||||
)
|
||||
parser.add_argument(
|
||||
"--source-url",
|
||||
default=SOURCE_URL,
|
||||
help="Telegram Login Widget SDK URL to download from.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--target",
|
||||
type=Path,
|
||||
default=TARGET_PATH,
|
||||
help="Output path for the vendored SDK.",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
data = _normalize_widget_sdk(_download(args.source_url))
|
||||
args.target.parent.mkdir(parents=True, exist_ok=True)
|
||||
args.target.write_bytes(data)
|
||||
print(f"Wrote {len(data)} bytes to {args.target}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user