diff --git a/CHANGELOG.en.md b/CHANGELOG.en.md index 4f06dae0..b2ac274d 100644 --- a/CHANGELOG.en.md +++ b/CHANGELOG.en.md @@ -22,6 +22,7 @@ The English translation covers the latest versions only; the full history (in Ru - [phone] A subscription page has edit, pause and delete in the header, a poster, quality chips, notifications, a link to the card and a check count - [phone] The subscription sheet keeps Delete and Save above the system bar. A swipe down with unsaved edits asks whether to save them. Releases already found do not notify - [phone] An episode is no longer marked watched because the file was only preloaded or probed. The mark needs a real watch or a manual mark +- [tech] Billing: a separate Crypto Pay testnet token (`CRYPTO_PAY_TESTNET_TOKEN`). The testnet switch picks the token and the host together. Invoice creation and the `/v1/crypto-pay` signature use only the active mode. With testnet on and no testnet token, crypto stays disabled and the live token is not sent there. A webhook signed by the other mode returns 200, is logged as ignored, and does not extend a subscription. The billing image was not deployed - [phone] Catalog: one, two or three cards a row, list and compact. The poster keeps quality on the left and the season line at the bottom, plus watching and a progress bar. The list has a status line and no size - [phone] Search: plus opens magnet paste and a .torrent file, and a pasted magnet on any tab opens add. An http(s) .torrent link from another app is added the same way. A file error is visible at once. The feed line drops the tracker phrase, and 0-1 seeds are marked. The sources hint is one line with a close button - [phone] Calendar lists days, Earlier stays folded, and the aired/today plates are gone. Month view marks today with a yellow circle, the selected day in gray, up to three dots plus a count, and a yellow dot for a subscription. A subscription that is any quality and best-only reads "best" diff --git a/CHANGELOG.md b/CHANGELOG.md index ad03a8ac..41025fd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,7 @@ - [phone] Карточка подписки: правки, пауза и удаление в шапке, постер, чипы качества, уведомления, ссылка на карточку и счетчик проверок - [phone] Лист подписки: «Удалить» и «Сохранить» остаются над системной панелью. Свайп вниз с несохраненными правками спрашивает, сохранить ли их. Уже найденные раздачи не присылают уведомление - [phone] Серия больше не помечается «Просмотрено» от предзагрузки или проверки файла. Отметка только после реального просмотра или ручной пометки +- [tech] Биллинг: отдельный токен Crypto Pay для testnet (`CRYPTO_PAY_TESTNET_TOKEN`). Переключатель testnet выбирает токен и хост вместе. Счёт и подпись вебхука `/v1/crypto-pay` идут только в активный режим. Без testnet-токена крипта в testnet выключена, боевой токен туда не уходит. Вебхук другого режима отвечает 200 и пишется как игнорированный, подписку не продлевает. Образ биллинга не выкатывался - [phone] Каталог: одна, две или три карточки в ряд, список и компактный вид. На постере качество слева и строка сезонов снизу, «смотрите» с полоской. В списке строка статуса, без размера - [phone] Поиск: «+» для magnet и файла .torrent, вставленная magnet-ссылка на любой вкладке открывает добавление. Ссылка http(s) на .torrent из другого приложения добавляется так же. Ошибка файла видна сразу. В ленте короткая строка размера и сидов без «по данным трекера», 0-1 сид выделен. Подсказка источников - одна строка с крестиком - [phone] Календарь: список по дням, «Ранее» свернуто, без плашек «сегодня» и «вышла». В месяце сегодня - желтый круг, выбранный день серый, до трех точек и счетчик, желтая точка у подписки. У подписки «любое качество» и «только лучшее» пишется «лучшее» diff --git a/ops/billing/README.md b/ops/billing/README.md index 7919f16c..838d3041 100644 --- a/ops/billing/README.md +++ b/ops/billing/README.md @@ -64,6 +64,7 @@ HSTS (`max-age=15552000; includeSubDomains`, без preload), `X-Content-Type-Op | Токен бота | `BILLING_BOT_TOKEN` | | Секрет ЮMoney | `BILLING_YOOMONEY_SECRET` | | Токен Crypto Pay | `CRYPTO_PAY_TOKEN` | +| Токен Crypto Pay (testnet) | `CRYPTO_PAY_TESTNET_TOKEN` | | SMTP-пароль | `BILLING_SMTP_PASS` | | Ключ API Jackett | `BILLING_JACKETT_API_KEY` | | Ключ API JacRed | `BILLING_JACRED_API_KEY` | @@ -126,14 +127,15 @@ sudo $DC up -d --no-deps billing # | --- | --- | | Включить звёзды, цена подписки и доп. устройства в звёздах | **Настройки**, группа **Звёзды** | | Включить крипту, цены USDT/TON/BTC, курс ₽ за 1, testnet, только не из РФ | **Настройки**, группа **Крипта** | -| Токен Crypto Pay | `CRYPTO_PAY_TOKEN` в `.env`. В админке только «задан» и маска. В лог токен не пишется | -| Вебхук Crypto Pay | `POST /v1/crypto-pay`. Подпись `crypto-pay-api-signature` - HMAC-SHA256 сырого тела, ключ SHA256 токена | -| Testnet | Переключатель в админке. Хост `testnet-pay.crypt.bot`, токен тот же `CRYPTO_PAY_TOKEN` (тестовый токен кладётся в эту переменную) | +| Токен Crypto Pay | `CRYPTO_PAY_TOKEN` в `.env`, хост `pay.crypt.bot`. В админке только «задан» и маска. В лог токен не пишется | +| Токен Crypto Pay (testnet) | `CRYPTO_PAY_TESTNET_TOKEN` в `.env`. В админке только «задан» и маска. В лог токен не пишется | +| Вебхук Crypto Pay | `POST /v1/crypto-pay`. Подпись `crypto-pay-api-signature` - HMAC-SHA256 сырого тела, ключ SHA256 токена активного режима | +| Testnet | Переключатель в админке. Включен: хост `testnet-pay.crypt.bot` и `CRYPTO_PAY_TESTNET_TOKEN`. Выключен: `pay.crypt.bot` и `CRYPTO_PAY_TOKEN`. Если testnet включен, а `CRYPTO_PAY_TESTNET_TOKEN` пуст, счёт не создаётся (`disabled`), боевой токен на testnet не отправляется. Уже созданная ссылка другого режима не выдаётся повторно: у каждого режима своя ссылка, ссылка того же режима переиспользуется. Вебхук принимает подпись только активного режима. Подпись другого режима отвечает `200`, пишется в журнал как игнорированная и подписку не продлевает | | Ссылка крипты | В боте (кнопка на сайт Crypto Pay и кнопка Crypto Bot) и в приложении, кнопка «Криптой». Сайт omp-player.online на это указывает | | Возврат звёзд | Карточка пользователя, «Вернуть звёзды» (`refundStarPayment`). Дни этой кнопкой не снимаются | | Выручка | Вкладка **Финансы**, блок «по способам». В таблице заказов есть колонка «Способ» | -`pre_checkout_query` только проверяет счёт и не включает подписку. `successful_payment` с валютой XTR включает её. Недоплата (сумма меньше заказа, другая валюта, чужой invoice id) записывается как ошибка и подписку не включает. Неверная подпись Crypto Pay - `400`. Повтор уже принятого вебхука - `200` и без второго продления. +`pre_checkout_query` только проверяет счёт и не включает подписку. `successful_payment` с валютой XTR включает её. Недоплата (сумма меньше заказа, другая валюта, чужой invoice id) записывается как ошибка и подписку не включает. Неверная подпись Crypto Pay - `400`. Подпись неактивного режима - `200` без продления. Повтор уже принятого вебхука - `200` и без второго продления. Флаг «только не из РФ» смотрит код страны Cloudflare (`CF-IPCountry`). Пустой код и `RU` ссылку не выдают. Бот узнаёт страну из последнего захода приложения. diff --git a/ops/billing/admin/src/lib/text.ts b/ops/billing/admin/src/lib/text.ts index 19d15ad5..f9c92883 100644 --- a/ops/billing/admin/src/lib/text.ts +++ b/ops/billing/admin/src/lib/text.ts @@ -95,6 +95,7 @@ const PROBLEM_KIND: Record = { duplicate: 'повтор уведомления', amount: 'неверная сумма', bad_signature: 'неверная подпись', + ignored: 'игнорирован', webhook: 'уведомление', no_account: 'нет аккаунта', no_subscription: 'нет подписки', diff --git a/ops/billing/admin/src/panels/sections.tsx b/ops/billing/admin/src/panels/sections.tsx index dc468614..cf6f64ad 100644 --- a/ops/billing/admin/src/panels/sections.tsx +++ b/ops/billing/admin/src/panels/sections.tsx @@ -584,6 +584,7 @@ const SETTING_GROUPS: { title: string; fields: [string, string][] }[] = [ ['yoomoneyWallet', 'Кошелёк ЮMoney'], ['yoomoneySecret', 'Секрет ЮMoney'], ['cryptoPayToken', 'Токен Crypto Pay'], + ['cryptoPayTestnetToken', 'Токен Crypto Pay (testnet)'], ], }, { @@ -641,7 +642,7 @@ const SETTING_GROUPS: { title: string; fields: [string, string][] }[] = [ ]; /** Secrets are read-only in the panel: they live in the server's .env. */ -const SECRET_KEYS = new Set(['botToken', 'yoomoneySecret', 'cryptoPayToken', 'smtpPass', 'jackettApiKey', 'jacredApiKey', 'indexerPass']); +const SECRET_KEYS = new Set(['botToken', 'yoomoneySecret', 'cryptoPayToken', 'cryptoPayTestnetToken', 'smtpPass', 'jackettApiKey', 'jacredApiKey', 'indexerPass']); /** One read-only secret: «задан ✅, ****abcd» or «не задан», and where it changes. */ function SecretField({ name, label, view, fallback }: { name: string; label: string; view?: SecretView; fallback?: string }) { @@ -827,7 +828,8 @@ export function SettingsCard({ setCryptoTest(e.target.checked); }} /> - Тестовая сеть Crypto Pay (testnet-pay.crypt.bot). Токен всё равно берётся из CRYPTO_PAY_TOKEN. + Тестовая сеть Crypto Pay (testnet-pay.crypt.bot). Токен этого режима:{' '} + {cryptoTest ? String(settings.cryptoPayTestnetToken || 'не задан') : String(settings.cryptoPayToken || 'не задан')}.