From 50f7f713935fbff9ec4cd132d8c488495244920b Mon Sep 17 00:00:00 2001 From: Navis Date: Sun, 2 Aug 2026 15:40:13 +0300 Subject: [PATCH] Add site contacts/FAQ and accept AWG 2.0 / naive pastes in Add config. ImportSubscription no longer requires only http(s): paste awg://, AWG .conf/JSON, or naive links; subscription parser also reads hosted AWG and Clash wireguard/naive. Site lists support emails and FAQ; Store listing texts/tools updated. Co-authored-by: Cursor --- Site/index.html | 650 ++++++++++++++++++ Site/privacy-en.html | 260 +++++++ Site/privacy-ru.html | 260 +++++++ Site/privacy.html | 12 + Site/terms-en.html | 144 ++++ Site/terms-ru.html | 146 ++++ Site/terms.html | 12 + dist/microsoft-store/AdditionalLicense.en.txt | 15 + dist/microsoft-store/AdditionalLicense.ru.txt | 15 + dist/microsoft-store/Copyright.en.txt | 1 + dist/microsoft-store/Copyright.ru.txt | 1 + dist/microsoft-store/README.txt | 21 +- dist/microsoft-store/WhatsNew.en.txt | 16 + dist/microsoft-store/WhatsNew.ru.txt | 16 + .../listing/screen/1.ru.300x300.png | Bin 0 -> 39700 bytes dist/microsoft-store/listing/store.csv | 74 +- docs/privacy-en.md | 3 +- docs/privacy-ru.md | 3 +- docs/terms-en.md | 3 +- docs/terms-ru.md | 3 +- internal/apphost/app.go | 25 +- internal/appui/index.html | 33 +- internal/core/manager.go | 25 +- internal/core/manager_test.go | 57 ++ internal/subscription/fetch.go | 301 ++++++-- internal/subscription/fetch_test.go | 159 +++++ packaging/msix/AppxManifest.xml | 6 +- screen/1.ru.300x300.fit.png | Bin 0 -> 33267 bytes screen/1.ru.300x300.png | Bin 0 -> 39700 bytes scripts/pack-msix.ps1 | 28 +- store.csv | 74 +- tools/fill_store_csv.py | 218 ++++++ tools/fillstore/additional_license.go | 59 ++ tools/fillstore/copyright.go | 61 ++ tools/fillstore/logo300.go | 18 + tools/fillstore/main.go | 191 +++++ tools/fillstore/notes.go | 63 ++ tools/fillstore/shots.go | 185 +++++ tools/mk300/main.go | 82 +++ 39 files changed, 3128 insertions(+), 112 deletions(-) create mode 100644 Site/index.html create mode 100644 Site/privacy-en.html create mode 100644 Site/privacy-ru.html create mode 100644 Site/privacy.html create mode 100644 Site/terms-en.html create mode 100644 Site/terms-ru.html create mode 100644 Site/terms.html create mode 100644 dist/microsoft-store/AdditionalLicense.en.txt create mode 100644 dist/microsoft-store/AdditionalLicense.ru.txt create mode 100644 dist/microsoft-store/Copyright.en.txt create mode 100644 dist/microsoft-store/Copyright.ru.txt create mode 100644 dist/microsoft-store/WhatsNew.en.txt create mode 100644 dist/microsoft-store/WhatsNew.ru.txt create mode 100644 dist/microsoft-store/listing/screen/1.ru.300x300.png create mode 100644 screen/1.ru.300x300.fit.png create mode 100644 screen/1.ru.300x300.png create mode 100644 tools/fill_store_csv.py create mode 100644 tools/fillstore/additional_license.go create mode 100644 tools/fillstore/copyright.go create mode 100644 tools/fillstore/logo300.go create mode 100644 tools/fillstore/main.go create mode 100644 tools/fillstore/notes.go create mode 100644 tools/fillstore/shots.go create mode 100644 tools/mk300/main.go diff --git a/Site/index.html b/Site/index.html new file mode 100644 index 0000000..13d457d --- /dev/null +++ b/Site/index.html @@ -0,0 +1,650 @@ + + + + + + EvilFox — Apps + + + + + + + +
+ + + +
+ +
+ + +
+
+ +
+
+

Студия приложений

+

EvilFox

+

Приложения для безопасного и спокойного интернета. Начните с EvilFox VPN — дальше появятся новые продукты.

+

EvilFox — это локальный клиент: вы сами добавляете конфигурации и URL подключения. Шифрование, выбор серверов, Kill Switch, светлая и тёмная темы, русский и английский интерфейс. Сборка для Windows, в том числе Microsoft Store.

+
    +
  • Современные протоколы и группировка серверов по странам
  • +
  • Режимы полной защиты и системного прокси
  • +
  • Данные профилей хранятся на устройстве — без обязательной регистрации
  • +
+ +
+ +
+ +
+
+

Наши приложения

+

Каталог продуктов EvilFox. Сейчас доступен VPN-клиент; другие приложения — скоро.

+
+
+ +
🦊
+

EvilFox VPN

+

Клиент для защищённого доступа в интернет на Windows: современные протоколы, флаги серверов, Kill Switch, светлая и тёмная темы, русский и английский.

+
+ Доступно + Открыть → +
+
+
+
+

Скоро

+

Новое приложение вне VPN — в разработке. Следите за обновлениями на сайте.

+
+ В планах +
+
+
+
+

Ещё проекты

+

Инструменты для работы и повседневных задач — появятся здесь позже.

+
+ В планах +
+
+
+
+ +
+
+

Частые вопросы

+

Кратко о клиенте, данных и поддержке. Если ответа нет — напишите нам.

+
+
+
+ Что такое EvilFox? +

EvilFox — Windows-клиент для защищённого доступа в интернет. Вы подключаетесь к серверам по своим конфигурациям; мы публикуем приложение и обновления.

+
+
+ Нужна ли регистрация или аккаунт? +

Нет обязательного аккаунта у издателя. Профили и настройки хранятся локально. URL и ключи подключения вы получаете у своего провайдера конфигурации.

+
+
+ Собираете ли вы мой трафик? +

Клиент работает на устройстве. EvilFox как издатель не ведёт централизованный сбор содержимого вашего трафика для рекламы. При подключении трафик идёт через серверы из вашей конфигурации — их политика может отличаться.

+
+
+ На каких платформах доступно приложение? +

Основная платформа — Windows (включая Microsoft Store). Следите за каталогом на сайте: появятся и другие продукты EvilFox.

+
+
+ Что делает Kill Switch? +

Kill Switch помогает ограничить незащищённый доступ в сеть, если защищённое соединение обрывается. Включайте в настройках приложения, если нужна такая защита.

+
+
+ Как связаться с поддержкой? +

Напишите на animegold3@gmail.com или резервную admin@evilfox.win. Также есть Telegram: t.me/evilfox100Bot.

+
+
+
+ +
+
+

Связаться с нами

+

Напишите на почту — ответим по вопросам приложений и поддержки.

+
+
+ Основная почта + animegold3@gmail.com +
+
+ Резервная почта + admin@evilfox.win +
+
+ Telegram + t.me/evilfox100Bot +
+
+
+
+ + +
+ + + + diff --git a/Site/privacy-en.html b/Site/privacy-en.html new file mode 100644 index 0000000..55a2758 --- /dev/null +++ b/Site/privacy-en.html @@ -0,0 +1,260 @@ + + + + + + Privacy Policy — EvilFox + + + + + + + +
+
+ + +
+

EvilFox

+ evilfox.win +
+
+ +
+ +
+

Privacy Policy

+

+ Publisher / controller (for on-device data): EvilFox
+ Effective date: August 2, 2026 · Document version: 1.0
+ Applies to the EvilFox Windows app (including the Microsoft Store build) and related pages on evilfox.win. +

+ + + +

1. Who we are and what this Policy covers

+

EvilFox is a local Windows client for protected network connectivity (proxy mode and full-protection / TUN mode, modern protocols). You add your own configurations and connection URLs. The Microsoft Store build has no in-app purchases.

+

This Privacy Policy explains what data may be processed when you use the App, for what purposes, how long it is kept, what rights you have, and how to contact us. We aim to meet Microsoft Store transparency expectations and the expectations of users in the United States and the European Union / EEA / United Kingdom.

+

In short: most data stays on your device. We do not sell personal data and do not build an advertising profile from the contents of your traffic.

+ +

2. Scope and roles

+

2.1. What is covered

+
    +
  • the EvilFox application (Windows, including MSIX / Microsoft Store);
  • +
  • policy and terms pages on evilfox.win;
  • +
  • support requests sent to the contacts listed below.
  • +
+

2.2. Roles

+
    +
  • EvilFox (client publisher) — controller for data the App stores and processes locally on your device to run the client.
  • +
  • Server operator / configuration provider — a separate party (you or your provider). When traffic goes through servers you choose, processing on those servers is governed by their policies. EvilFox as client publisher is not necessarily the operator of those servers.
  • +
  • Microsoft — if you install or update from the Microsoft Store, Microsoft’s policies apply to Store distribution, Microsoft accounts, and Store payments (where applicable).
  • +
+ +

3. What data is processed

+

3.1. Data on your device (local)

+

The App may store on your device (config files, app data folders, WebView2 localStorage and similar OS storage):

+ + + + + + + + +
CategoryExamplesWhy
Connection configurationsConfiguration URLs, server profiles, protocol parameters you enter or importConnecting and choosing a server
App settingsTheme (light/dark), language (RU/EN), proxy or full-protection mode, Kill Switch, auto best serverRemembering your preferences
Session technical dataConnection status, selected profile, ping, local session/traffic stats (when available)Status and statistics UI
OS / WebView2 service dataWebView2 cache, on-device error logsStable UI operation
+

3.2. Data during network use

+
    +
  • With servers you choose: technical parameters needed by the protocol are exchanged (addresses, keys/tokens from your configuration, tunnel control traffic). Your user traffic is processed along the path through the selected server — see Section 6.
  • +
  • Update checks (non-Store builds or when you initiate a check): a request to an update feed (e.g. hosting on git.de4ima.uk) may include standard HTTP request metadata (IP address as seen by the host, User-Agent, time).
  • +
  • When you open external links: the browser or OS sends data to that site/messenger under their rules.
  • +
+

3.3. Data you may send to support

+

If you contact us (email / Telegram / website), you may voluntarily provide an address, problem description, or screenshots. We use them only to respond and improve the product.

+ +

4. What we do not collect centrally

+

As the client publisher, EvilFox does not operate a mandatory central collection and does not sell:

+
    +
  • a cloud account registry of EvilFox client users for ordinary app operation;
  • +
  • payment cards or in-app purchase details (the Store build has no in-app purchases; Store purchases, if any, are handled by Microsoft);
  • +
  • browsing history, contacts, microphone/camera by default;
  • +
  • the contents of your internet traffic for advertising or data resale.
  • +
+

We do not sell personal data.

+ +

5. Purposes and legal bases

+ + + + + + + + + +
PurposeLegal basis (GDPR / equivalents)
Providing client features (connect, settings, UI)Performance of a contract / user request for the client service
Security and stability (local logs, preventing failures)Legitimate interests / necessity to operate the product
Update checks (user-initiated or build policy)Legitimate interests / user action
Responding to support requestsLegitimate interests / responding to the data subject
Legal compliance and protecting rightsLegal obligation / legitimate interests
+ +

6. Network traffic and third-party servers

+

After you connect, traffic is routed according to your configuration. The node operator may process IP addresses, session metadata, and (depending on protocol and settings) traffic contents. EvilFox does not control every third-party server’s privacy practice.

+

Recommendation: use only trusted configurations; read your server provider’s privacy policy and terms.

+

Full-protection (TUN) mode and Kill Switch: these features change on-device network routing to protect the connection and reduce leaks if the tunnel drops. They operate locally on your system.

+ +

7. App updates

+
    +
  • Microsoft Store: updates are normally delivered by the Store; in-app self-update in the MSIX build is disabled or limited.
  • +
  • Other channels (sideload): when you choose, the client may fetch an update manifest from a publisher URL (including on git.de4ima.uk). The hosting server may see IP and technical request headers.
  • +
+ +

8. External links and third-party services

+

The App may open, after you choose to click:

+ +

The device also uses OS components and Microsoft Edge WebView2 — Microsoft’s policies apply to those components.

+ +

9. Retention, deletion, and security

+

9.1. Retention

+

Local data remains while you use the App, or until you delete profiles, clear app data, or uninstall EvilFox. Support correspondence is kept as long as needed to resolve the request (typically no longer than needed for the conversation and basic support records).

+

9.2. How to delete data

+
    +
  • delete configurations/profiles in the App;
  • +
  • uninstall EvilFox in Windows;
  • +
  • if needed, manually clear remaining app data folders.
  • +
+

There is no central EvilFox cloud account for restoring local profiles — we cannot restore device-deleted data from our servers.

+

9.3. Security

+

We apply reasonable organizational and technical measures within the client and OS. No method is perfectly secure. You are responsible for keeping configuration URLs/keys confidential on the device and for physical access to the computer.

+ +

10. Transfers and international aspects

+

The client runs locally. Data may be processed in other countries when:

+
    +
  • you connect to servers abroad (via your configuration);
  • +
  • you open foreign websites/services;
  • +
  • an update request is handled by hosting infrastructure outside your country.
  • +
+

For users in the EU/EEA/UK: such transfers result from your choice of configuration and services. Where required, server operators should provide appropriate safeguards (e.g. Standard Contractual Clauses) — ask your configuration provider.

+ +

11. Your rights (EU / GDPR and equivalents)

+

Depending on applicable law, you may have rights to:

+
    +
  • access and obtain a copy of data;
  • +
  • rectify inaccurate data;
  • +
  • erasure (“right to be forgotten”) — including by uninstalling and clearing local data;
  • +
  • restriction of processing and objection to processing based on legitimate interests;
  • +
  • data portability — to the extent data is stored in a structured form on the device (export configurations if available);
  • +
  • lodge a complaint with a supervisory authority where you live or work in the EU/EEA/UK.
  • +
+

Because most processing is on-device, most rights are exercised locally. For questions about this Policy, contact us below. We will respond within a reasonable time.

+ +

12. California (CCPA/CPRA) and US users

+

We do not sell and do not “share” personal information for cross-context behavioral advertising under CCPA/CPRA. Categories of data are described in Section 3. Sources are mainly you (configuration input) and the device. We do not use sensitive personal information to infer consumer characteristics for advertising.

+

Rights to know, delete, and correct regarding local client data are exercised on the device (uninstall / clear data). Requests related to support correspondence can be sent via Section 16.

+

We do not discriminate against you for exercising privacy rights.

+ +

13. Children

+

The App is not directed to children under 13. In the EU/EEA, where local law sets a higher digital consent age (often up to 16), do not use the App below that age without parental/guardian consent where required. We do not knowingly collect children’s data centrally. If you believe a child sent us data via support, contact us — we will delete the request where appropriate.

+ +

14. Microsoft Store

+

When distributed through the Microsoft Store, Microsoft may process install, update, review, and (for paid products) payment data under its own policies. Capabilities such as runFullTrust / classic desktop may require Store disclosure and approval of restricted capabilities.

+ +

15. Changes to this Policy

+

We may update this Policy. The current version is published on the website (this page) and/or in the App Help section. Material changes are reflected by the date at the top where practical. Continued use of the App after an update means you have an opportunity to review the new text.

+ +

16. Contact

+

+ EvilFox
+ Website: https://evilfox.win/
+ Primary email: animegold3@gmail.com
+ Backup email: admin@evilfox.win
+ Telegram: https://t.me/evilfox100Bot
+ Terms of Use: terms-en.html +

+ + +
+ + +
+ + diff --git a/Site/privacy-ru.html b/Site/privacy-ru.html new file mode 100644 index 0000000..8f27145 --- /dev/null +++ b/Site/privacy-ru.html @@ -0,0 +1,260 @@ + + + + + + Политика конфиденциальности — EvilFox + + + + + + + +
+
+ + +
+

EvilFox

+ evilfox.win +
+
+ +
+ +
+

Политика конфиденциальности

+

+ Издатель / контролёр (для данных на устройстве): EvilFox
+ Дата вступления в силу: 2 августа 2026 г. · Версия документа: 1.0
+ Применяется к приложению EvilFox для Windows (включая сборку Microsoft Store) и связанным страницам на evilfox.win. +

+ + + +

1. Кто мы и о чём эта политика

+

EvilFox — локальный клиент для защищённого сетевого подключения на Windows (режимы прокси и полной защиты / TUN, поддержка современных протоколов). Вы самостоятельно добавляете конфигурации и URL подключения. В сборке Microsoft Store нет встроенных покупок внутри приложения.

+

Настоящая Политика объясняет, какие данные могут обрабатываться при использовании Приложения, для каких целей, как долго они хранятся, какие у вас есть права и как с нами связаться. Мы стремимся соответствовать требованиям прозрачности Microsoft Store, а также ожиданиям пользователей в США и Европейском союзе / ЕЭЗ / Великобритании.

+

Кратко: большинство данных остаётся на вашем устройстве. Мы не продаём персональные данные и не ведём рекламный профиль на основе содержимого вашего трафика.

+ +

2. Область применения и роли

+

2.1. Что покрывается

+
    +
  • приложение EvilFox (Windows, в том числе MSIX / Microsoft Store);
  • +
  • страницы политики и соглашения на сайте evilfox.win;
  • +
  • обращения в поддержку через указанные контакты.
  • +
+

2.2. Роли

+
    +
  • EvilFox (издатель клиента) — контролёр в отношении данных, которые Приложение хранит и обрабатывает локально на устройстве для работы клиента.
  • +
  • Оператор серверов / провайдер конфигурации — отдельное лицо (вы сами или ваш поставщик). Когда трафик проходит через выбранные вами серверы, обработка на стороне этих серверов регулируется их политиками. EvilFox как издатель клиента не обязательно является оператором этих серверов.
  • +
  • Microsoft — при установке и обновлении из Microsoft Store действуют политики Microsoft в части Store, учётной записи Microsoft и платёжных операций Store (если применимо).
  • +
+ +

3. Какие данные обрабатываются

+

3.1. Данные на вашем устройстве (локально)

+

Приложение может сохранять на устройстве (файлы конфигурации, каталог данных приложения, localStorage WebView2 и аналогичные хранилища ОС):

+ + + + + + + + +
КатегорияПримерыЗачем
Конфигурации подключенияURL конфигурации, профили серверов, параметры протоколов, которые вы вводите или импортируетеПодключение и выбор сервера
Настройки приложенияТема (светлая/тёмная), язык (RU/EN), режим прокси или полной защиты, Kill Switch, автовыбор лучшего сервераСохранение ваших предпочтений
Технические сведения о сессииСтатус подключения, выбранный профиль, пинг, локальная статистика сессий/трафика (если доступна)Отображение статуса и статистики
Служебные файлы ОС/WebView2Кэш WebView2, журналы ошибок на устройствеСтабильная работа интерфейса
+

3.2. Данные при сетевом взаимодействии

+
    +
  • С выбранными вами серверами: для установления защищённого соединения передаются технические параметры, необходимые протоколу (адреса, ключи/токены из вашей конфигурации, служебный трафик туннеля). Содержимое вашего пользовательского трафика обрабатывается на пути через выбранный сервер — см. раздел 6.
  • +
  • При проверке обновлений (не Store-сборка или по вашей инициативе): запрос к ленте обновлений (например, хостинг git.de4ima.uk) может включать стандартные технические данные HTTP-запроса (IP-адрес на стороне сервера хостинга, User-Agent, время запроса).
  • +
  • При открытии внешних ссылок: браузер или система передаёт данные соответствующему сайту/мессенджеру по их правилам.
  • +
+

3.3. Данные, которые вы можете прислать в поддержку

+

Если вы пишете нам (почта / Telegram / сайт), вы можете добровольно указать адрес, описание проблемы, скриншоты. Мы используем их только для ответа на обращение и улучшения продукта.

+ +

4. Что мы не собираем централизованно

+

EvilFox как издатель клиента не ведёт обязательный централизованный сбор и не продаёт:

+
    +
  • реестр аккаунтов пользователей клиента «в облаке EvilFox» для обычной работы приложения;
  • +
  • платёжные карты и данные покупок внутри приложения (в Store-сборке покупок в приложении нет; покупки Store, если есть, обрабатывает Microsoft);
  • +
  • историю браузера, контакты, микрофон/камеру по умолчанию;
  • +
  • содержимое вашего интернет-трафика для рекламы или перепродажи данных.
  • +
+

Мы не продаём персональные данные.

+ +

5. Цели и правовые основания

+ + + + + + + + + +
ЦельОснование (GDPR / аналоги)
Предоставление функций клиента (подключение, настройки, интерфейс)Исполнение договора / запрос пользователя на предоставление сервиса клиента
Безопасность и стабильность (локальные логи, предотвращение сбоев)Законный интерес / необходимость для работы продукта
Проверка обновлений (по действию пользователя или политике сборки)Законный интерес / согласие-действие пользователя
Ответы на обращения в поддержкуЗаконный интерес / исполнение запроса субъекта
Соблюдение закона и защита правПравовая обязанность / законный интерес
+ +

6. Сетевой трафик и сторонние серверы

+

После подключения ваш трафик направляется согласно выбранной конфигурации. Оператор узла может обрабатывать IP-адреса, метаданные сессии и (в зависимости от протокола и настроек) содержимое трафика. EvilFox не контролирует политику каждого стороннего сервера.

+

Рекомендация: используйте только доверенные конфигурации; читайте политику конфиденциальности и условия вашего провайдера серверов.

+

Режим полной защиты (TUN) и Kill Switch: эти функции изменяют сетевую маршрутизацию на устройстве для защиты соединения и снижения утечек при обрыве. Они работают локально на вашей системе.

+ +

7. Обновления приложения

+
    +
  • Microsoft Store: обновления обычно доставляет Store; встроенное самообновление в MSIX-сборке отключено или ограничено.
  • +
  • Иные каналы (sideload): по вашей инициативе клиент может запросить манифест обновлений с указанного издателем URL (в т.ч. на git.de4ima.uk). Сервер хостинга может видеть IP и технические заголовки запроса.
  • +
+ +

8. Внешние ссылки и сторонние сервисы

+

Приложение может открывать по вашему действию:

+ +

Также на устройстве используются компоненты ОС и Microsoft Edge WebView2 — к ним применяются политики Microsoft.

+ +

9. Хранение, удаление и безопасность

+

9.1. Срок хранения

+

Локальные данные хранятся, пока вы пользуетесь Приложением, либо до удаления профилей, очистки данных приложения или удаления EvilFox. Данные обращений в поддержку храним столько, сколько нужно для решения вопроса (как правило, не дольше, чем требуется для переписки и учёта обращений).

+

9.2. Как удалить данные

+
    +
  • удалить конфигурации/профили в приложении;
  • +
  • удалить приложение EvilFox в Windows;
  • +
  • при необходимости очистить остаточные папки данных приложения вручную.
  • +
+

Центрального «облачного аккаунта EvilFox» для восстановления локальных профилей нет — удалённое с устройства мы не можем вернуть с наших серверов.

+

9.3. Безопасность

+

Мы применяем разумные организационные и технические меры в рамках клиентского приложения и ОС. Абсолютной безопасности не существует. Вы отвечаете за сохранность URL, ключей и файлов конфигурации на устройстве и за физический доступ к компьютеру.

+ +

10. Передачи данных и международные аспекты

+

Клиент работает локально. Передача данных в другие страны может происходить, когда:

+
    +
  • вы подключаетесь к серверам за рубежом (по вашей конфигурации);
  • +
  • вы открываете зарубежные сайты/сервисы;
  • +
  • запрос обновлений обрабатывается инфраструктурой хостинга за пределами вашей страны.
  • +
+

Для пользователей в ЕС/ЕЭЗ/Великобритании: такие передачи связаны с вашим выбором конфигурации и сервисов. При необходимости операторы серверов должны обеспечивать надлежащие гарантии (например, стандартные договорные условия) — уточняйте у провайдера конфигурации.

+ +

11. Ваши права (ЕС / GDPR и аналоги)

+

В зависимости от применимого права вы можете иметь права на:

+
    +
  • доступ к данным и получение копии;
  • +
  • исправление неточных данных;
  • +
  • удаление («право на забвение») — в т.ч. путём удаления приложения и локальных данных;
  • +
  • ограничение обработки и возражение против обработки на основе законного интереса;
  • +
  • переносимость данных — в той мере, в какой данные хранятся в структурированном виде на устройстве (экспорт конфигураций, если доступен);
  • +
  • жалобу в надзорный орган по месту жительства/работы в ЕС/ЕЭЗ/Великобритании.
  • +
+

Поскольку основная обработка идёт на устройстве, большинство прав реализуется вами локально. По вопросам, связанным с этой Политикой, пишите на контакты ниже. Мы ответим в разумный срок.

+ +

12. Калифорния (CCPA/CPRA) и пользователи в США

+

Мы не продаём и не «делимся» персональной информацией для контекстной кросс-рекламы в смысле CCPA/CPRA. Категории данных описаны в разделе 3. Источники — в основном вы (ввод конфигураций) и устройство. Мы не используем чувствительные данные для вывода характеристик потребителя в рекламных целях.

+

Права на знание, удаление и исправление в отношении локальных данных клиента осуществляются на устройстве (удаление приложения/данных). Запросы, связанные с перепиской поддержки, можно направить через контакты в разделе 16.

+

Мы не осуществляем дискриминацию за реализацию конфиденциальных прав.

+ +

13. Дети

+

Приложение не предназначено для детей младше 13 лет. В ЕС/ЕЭЗ, где местное право устанавливает более высокий возраст цифрового согласия (часто до 16 лет), не используйте Приложение ниже этого возраста без согласия родителя или опекуна, если оно требуется. Мы сознательно не собираем данные детей централизованно. Если вы считаете, что ребёнок передал нам данные через поддержку, свяжитесь с нами — мы удалим обращение, где это уместно.

+ +

14. Microsoft Store

+

При распространении через Microsoft Store корпорация Microsoft может обрабатывать данные установки, обновлений, отзывов и (при платных продуктах) платежей согласно своим политикам. Для возможностей вроде runFullTrust / классического рабочего стола могут применяться требования Store к прозрачности и разрешению ограниченных возможностей.

+ +

15. Изменения политики

+

Мы можем обновлять Политику. Актуальная версия публикуется на сайте (эта страница) и/или в разделе «Помощь» приложения. Существенные изменения по возможности отражаются датой в начале документа. Продолжение использования Приложения после обновления означает, что вы можете ознакомиться с новой редакцией.

+ +

16. Контакты

+

+ EvilFox
+ Сайт: https://evilfox.win/
+ Основная почта: animegold3@gmail.com
+ Резервная почта: admin@evilfox.win
+ Telegram: https://t.me/evilfox100Bot
+ Пользовательское соглашение: terms-ru.html +

+ + +
+ + +
+ + diff --git a/Site/privacy.html b/Site/privacy.html new file mode 100644 index 0000000..cc5748b --- /dev/null +++ b/Site/privacy.html @@ -0,0 +1,12 @@ + + + + + + EvilFox — Privacy + + + +

Политика конфиденциальности (RU) · Privacy Policy (EN)

+ + diff --git a/Site/terms-en.html b/Site/terms-en.html new file mode 100644 index 0000000..22c8e8f --- /dev/null +++ b/Site/terms-en.html @@ -0,0 +1,144 @@ + + + + + + Terms of Use — EvilFox + + + + + + + +
+
+ + +
+

EvilFox

+ evilfox.win +
+
+ +
+ +
+

Terms of Use (User Agreement)

+

Publisher: EvilFox · Effective date: August 2, 2026

+ +

1. Acceptance

+

By installing or using the EvilFox application (the “App”), you confirm that you have read and accept this User Agreement (Terms of Use). If you do not agree, do not install or use the App.

+ +

2. License

+

You receive a limited, non-exclusive, non-transferable license to use the EvilFox client on your devices for personal or internal use, subject to these Terms and applicable law, including Microsoft Store rules if the App is installed from the Microsoft Store.

+ +

3. Acceptable use

+

Use EvilFox only for lawful purposes. You must not violate the laws of your country or third-party rights, or attempt to disrupt the App or others’ systems. You are responsible for how you use the client and the servers you choose.

+ +

4. User-supplied configurations

+

You provide connection URLs and parameters. EvilFox does not guarantee availability, quality, or legality of third-party servers. Review your configuration provider’s terms. Configurations are not part of a Microsoft Store purchase (where applicable).

+ +

5. No warranty

+

The App is provided “as is” and “as available,” without warranties of any kind (express or implied, including merchantability and fitness for a particular purpose), to the fullest extent permitted by law.

+ +

6. Limitation of liability

+

To the maximum extent permitted by law, EvilFox is not liable for indirect, incidental, special, or consequential damages, lost profits, data loss, or connectivity interruptions arising from use of the client or third-party servers. Mandatory consumer rights (including in the EU) remain unaffected.

+ +

7. Updates

+

Microsoft Store builds update through the Store. Other (sideload) builds may offer updates via the publisher’s update feed. Features may change in new versions.

+ +

8. Termination

+

You may stop using the App by uninstalling it. We may discontinue support for particular builds. If you breach these Terms, your right to use the App ends.

+ +

9. Governing law

+

These Terms are interpreted under the laws of your country of residence unless mandatory rules require otherwise. EU consumers keep mandatory rights under the law of their country of residence.

+ +

10. Contact

+

+ EvilFox · https://evilfox.win/
+ Primary: animegold3@gmail.com · + Backup: admin@evilfox.win · + Telegram: https://t.me/evilfox100Bot +

+ + +
+ + +
+ + diff --git a/Site/terms-ru.html b/Site/terms-ru.html new file mode 100644 index 0000000..02dfec9 --- /dev/null +++ b/Site/terms-ru.html @@ -0,0 +1,146 @@ + + + + + + Пользовательское соглашение — EvilFox + + + + + + + +
+
+ + +
+

EvilFox

+ evilfox.win +
+
+ +
+ +
+

Пользовательское соглашение

+

Издатель: EvilFox · Дата вступления в силу: 2 августа 2026 г.

+ +

1. Принятие условий

+

Устанавливая или используя приложение EvilFox («Приложение»), вы подтверждаете, что прочитали и принимаете настоящее Пользовательское соглашение (условия использования). Если вы не согласны с условиями — не устанавливайте и не используйте Приложение.

+ +

2. Лицензия

+

Вам предоставляется ограниченная, неисключительная, непередаваемая лицензия на использование клиента EvilFox на ваших устройствах в личных или внутренних целях в соответствии с настоящим Соглашением и применимым правом, включая правила Microsoft Store (если Приложение установлено из Microsoft Store).

+ +

3. Допустимое использование

+

Используйте EvilFox только законно. Запрещены действия, нарушающие законы вашей страны или права третьих лиц, а также попытки нарушить работу Приложения или чужих систем. Вы несёте ответственность за то, как используете клиент и выбранные серверы.

+ +

4. Конфигурации пользователя

+

URL и параметры подключения задаёте вы. EvilFox не гарантирует доступность, качество или законность сторонних серверов. Ознакомьтесь с условиями вашего провайдера конфигурации. Конфигурации не являются частью покупки в Microsoft Store (если применимо).

+ +

5. Отсутствие гарантий

+

Приложение предоставляется «как есть» и «по мере доступности», без явных или подразумеваемых гарантий (включая товарную пригодность и пригодность для конкретной цели), в пределах, допускаемых законом.

+ +

6. Ограничение ответственности

+

В максимальной степени, допускаемой законом, EvilFox не несёт ответственности за косвенные, случайные, особые убытки, упущенную выгоду, потерю данных или перебои связи, связанные с использованием клиента или сторонних серверов. Обязательные права потребителей (в том числе в ЕС) сохраняются.

+ +

7. Обновления

+

Сборка из Microsoft Store обновляется через Store. Иные (sideload) сборки могут предлагать обновление через ленту обновлений издателя. Функции могут меняться в новых версиях.

+ +

8. Прекращение

+

Вы можете прекратить использование, удалив Приложение. Мы можем прекратить поддержку отдельных сборок. При нарушении Соглашения право на использование Приложения прекращается.

+ +

9. Применимое право

+

Настоящее Соглашение толкуется по законам страны вашего проживания, если иное не требуется императивными нормами. Для потребителей в ЕС сохраняются обязательные права по праву страны проживания.

+ +

10. Контакты

+

+ EvilFox · https://evilfox.win/
+ Основная: animegold3@gmail.com · + Резервная: admin@evilfox.win · + Telegram: https://t.me/evilfox100Bot +

+ + +
+ + +
+ + diff --git a/Site/terms.html b/Site/terms.html new file mode 100644 index 0000000..9957498 --- /dev/null +++ b/Site/terms.html @@ -0,0 +1,12 @@ + + + + + + EvilFox — Terms + + + +

Пользовательское соглашение (RU) · Terms of Use (EN)

+ + diff --git a/dist/microsoft-store/AdditionalLicense.en.txt b/dist/microsoft-store/AdditionalLicense.en.txt new file mode 100644 index 0000000..cf9ae12 --- /dev/null +++ b/dist/microsoft-store/AdditionalLicense.en.txt @@ -0,0 +1,15 @@ +In addition to the standard Microsoft Store / app license terms: + +1. EvilFox is a client for protected network connectivity. Server configurations and connection URLs are supplied by you and are not part of any Store purchase (where applicable). + +2. You are responsible for using the app and chosen servers lawfully in your jurisdiction. + +3. The publisher does not warrant uninterrupted operation of third-party servers, speed, or availability of specific nodes. + +4. The app may store settings and configurations locally on your device. The Privacy Policy and full Terms of Use are available in the app Help section and at https://evilfox.win/ + +5. Updates delivered via the Microsoft Store replace in-app self-update in Store builds. + +6. The runFullTrust / classic desktop capability is required for the client to function (WebView2, network modes). + +Contact: https://evilfox.win/ · https://t.me/evilfox100Bot diff --git a/dist/microsoft-store/AdditionalLicense.ru.txt b/dist/microsoft-store/AdditionalLicense.ru.txt new file mode 100644 index 0000000..d0572e7 --- /dev/null +++ b/dist/microsoft-store/AdditionalLicense.ru.txt @@ -0,0 +1,15 @@ +Дополнительно к стандартным условиям лицензии Microsoft Store / приложения: + +1. EvilFox — клиент для защищённого сетевого подключения. Конфигурации серверов и URL подключения предоставляются вами и не являются частью покупки в Store (если применимо). + +2. Вы несёте ответственность за законность использования приложения и выбранных серверов в вашей юрисдикции. + +3. Издатель не гарантирует бесперебойную работу сторонних серверов, скорость или доступность конкретных узлов. + +4. Приложение может хранить настройки и конфигурации локально на устройстве. Политика конфиденциальности и полные условия использования доступны в разделе «Помощь» приложения и на https://evilfox.win/ + +5. Обновления через Microsoft Store заменяют самообновление приложения в сборке Store. + +6. Возможность runFullTrust / классическое настольное приложение требуется для работы клиента (WebView2, сетевые режимы). + +Контакты: https://evilfox.win/ · https://t.me/evilfox100Bot diff --git a/dist/microsoft-store/Copyright.en.txt b/dist/microsoft-store/Copyright.en.txt new file mode 100644 index 0000000..9b9cfdd --- /dev/null +++ b/dist/microsoft-store/Copyright.en.txt @@ -0,0 +1 @@ +© 2026 EvilFox. All rights reserved. EvilFox, the EvilFox logo, and related marks are trademarks or registered trademarks of EvilFox. Other product and company names mentioned in the app or product listing may be trademarks of their respective owners. diff --git a/dist/microsoft-store/Copyright.ru.txt b/dist/microsoft-store/Copyright.ru.txt new file mode 100644 index 0000000..3b8b59a --- /dev/null +++ b/dist/microsoft-store/Copyright.ru.txt @@ -0,0 +1 @@ +© 2026 EvilFox. Все права защищены. EvilFox, логотип EvilFox и связанные знаки являются товарными знаками или зарегистрированными товарными знаками EvilFox. Прочие названия продуктов и компаний, упомянутые в приложении или на странице продукта, могут быть товарными знаками соответствующих владельцев. diff --git a/dist/microsoft-store/README.txt b/dist/microsoft-store/README.txt index bced188..608004c 100644 --- a/dist/microsoft-store/README.txt +++ b/dist/microsoft-store/README.txt @@ -1,13 +1,13 @@ EvilFox Microsoft Store package folder -Version: 4.2.8.1 -Generated: 2026-08-02 14:05:35 +Version: 4.2.8.0 +Generated: 2026-08-02 14:21:55 === Partner Center upload (EN) === 1. Sign in to Partner Center with the same Microsoft Store developer account you use for Visual Studio packaging / Store association (same tenant). 2. Open the EvilFox product -> Packages (Windows 10 / 11). -3. Prefer uploading EvilFox_4.2.8.1.msixbundle if present. - Otherwise upload each EvilFox_4.2.8.1_.msix (x64 + arm64). +3. Prefer uploading EvilFox_4.2.8.0.msixbundle if present. + Otherwise upload each EvilFox_4.2.8.0_.msix (x64 + arm64). 4. Device family: check Windows 10 / 11 Desktop ONLY (do NOT select Xbox, HoloLens, Surface Hub, IoT, Team, etc.). 5. Arm64 package covers Windows on ARM. Do not ship x86 / AArch32; @@ -19,7 +19,7 @@ Generated: 2026-08-02 14:05:35 === Partner Center (RU) === 1. Войдите в Partner Center тем же аккаунтом разработчика Store, что и в Visual Studio (ассоциация приложения / упаковка). -2. Загрузите EvilFox_4.2.8.1.msixbundle, если есть; иначе оба .msix +2. Загрузите EvilFox_4.2.8.0.msixbundle, если есть; иначе оба .msix (x64 и arm64). 3. Семейство устройств: только Windows 10/11 Desktop (без Xbox / HoloLens / IoT и т.п.). @@ -29,17 +29,14 @@ Generated: 2026-08-02 14:05:35 6. Нужен URL политики конфиденциальности на evilfox.win. === Artifacts === -Bundle: (not created) +Bundle: D:\vpn navi\dist\microsoft-store\EvilFox_4.2.8.0.msixbundle +MSIX: D:\vpn navi\dist\microsoft-store\EvilFox_4.2.8.0_x64.msix +MSIX: D:\vpn navi\dist\microsoft-store\EvilFox_4.2.8.0_arm64.msix Staging x64: D:\vpn navi\packaging\msix\_staging_x64 Staging arm64: D:\vpn navi\packaging\msix\_staging_arm64 === MakeAppx === -MakeAppx.exe NOT FOUND on this machine. -Install Windows 10/11 SDK, then run: - makeappx pack /d "D:\vpn navi\packaging\msix\_staging_x64" /p "D:\vpn navi\dist\microsoft-store\EvilFox_4.2.8.1_x64.msix" /o - makeappx pack /d "D:\vpn navi\packaging\msix\_staging_arm64" /p "D:\vpn navi\dist\microsoft-store\EvilFox_4.2.8.1_arm64.msix" /o - makeappx bundle /d "D:\vpn navi\dist\microsoft-store\_bundle_input" /p "D:\vpn navi\dist\microsoft-store\EvilFox_4.2.8.1.msixbundle" /o - (copy both .msix into _bundle_input first) +Found: C:\Users\orohi\AppData\Local\Microsoft\WinGet\Packages\Microsoft.MSIX-Toolkit_Microsoft.Winget.Source_8wekyb3d8bbwe\MSIX-Toolkit.x64\makeappx.exe === wintun.dll === wintun.dll was NOT found under assets/ or dist/. Packaging continued. diff --git a/dist/microsoft-store/WhatsNew.en.txt b/dist/microsoft-store/WhatsNew.en.txt new file mode 100644 index 0000000..507b7c3 --- /dev/null +++ b/dist/microsoft-store/WhatsNew.en.txt @@ -0,0 +1,16 @@ +EvilFox 4.2 — a clearer, more polished client for private internet access. + +What's new: +• Modern UI: Protection, My servers, Settings, Statistics, Help +• Large connect button and clear protection status +• Light theme by default, with dark theme toggle +• Russian and English languages (RU | EN) +• Country flags for servers (rendered correctly on Windows) +• Same-IP servers grouped into one row with available protocols +• Add configuration via URL +• Proxy mode and full protection mode (TUN) +• Kill Switch — leak protection if the connection drops +• Auto-select the lowest-ping server +• Traffic and session statistics +• Privacy Policy and Terms of Use in Help +• Adaptive window sizing for any screen and Windows display scale diff --git a/dist/microsoft-store/WhatsNew.ru.txt b/dist/microsoft-store/WhatsNew.ru.txt new file mode 100644 index 0000000..41ec8c7 --- /dev/null +++ b/dist/microsoft-store/WhatsNew.ru.txt @@ -0,0 +1,16 @@ +EvilFox 4.2 — удобный и понятный клиент для безопасного доступа в интернет. + +Что нового для пользователей: +• Современный интерфейс: вкладки Защита, Мои серверы, Настройки, Статистика, Помощь +• Большая кнопка подключения и понятный статус защиты +• Светлая тема по умолчанию и переключение на тёмную +• Языки: русский и английский (RU | EN) +• Флаги стран у серверов (корректно на Windows) +• Серверы с одним IP объединяются в одну строку с доступными протоколами +• Добавление конфигурации по URL +• Режим прокси и полный режим защиты (TUN) +• Kill Switch — защита от утечек при обрыве соединения +• Автовыбор сервера с лучшим пингом +• Статистика трафика и сессий +• Политика конфиденциальности и условия использования в разделе Помощь +• Адаптивное окно под любой экран и масштаб Windows diff --git a/dist/microsoft-store/listing/screen/1.ru.300x300.png b/dist/microsoft-store/listing/screen/1.ru.300x300.png new file mode 100644 index 0000000000000000000000000000000000000000..c935c33f584b4a1fba1b7c5aa51a5c0f4fe2ec13 GIT binary patch literal 39700 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 literal 0 HcmV?d00001 diff --git a/dist/microsoft-store/listing/store.csv b/dist/microsoft-store/listing/store.csv index 0ffd9a0..f61756d 100644 --- a/dist/microsoft-store/listing/store.csv +++ b/dist/microsoft-store/listing/store.csv @@ -1,4 +1,4 @@ -Field,ID,Type (Тип),default,en +Field,ID,Type (Тип),default,en Description,2,Текст,"EvilFox — приложение для безопасного доступа в интернет на Windows. Защитите данные в публичных Wi‑Fi сетях: EvilFox шифрует трафик, скрывает ваш реальный IP-адрес и помогает предотвратить утечки DNS. Современный интерфейс на русском и английском, светлая и тёмная темы, удобный выбор серверов и понятный статус подключения. @@ -34,15 +34,75 @@ EvilFox is built for everyday browsing, travel, and privacy. You add your own co Website: https://evilfox.win/ Support: https://t.me/evilfox100Bot" -ReleaseNotes,3,Текст,"Обновление 4.2: улучшенный интерфейс для Microsoft Store, переключатель языка RU/EN, светлая тема по умолчанию, группировка серверов по IP с отображением доступных протоколов, исправления переключателей темы и языка, реальные флаги стран (SVG), Kill Switch и статистика.","Version 4.2: Microsoft Store–ready UI polish, RU/EN language switch, light theme by default, servers grouped by IP with available protocols, theme/language toggle fixes, real country flags (SVG), Kill Switch, and usage statistics." +ReleaseNotes,3,Текст,"EvilFox 4.2 — удобный и понятный клиент для безопасного доступа в интернет. + +Что нового для пользователей: +• Современный интерфейс: вкладки Защита, Мои серверы, Настройки, Статистика, Помощь +• Большая кнопка подключения и понятный статус защиты +• Светлая тема по умолчанию и переключение на тёмную +• Языки: русский и английский (RU | EN) +• Флаги стран у серверов (корректно на Windows) +• Серверы с одним IP объединяются в одну строку с доступными протоколами +• Добавление конфигурации по URL +• Режим прокси и полный режим защиты (TUN) +• Kill Switch — защита от утечек при обрыве соединения +• Автовыбор сервера с лучшим пингом +• Статистика трафика и сессий +• Политика конфиденциальности и условия использования в разделе Помощь +• Адаптивное окно под любой экран и масштаб Windows","EvilFox 4.2 — a clearer, more polished client for private internet access. + +What's new: +• Modern UI: Protection, My servers, Settings, Statistics, Help +• Large connect button and clear protection status +• Light theme by default, with dark theme toggle +• Russian and English languages (RU | EN) +• Country flags for servers (rendered correctly on Windows) +• Same-IP servers grouped into one row with available protocols +• Add configuration via URL +• Proxy mode and full protection mode (TUN) +• Kill Switch — leak protection if the connection drops +• Auto-select the lowest-ping server +• Traffic and session statistics +• Privacy Policy and Terms of Use in Help +• Adaptive window sizing for any screen and Windows display scale" Title,4,Текст,EvilFox,EvilFox ShortTitle,5,Текст,EvilFox,EvilFox SortTitle,6,Текст,EvilFox,EvilFox VoiceTitle,7,Текст,Evil Fox,Evil Fox ShortDescription,8,Текст,"Безопасный доступ в интернет: шифрование трафика, скрытие IP, защита от утечек DNS. Русский и английский. Современные протоколы, Kill Switch, удобный выбор серверов.","Secure internet access: encrypt traffic, hide your IP, help prevent DNS leaks. English & Russian. Modern protocols, Kill Switch, easy server selection." DevStudio,9,Текст,EvilFox,EvilFox -CopyrightTrademarkInformation,12,Текст,© EvilFox. All rights reserved. EvilFox and the EvilFox logo are trademarks of their respective owners.,© EvilFox. All rights reserved. EvilFox and the EvilFox logo are trademarks of their respective owners. -AdditionalLicenseTerms,13,Текст,Proprietary software. By installing EvilFox you agree to use the application in accordance with applicable laws. The app provides a client for encrypted network connections; server configurations are supplied by the user. See https://evilfox.win/ for support and terms.,Proprietary software. By installing EvilFox you agree to use the application in accordance with applicable laws. The app provides a client for encrypted network connections; server configurations are supplied by the user. See https://evilfox.win/ for support and terms. +CopyrightTrademarkInformation,12,Текст,"© 2026 EvilFox. Все права защищены. EvilFox, логотип EvilFox и связанные знаки являются товарными знаками или зарегистрированными товарными знаками EvilFox. Прочие названия продуктов и компаний, упомянутые в приложении или на странице продукта, могут быть товарными знаками соответствующих владельцев.","© 2026 EvilFox. All rights reserved. EvilFox, the EvilFox logo, and related marks are trademarks or registered trademarks of EvilFox. Other product and company names mentioned in the app or product listing may be trademarks of their respective owners." +AdditionalLicenseTerms,13,Текст,"Дополнительно к стандартным условиям лицензии Microsoft Store / приложения: + +1. EvilFox — клиент для защищённого сетевого подключения. Конфигурации серверов и URL подключения предоставляются вами и не являются частью покупки в Store (если применимо). + +2. Вы несёте ответственность за законность использования приложения и выбранных серверов в вашей юрисдикции. + +3. Издатель не гарантирует бесперебойную работу сторонних серверов, скорость или доступность конкретных узлов. + +4. Приложение может хранить настройки и конфигурации локально на устройстве. Политика конфиденциальности и полные условия использования доступны в разделе «Помощь» приложения и на https://evilfox.win/ + +5. Обновления через Microsoft Store заменяют самообновление приложения в сборке Store. + +6. Возможность runFullTrust / классическое настольное приложение требуется для работы клиента (WebView2, сетевые режимы). + +Контакты: https://evilfox.win/ · https://t.me/evilfox100Bot +","In addition to the standard Microsoft Store / app license terms: + +1. EvilFox is a client for protected network connectivity. Server configurations and connection URLs are supplied by you and are not part of any Store purchase (where applicable). + +2. You are responsible for using the app and chosen servers lawfully in your jurisdiction. + +3. The publisher does not warrant uninterrupted operation of third-party servers, speed, or availability of specific nodes. + +4. The app may store settings and configurations locally on your device. The Privacy Policy and full Terms of Use are available in the app Help section and at https://evilfox.win/ + +5. Updates delivered via the Microsoft Store replace in-app self-update in Store builds. + +6. The runFullTrust / classic desktop capability is required for the client to function (WebView2, network modes). + +Contact: https://evilfox.win/ · https://t.me/evilfox100Bot +" DesktopScreenshot1,100,Относительный путь (или URL-адрес файла в Центре партнеров),screen/1.ru.png,screen/7.en.png DesktopScreenshot2,101,Относительный путь (или URL-адрес файла в Центре партнеров),screen/2.ru.png,screen/8.en.png DesktopScreenshot3,102,Относительный путь (или URL-адрес файла в Центре партнеров),screen/3.ru.png,screen/9.png @@ -75,8 +135,8 @@ DesktopScreenshot29,128,Относительный путь (или URL-адре DesktopScreenshot30,129,Относительный путь (или URL-адрес файла в Центре партнеров),, DesktopScreenshotCaption1,150,Текст,Главный экран: подключение и статус защиты,Home: connect and protection status DesktopScreenshotCaption2,151,Текст,Список серверов с флагами и пингом,Server list with flags and ping -DesktopScreenshotCaption3,152,Текст,"Настройки: тема, язык, Kill Switch",App overview -DesktopScreenshotCaption4,153,Текст,Статистика использования,"Settings: theme, language, Kill Switch" +DesktopScreenshotCaption3,152,Текст,"Настройки: тема, язык, Kill Switch","Settings: theme, language, Kill Switch" +DesktopScreenshotCaption4,153,Текст,Статистика использования,Usage statistics DesktopScreenshotCaption5,154,Текст,Помощь и полезные ссылки,Statistics and help DesktopScreenshotCaption6,155,Текст,Добавление конфигурации,Dark theme: home DesktopScreenshotCaption7,156,Текст,Тёмная тема: главный экран,Dark theme: servers @@ -325,7 +385,7 @@ SurfaceHubScreenshotCaption29,578,Текст,, SurfaceHubScreenshotCaption30,579,Текст,, StoreLogo720x1080,600,Относительный путь (или URL-адрес файла в Центре партнеров),, StoreLogo1080x1080,601,Относительный путь (или URL-адрес файла в Центре партнеров),, -StoreLogo300x300,602,Относительный путь (или URL-адрес файла в Центре партнеров),, +StoreLogo300x300,602,Относительный путь (или URL-адрес файла в Центре партнеров),screen/1.ru.300x300.png,screen/1.ru.300x300.png OverrideLogosForWin10,603,True/False,,False StoreLogoOverride150x150,604,Относительный путь (или URL-адрес файла в Центре партнеров),, StoreLogoOverride71x71,605,Относительный путь (или URL-адрес файла в Центре партнеров),, diff --git a/docs/privacy-en.md b/docs/privacy-en.md index 8de77d4..50a51ee 100644 --- a/docs/privacy-en.md +++ b/docs/privacy-en.md @@ -71,4 +71,5 @@ We may update this policy. The current version is in the app (Help) and on the w ## 15. Contact -EvilFox · https://evilfox.win/ · support: https://t.me/evilfox100Bot +EvilFox · https://evilfox.win/ +Primary: animegold3@gmail.com · Backup: admin@evilfox.win · Telegram: https://t.me/evilfox100Bot diff --git a/docs/privacy-ru.md b/docs/privacy-ru.md index 3be1c7a..5039ff0 100644 --- a/docs/privacy-ru.md +++ b/docs/privacy-ru.md @@ -71,4 +71,5 @@ EvilFox как издатель клиента не ведёт централи ## 15. Контакты -EvilFox · https://evilfox.win/ · поддержка: https://t.me/evilfox100Bot +EvilFox · https://evilfox.win/ +Основная: animegold3@gmail.com · Резервная: admin@evilfox.win · Telegram: https://t.me/evilfox100Bot diff --git a/docs/terms-en.md b/docs/terms-en.md index 7c92500..056fe07 100644 --- a/docs/terms-en.md +++ b/docs/terms-en.md @@ -41,4 +41,5 @@ These Terms are interpreted under the laws of your country of residence unless m ## 10. Contact -EvilFox · https://evilfox.win/ · https://t.me/evilfox100Bot +EvilFox · https://evilfox.win/ +Primary: animegold3@gmail.com · Backup: admin@evilfox.win · Telegram: https://t.me/evilfox100Bot diff --git a/docs/terms-ru.md b/docs/terms-ru.md index f5b9ea2..81cecc2 100644 --- a/docs/terms-ru.md +++ b/docs/terms-ru.md @@ -41,4 +41,5 @@ URL и параметры подключения задаёте вы. EvilFox н ## 10. Контакты -EvilFox · https://evilfox.win/ · https://t.me/evilfox100Bot +EvilFox · https://evilfox.win/ +Основная: animegold3@gmail.com · Резервная: admin@evilfox.win · Telegram: https://t.me/evilfox100Bot diff --git a/internal/apphost/app.go b/internal/apphost/app.go index 6ef7281..16a4ae7 100644 --- a/internal/apphost/app.go +++ b/internal/apphost/app.go @@ -476,8 +476,14 @@ var allowedLinkHosts = map[string]bool{ "t.me": true, } +// allowedMailto are support addresses the UI may open via mailto:. +var allowedMailto = map[string]bool{ + "animegold3@gmail.com": true, + "admin@evilfox.win": true, +} + // LinkAllowed validates that raw is an http(s) URL pointing at one of the -// allowed hosts; returns the normalized URL. +// allowed hosts, or a mailto: address from the allowlist; returns the normalized URL. func LinkAllowed(raw string) (string, error) { raw = strings.TrimSpace(raw) if raw == "" { @@ -487,8 +493,23 @@ func LinkAllowed(raw string) (string, error) { if err != nil { return "", fmt.Errorf("некорректная ссылка") } + if strings.EqualFold(u.Scheme, "mailto") { + addr := strings.TrimSpace(u.Opaque) + if addr == "" { + addr = strings.TrimSpace(u.Path) + } + addr = strings.TrimPrefix(addr, "//") + if i := strings.IndexAny(addr, "?#"); i >= 0 { + addr = addr[:i] + } + addr = strings.ToLower(addr) + if !allowedMailto[addr] { + return "", fmt.Errorf("почта %s не разрешена", addr) + } + return "mailto:" + addr, nil + } if u.Scheme != "https" && u.Scheme != "http" { - return "", fmt.Errorf("разрешены только http(s) ссылки") + return "", fmt.Errorf("разрешены только http(s) и mailto ссылки") } if !allowedLinkHosts[strings.ToLower(u.Hostname())] { return "", fmt.Errorf("ссылка на %s не разрешена", u.Hostname()) diff --git a/internal/appui/index.html b/internal/appui/index.html index 7381756..5f9ef98 100644 --- a/internal/appui/index.html +++ b/internal/appui/index.html @@ -1379,6 +1379,11 @@ gap: 8px; } .key-box h3 { font-family: Outfit, sans-serif; font-size: .95rem; letter-spacing: -.02em; margin: 0; } + .key-box #subUrl { + width: 100%; min-height: 64px; max-height: 160px; resize: vertical; + font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; + font-size: .8rem; line-height: 1.35; + } .key-hint { margin: 0; font-size: .76rem; color: var(--muted); line-height: 1.4; } /* Статус конфигурации: 🟢 добавлена / 🔴 не добавлена (сам URL не показываем). */ .key-status { margin: 0; font-size: .8rem; font-weight: 700; } @@ -1623,9 +1628,9 @@

🔗 Добавить конфигурацию

🔴 Конфигурация не добавлена

- + -

Вставьте URL-ссылку для подключения

+

http(s) URL подписки/файла — или вставьте awg://, AWG .conf, naive, hy2, vless…

@@ -1910,7 +1915,7 @@

14. Изменения

Мы можем обновлять эту политику. Актуальная версия доступна в приложении (Помощь) и на сайте. Продолжение использования после обновления означает ознакомление с новой редакцией.

15. Контакты

-

EvilFox · https://evilfox.win/ · поддержка: https://t.me/evilfox100Bot

+

EvilFox · https://evilfox.win/
Основная почта: animegold3@gmail.com · Резервная: admin@evilfox.win · Telegram: https://t.me/evilfox100Bot

@@ -1976,7 +1981,7 @@

9. Применимое право

Эти Условия толкуются по законам страны вашего проживания, если иное не требуется императивными нормами. Для потребителей в ЕС сохраняются обязательные права по праву страны проживания.

10. Контакты

-

EvilFox · https://evilfox.win/ · https://t.me/evilfox100Bot

+

EvilFox · https://evilfox.win/
Основная: animegold3@gmail.com · Резервная: admin@evilfox.win · Telegram: https://t.me/evilfox100Bot

@@ -2142,7 +2147,7 @@ offer_text: "🎁 3 дня бесплатного доступа", page_profiles: "Мои серверы", add_config_aria: "Добавить конфигурацию", add_config_title: "🔗 Добавить конфигурацию", add_config_btn: "Добавить конфигурацию", - add_config_hint: "Вставьте URL-ссылку для подключения", where_url: "Где взять URL-ссылку?", + add_config_hint: "http(s) URL подписки/файла — или вставьте awg://, AWG .conf, naive, hy2, vless…", where_url: "Где взять URL-ссылку?", servers_title: "🌍 Серверы", ping_btn: "Пинг", best_btn: "Выбрать лучший", best_btn_title: "Выбрать сервер с наименьшим пингом", account_info: "Информация об аккаунте", expires_label: "Действует до", @@ -2233,8 +2238,8 @@ meta_opening_site: "Открываю evilfox.win…", meta_opened: "Открыто в браузере", meta_open_fail: "Не удалось открыть ссылку", meta_opening_named: "Открываю {name}…", - svc_site: "Сайт", svc_support: "Поддержка: Telegram", - meta_need_url: "Вставьте URL-ссылку для подключения", + svc_site: "Сайт", svc_mail: "Основная почта", svc_mail_backup: "Резервная почта", svc_support: "Поддержка: Telegram", + meta_need_url: "Вставьте URL или конфигурацию (AWG / naive / hy2…)", meta_adding_config: "Добавление конфигурации…", meta_picking_best: "подбираю оптимальный сервер…", import_ok: "Конфигурация добавлена · серверов: {n}", @@ -2266,7 +2271,7 @@ offer_text: "🎁 3 days free access", page_profiles: "My servers", add_config_aria: "Add configuration", add_config_title: "🔗 Add configuration", add_config_btn: "Add configuration", - add_config_hint: "Paste a connection URL", where_url: "Where do I get a URL?", + add_config_hint: "http(s) subscription/file URL — or paste awg://, AWG .conf, naive, hy2, vless…", where_url: "Where do I get a URL?", servers_title: "🌍 Servers", ping_btn: "Ping", best_btn: "Pick best", best_btn_title: "Select the server with the lowest ping", account_info: "Account info", expires_label: "Valid until", @@ -2357,8 +2362,8 @@ meta_opening_site: "Opening evilfox.win…", meta_opened: "Opened in browser", meta_open_fail: "Could not open link", meta_opening_named: "Opening {name}…", - svc_site: "Website", svc_support: "Support: Telegram", - meta_need_url: "Paste a connection URL", + svc_site: "Website", svc_mail: "Primary email", svc_mail_backup: "Backup email", svc_support: "Support: Telegram", + meta_need_url: "Paste a URL or config (AWG / naive / hy2…)", meta_adding_config: "Adding configuration…", meta_picking_best: "picking optimal server…", import_ok: "Configuration added · servers: {n}", @@ -2777,6 +2782,8 @@ // (internal/apphost/app.go → allowedLinkHosts). const RECOMMENDED_SERVICES = [ { icon: "🌐", nameKey: "svc_site", url: "https://evilfox.win/" }, + { icon: "✉️", nameKey: "svc_mail", url: "mailto:animegold3@gmail.com" }, + { icon: "📧", nameKey: "svc_mail_backup", url: "mailto:admin@evilfox.win" }, { icon: "✈️", nameKey: "svc_support", url: "https://t.me/evilfox100Bot" } ]; const AUTO_BEST_KEY = "navis.autoBest"; @@ -3989,7 +3996,7 @@ } catch (e) { setMeta(String(e), "err"); } })); subUrl.addEventListener("keydown", (e) => { - if (e.key === "Enter") { + if (e.key === "Enter" && (e.ctrlKey || e.metaKey)) { e.preventDefault(); subBtn.click(); } diff --git a/internal/core/manager.go b/internal/core/manager.go index 6a1f88b..5aee567 100644 --- a/internal/core/manager.go +++ b/internal/core/manager.go @@ -632,6 +632,9 @@ type ImportResult struct { func (m *Manager) ImportSubscription(rawURL string) (ImportResult, error) { rawURL = strings.TrimSpace(rawURL) + if rawURL == "" { + return ImportResult{}, fmt.Errorf("пустой URL или конфигурация") + } ctx, cancel := context.WithTimeout(context.Background(), 45*time.Second) defer cancel() @@ -650,11 +653,25 @@ func (m *Manager) ImportSubscription(rawURL string) (ImportResult, error) { return m.applySubscription(ctx, res, used, &s) } - res, err := subscription.Fetch(ctx, rawURL) - if err != nil { - return ImportResult{}, err + // Remote subscription / hosted config file (http(s) without user:pass@). + if linknorm.LooksLikeSubscriptionURL(rawURL) { + res, err := subscription.Fetch(ctx, rawURL) + if err != nil { + return ImportResult{}, err + } + return m.applySubscription(ctx, res, rawURL, nil) } - return m.applySubscription(ctx, res, rawURL, nil) + + // Direct paste into «Добавить конфигурацию»: awg://, AWG 2.0 .conf / JSON, + // naive share links, Clash YAML body, multi-line link lists — no HTTP fetch. + res, err := subscription.ParseBodyDetailed(rawURL) + if err != nil || res == nil || len(res.Items) == 0 { + if err != nil { + return ImportResult{}, fmt.Errorf("%w — либо вставьте http(s) URL конфигурации, либо ссылку/тело AWG, naive, hy2, vless…", err) + } + return ImportResult{}, fmt.Errorf("не удалось распознать конфигурацию — нужен http(s) URL либо ссылка/тело (AWG, naive, hy2, vless…)") + } + return m.applySubscription(ctx, res, "", nil) } // ImportRemnawave fetches configs using saved / provided panel settings. diff --git a/internal/core/manager_test.go b/internal/core/manager_test.go index 1d86c72..d158e71 100644 --- a/internal/core/manager_test.go +++ b/internal/core/manager_test.go @@ -87,3 +87,60 @@ func TestSaveProfileKeepsNaiveLink(t *testing.T) { t.Fatalf("naive profile broken: %+v", p) } } + +// «Добавить конфигурацию» must accept pasted AWG 2.0 .conf / naive links, +// not only http(s) subscription URLs (regression: "нужен http(s) URL"). +func TestImportSubscriptionDirectAWGAndNaive(t *testing.T) { + m := newTestManager(t) + awgBody := `[Interface] +PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +Address = 10.8.0.2/32 +Jc = 4 +Jmin = 40 +Jmax = 70 +H1 = 1 +H2 = 2 +H3 = 3 +H4 = 4 + +[Peer] +PublicKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE= +Endpoint = 203.0.113.10:51820 +AllowedIPs = 0.0.0.0/0 +` + r, err := m.ImportSubscription(awgBody) + if err != nil { + t.Fatalf("AWG paste: %v", err) + } + if r.Imported < 1 { + t.Fatalf("AWG imported=%d", r.Imported) + } + foundAWG := false + for _, p := range m.Profiles() { + if config.Protocol(p.Protocol) == config.ProtocolAWG && strings.Contains(p.Proxy, "203.0.113.10:51820") { + foundAWG = true + break + } + } + if !foundAWG { + t.Fatal("AWG profile missing") + } + + r2, err := m.ImportSubscription("https://user:secret@naive.example.com:443#NV") + if err != nil { + t.Fatalf("naive paste: %v", err) + } + if r2.Imported < 1 { + t.Fatalf("naive imported=%d", r2.Imported) + } + foundNaive := false + for _, p := range m.Profiles() { + if config.Protocol(p.Protocol) == config.ProtocolNaive && strings.Contains(p.Proxy, "naive.example.com") { + foundNaive = true + break + } + } + if !foundNaive { + t.Fatal("naive profile missing") + } +} diff --git a/internal/subscription/fetch.go b/internal/subscription/fetch.go index 49f12f4..2b7e9b3 100644 --- a/internal/subscription/fetch.go +++ b/internal/subscription/fetch.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "fmt" "io" + "net" "net/http" "net/url" "regexp" @@ -15,6 +16,7 @@ import ( "vpnclient/internal/config" "vpnclient/internal/linknorm" + "vpnclient/internal/protocols/awg" "vpnclient/internal/protocols/hysteria2" "vpnclient/internal/protocols/naive" ) @@ -46,7 +48,7 @@ type Result struct { const maxWarnings = 8 var ( - reShareLine = regexp.MustCompile(`(?i)((?:hysteria2|hy2|vless|vmess|trojan|awg|amneziawg|wireguard|naive\+https|naive\+quic|naive|quic|https|http)://[^\s"'<>]+)`) + reShareLine = regexp.MustCompile(`(?i)((?:hysteria2|hy2|vless|vmess|trojan|awg|amneziawg|wireguard|vpn|naive\+https|naive\+quic|naive|quic|https|http)://[^\s"'<>]+)`) reClashHY2 = regexp.MustCompile(`(?is)type:\s*hysteria2\b.*?server:\s*(\S+).*?port:\s*(\d+).*?(?:password|auth):\s*["']?([^\s"']+)`) // reURILine matches a standalone "scheme://..." line — only such lines are // counted as skipped entries (YAML/HTML noise is ignored silently). @@ -222,35 +224,38 @@ func parseText(text string) *Result { // countSkips is true only for raw subscription lines; URIs extracted from // YAML/HTML/JSON noise are best-effort and never counted as "skipped". - process := func(line string, countSkips bool) { - line = strings.TrimSpace(line) - if line == "" || strings.HasPrefix(line, "#") { + process := func(raw string, countSkips bool) { + raw = strings.TrimSpace(raw) + if raw == "" || strings.HasPrefix(raw, "#") { return } - line = strings.Trim(line, `"'`) - looksURI := reURILine.MatchString(line) + // Only strip surrounding quotes on single-line share links. + if !strings.Contains(raw, "\n") { + raw = strings.Trim(raw, `"'`) + } + looksURI := reURILine.MatchString(raw) skip := func(reason string) { if !countSkips || !looksURI { return } res.Skipped++ if len(res.Warnings) < maxWarnings { - res.Warnings = append(res.Warnings, shortenLink(line)+" — "+reason) + res.Warnings = append(res.Warnings, shortenLink(raw)+" — "+reason) } } - proto := config.DetectProtocol(line) + proto := config.DetectProtocol(raw) if proto == "" { skip("неподдерживаемая схема") return } // Bare https:// without credentials (common noise in HTML/YAML, // or a subscription URL pasted among the links) is not a proxy link. - if proto == config.ProtocolNaive && !naiveLinkHasAuth(line) && !strings.HasPrefix(strings.ToLower(line), "naive+") { + if proto == config.ProtocolNaive && !naiveLinkHasAuth(raw) && !strings.HasPrefix(strings.ToLower(raw), "naive+") { skip("нет логина и пароля в ссылке") return } - normalized, detected, remark, err := linknorm.Normalize(proto, line) + normalized, detected, remark, err := linknorm.Normalize(proto, raw) if err != nil { skip(err.Error()) return @@ -263,6 +268,12 @@ func parseText(text string) *Result { if name == "" { name = defaultName(detected, normalized) } + // Clash wireguard INI may carry "# name: …" — prefer that display name. + if detected == config.ProtocolAWG { + if n := awgCommentName(raw); n != "" { + name = n + } + } base := name for n := 2; ; n++ { if _, ok := seen[name]; !ok { @@ -274,6 +285,15 @@ func parseText(text string) *Result { res.Items = append(res.Items, Item{Name: name, Protocol: detected, URI: normalized}) } + // Whole-body AWG/WireGuard .conf, Amnezia JSON, vpn:// — hosted as a single + // HTTP(S) config file (line-oriented parsing cannot reconstruct these). + if awg.Detect(text) { + process(text, false) + if len(res.Items) > 0 && !looksLikeShareList(text) { + return res + } + } + for _, line := range splitLines(text) { process(line, true) } @@ -281,12 +301,39 @@ func parseText(text string) *Result { for _, m := range reShareLine.FindAllString(text, -1) { process(strings.TrimRight(m, ".,;)]}\"'"), false) } - for _, block := range extractClashHY2(text) { + for _, block := range extractClashProxies(text) { process(block, false) } return res } +// looksLikeShareList reports bodies that also contain line-oriented share links +// (mixed subscription + AWG is rare, but do not early-return on those). +func looksLikeShareList(text string) bool { + lower := strings.ToLower(text) + for _, p := range []string{"vless://", "vmess://", "trojan://", "hysteria2://", "hy2://", "naive+", "ss://"} { + if strings.Contains(lower, p) { + return true + } + } + return false +} + +func awgCommentName(raw string) string { + for _, line := range splitLines(raw) { + line = strings.TrimSpace(line) + if !strings.HasPrefix(line, "#") { + continue + } + rest := strings.TrimSpace(strings.TrimPrefix(line, "#")) + lower := strings.ToLower(rest) + if strings.HasPrefix(lower, "name:") { + return strings.TrimSpace(rest[len("name:"):]) + } + } + return "" +} + // shortenLink trims a link for warning messages, hiding query/credentials noise. func shortenLink(line string) string { if i := strings.IndexAny(line, "?#"); i >= 0 { @@ -312,62 +359,193 @@ func naiveLinkHasAuth(line string) bool { return false } -func extractClashHY2(text string) []string { - // Very small helper for Clash YAML hysteria2 blocks when share URI is absent. +// extractClashProxies builds share links from Clash YAML proxy blocks when the +// panel does not embed native share URIs (hysteria2, wireguard/AWG, naive). +func extractClashProxies(text string) []string { lower := strings.ToLower(text) - if !strings.Contains(lower, "type:") || !strings.Contains(lower, "hysteria2") { + if !strings.Contains(lower, "type:") { + return nil + } + need := strings.Contains(lower, "hysteria2") || + strings.Contains(lower, "wireguard") || + strings.Contains(lower, "type: naive") || + strings.Contains(lower, "type:naive") + if !need { return nil } var out []string - // Split roughly by list items. - chunks := splitClashItems(text) - for _, chunk := range chunks { + for _, chunk := range splitClashItems(text) { cl := strings.ToLower(chunk) - if !strings.Contains(cl, "type:") || !strings.Contains(cl, "hysteria2") { - continue + typ := strings.ToLower(yamlField(chunk, "type")) + switch { + case typ == "hysteria2" || (typ == "" && strings.Contains(cl, "hysteria2")): + if link := clashHY2Link(chunk); link != "" { + out = append(out, link) + } + case typ == "wireguard": + if link := clashWireguardLink(chunk); link != "" { + out = append(out, link) + } + case typ == "naive": + if link := clashNaiveLink(chunk); link != "" { + out = append(out, link) + } } - server := yamlField(chunk, "server") - port := yamlField(chunk, "port") - pass := yamlField(chunk, "password") - if pass == "" { - pass = yamlField(chunk, "auth") - } - if server == "" || port == "" || pass == "" { - continue - } - name := yamlField(chunk, "name") - sni := yamlField(chunk, "sni") - obfs := yamlField(chunk, "obfs") - obfsPass := yamlField(chunk, "obfs-password") - if obfsPass == "" { - obfsPass = yamlField(chunk, "obfs_password") - } - u := url.URL{ - Scheme: "hysteria2", - User: url.User(pass), - Host: server + ":" + port, - } - q := url.Values{} - if sni != "" { - q.Set("sni", sni) - } - if obfs != "" { - q.Set("obfs", obfs) - } - if obfsPass != "" { - q.Set("obfs-password", obfsPass) - } - u.RawQuery = q.Encode() - link := u.String() - if name != "" { - link += "#" + url.PathEscape(name) - } - out = append(out, link) } _ = reClashHY2 // kept for possible future tightening return out } +func clashHY2Link(chunk string) string { + server := yamlField(chunk, "server") + port := yamlField(chunk, "port") + pass := yamlField(chunk, "password") + if pass == "" { + pass = yamlField(chunk, "auth") + } + if server == "" || port == "" || pass == "" { + return "" + } + name := yamlField(chunk, "name") + sni := yamlField(chunk, "sni") + obfs := yamlField(chunk, "obfs") + obfsPass := yamlField(chunk, "obfs-password") + if obfsPass == "" { + obfsPass = yamlField(chunk, "obfs_password") + } + u := url.URL{ + Scheme: "hysteria2", + User: url.User(pass), + Host: server + ":" + port, + } + q := url.Values{} + if sni != "" { + q.Set("sni", sni) + } + if obfs != "" { + q.Set("obfs", obfs) + } + if obfsPass != "" { + q.Set("obfs-password", obfsPass) + } + u.RawQuery = q.Encode() + link := u.String() + if name != "" { + link += "#" + url.PathEscape(name) + } + return link +} + +func clashWireguardLink(chunk string) string { + priv := firstYAML(chunk, "private-key", "private_key") + pub := firstYAML(chunk, "public-key", "public_key") + server := yamlField(chunk, "server") + port := yamlField(chunk, "port") + ip := firstYAML(chunk, "ip", "address") + if priv == "" || pub == "" || server == "" || port == "" { + return "" + } + name := yamlField(chunk, "name") + psk := firstYAML(chunk, "pre-shared-key", "preshared-key", "presharedkey") + allowed := stripYAMLList(firstYAML(chunk, "allowed-ips", "allowed_ips")) + if allowed == "" { + allowed = "0.0.0.0/0" + } + dns := stripYAMLList(yamlField(chunk, "dns")) + mtu := yamlField(chunk, "mtu") + keepalive := firstYAML(chunk, "persistent-keepalive", "keepalive") + + var b strings.Builder + b.WriteString("[Interface]\n") + b.WriteString("PrivateKey = " + priv + "\n") + if ip != "" { + b.WriteString("Address = " + ip + "\n") + } + if dns != "" { + b.WriteString("DNS = " + dns + "\n") + } + if mtu != "" { + b.WriteString("MTU = " + mtu + "\n") + } + // AmneziaWG / AWG 2.0 obfuscation (Clash Meta / Amnezia exports). + for _, k := range []string{"jc", "jmin", "jmax", "s1", "s2", "s3", "s4", "h1", "h2", "h3", "h4", "i1", "i2", "i3", "i4", "i5"} { + v := firstYAML(chunk, k, strings.ToUpper(k), strings.ToUpper(k[:1])+k[1:]) + if v == "" { + continue + } + canon := strings.ToUpper(k[:1]) + k[1:] + b.WriteString(canon + " = " + v + "\n") + } + b.WriteString("\n[Peer]\n") + b.WriteString("PublicKey = " + pub + "\n") + if psk != "" { + b.WriteString("PresharedKey = " + psk + "\n") + } + b.WriteString("Endpoint = " + server + ":" + port + "\n") + b.WriteString("AllowedIPs = " + allowed + "\n") + if keepalive != "" { + b.WriteString("PersistentKeepalive = " + keepalive + "\n") + } + if name != "" { + b.WriteString("# name: " + name + "\n") + } + return b.String() +} + +func clashNaiveLink(chunk string) string { + server := yamlField(chunk, "server") + port := yamlField(chunk, "port") + user := firstYAML(chunk, "username", "user") + pass := yamlField(chunk, "password") + if server == "" || user == "" || pass == "" { + return "" + } + if port == "" { + port = "443" + } + name := yamlField(chunk, "name") + udp := strings.ToLower(yamlField(chunk, "udp")) + scheme := "https" + if udp == "true" || udp == "yes" || strings.EqualFold(yamlField(chunk, "protocol"), "quic") { + scheme = "quic" + } + u := url.URL{ + Scheme: scheme, + User: url.UserPassword(user, pass), + Host: server + ":" + port, + } + link := u.String() + if name != "" { + link += "#" + url.PathEscape(name) + } + return link +} + +func firstYAML(block string, keys ...string) string { + for _, k := range keys { + if v := yamlField(block, k); v != "" { + return v + } + } + return "" +} + +func stripYAMLList(v string) string { + v = strings.TrimSpace(v) + v = strings.TrimPrefix(v, "[") + v = strings.TrimSuffix(v, "]") + parts := strings.Split(v, ",") + var clean []string + for _, p := range parts { + p = strings.TrimSpace(p) + p = strings.Trim(p, `"'`) + if p != "" { + clean = append(clean, p) + } + } + return strings.Join(clean, ", ") +} + // reClashItemStart matches a mapping list item ("- name: X", " - type: y"), // but not nested scalar list entries like "- h3" under alpn. var reClashItemStart = regexp.MustCompile(`^\s*-\s+[^\s:]+\s*:`) @@ -442,6 +620,17 @@ func defaultName(proto config.Protocol, uri string) string { if h, _, err := hysteria2.HostPort(uri); err == nil { host = h } + case config.ProtocolAWG: + if c, err := awg.Parse(uri); err == nil { + if c.Name != "" { + return c.Name + } + if h, _, e := net.SplitHostPort(c.Endpoint); e == nil { + host = h + } else { + host = c.Endpoint + } + } default: if u, _, err := naive.ParseShareLink(uri); err == nil { if parsed, err := url.Parse(u); err == nil { diff --git a/internal/subscription/fetch_test.go b/internal/subscription/fetch_test.go index ae60489..6f96bc0 100644 --- a/internal/subscription/fetch_test.go +++ b/internal/subscription/fetch_test.go @@ -3,6 +3,7 @@ package subscription import ( "context" "encoding/base64" + "io" "net/http" "net/http/httptest" "strings" @@ -193,3 +194,161 @@ proxies: t.Fatalf("uri %s", items[0].URI) } } + +func TestParseBodyAWGConf(t *testing.T) { + body := `[Interface] +PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +Address = 10.8.0.2/32 +DNS = 1.1.1.1 +Jc = 4 +Jmin = 40 +Jmax = 70 +H1 = 1 +H2 = 2 +H3 = 3 +H4 = 4 +I1 = + +[Peer] +PublicKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE= +Endpoint = 203.0.113.10:51820 +AllowedIPs = 0.0.0.0/0 +PersistentKeepalive = 25 +` + items, err := ParseBody(body) + if err != nil { + t.Fatal(err) + } + if len(items) != 1 { + t.Fatalf("got %d items: %+v", len(items), items) + } + if items[0].Protocol != "awg" { + t.Fatalf("proto %s", items[0].Protocol) + } + if !strings.Contains(items[0].URI, "Jc = 4") || !strings.Contains(items[0].URI, "203.0.113.10:51820") { + t.Fatalf("uri missing AWG2 fields: %s", items[0].URI) + } +} + +func TestParseBodyAmneziaJSON(t *testing.T) { + body := `{ + "client_priv_key": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + "server_pub_key": "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=", + "client_ip": "10.8.0.2/32", + "hostName": "203.0.113.10", + "port": "51820", + "Jc": 4, + "Jmin": 10, + "Jmax": 50, + "H1": "1", + "H2": "2", + "H3": "3", + "H4": "4" +}` + items, err := ParseBody(body) + if err != nil { + t.Fatal(err) + } + if len(items) != 1 || items[0].Protocol != "awg" { + t.Fatalf("got %+v", items) + } + if !strings.Contains(items[0].URI, "203.0.113.10:51820") { + t.Fatalf("uri %s", items[0].URI) + } +} + +func TestParseBodyClashWireguardAWG20(t *testing.T) { + body := `proxies: + - name: AWG-EU + type: wireguard + server: 203.0.113.20 + port: 51820 + ip: 10.8.0.2/32 + private-key: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + public-key: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE= + allowed-ips: ['0.0.0.0/0'] + dns: [1.1.1.1] + jc: 4 + jmin: 40 + jmax: 70 + h1: 1 + h2: 2 + h3: 3 + h4: 4 +` + items, err := ParseBody(body) + if err != nil { + t.Fatal(err) + } + if len(items) != 1 { + t.Fatalf("got %d: %+v", len(items), items) + } + if items[0].Protocol != "awg" { + t.Fatalf("proto %s", items[0].Protocol) + } + if items[0].Name != "AWG-EU" { + t.Fatalf("name %q", items[0].Name) + } + if !strings.Contains(items[0].URI, "Jc = 4") || !strings.Contains(items[0].URI, "203.0.113.20:51820") { + t.Fatalf("uri %s", items[0].URI) + } +} + +func TestParseBodyClashNaive(t *testing.T) { + body := `proxies: + - name: Naive-HTTPS + type: naive + server: naive.example.com + port: 443 + username: user + password: secret + - name: Naive-QUIC + type: naive + server: quic.example.com + port: 443 + username: u2 + password: p2 + udp: true +` + items, err := ParseBody(body) + if err != nil { + t.Fatal(err) + } + if len(items) != 2 { + t.Fatalf("got %d: %+v", len(items), items) + } + if items[0].Protocol != "naive" || items[1].Protocol != "naive" { + t.Fatalf("protos %s %s", items[0].Protocol, items[1].Protocol) + } + if !strings.Contains(items[0].URI, "https://") || !strings.Contains(items[0].URI, "user:secret@naive.example.com") { + t.Fatalf("https uri %s", items[0].URI) + } + if !strings.Contains(items[1].URI, "quic://") || !strings.Contains(items[1].URI, "u2:p2@quic.example.com") { + t.Fatalf("quic uri %s", items[1].URI) + } +} + +func TestFetchAWGConfOverHTTP(t *testing.T) { + conf := `[Interface] +PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +Address = 10.8.0.2/32 +Jc = 3 + +[Peer] +PublicKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE= +Endpoint = 198.51.100.7:51820 +AllowedIPs = 0.0.0.0/0 +` + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + _, _ = io.WriteString(w, conf) + })) + defer srv.Close() + + res, err := Fetch(context.Background(), srv.URL+"/awg.conf") + if err != nil { + t.Fatal(err) + } + if len(res.Items) != 1 || res.Items[0].Protocol != "awg" { + t.Fatalf("got %+v", res.Items) + } +} diff --git a/packaging/msix/AppxManifest.xml b/packaging/msix/AppxManifest.xml index a590afe..c0ee460 100644 --- a/packaging/msix/AppxManifest.xml +++ b/packaging/msix/AppxManifest.xml @@ -32,9 +32,9 @@ diff --git a/screen/1.ru.300x300.fit.png b/screen/1.ru.300x300.fit.png new file mode 100644 index 0000000000000000000000000000000000000000..9f9ee4d90e8b68009632dadc8449313862cb4450 GIT binary patch literal 33267 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 literal 0 HcmV?d00001 diff --git a/scripts/pack-msix.ps1 b/scripts/pack-msix.ps1 index 471bea4..d13a714 100644 --- a/scripts/pack-msix.ps1 +++ b/scripts/pack-msix.ps1 @@ -13,9 +13,11 @@ .EXAMPLE .\scripts\pack-msix.ps1 - .\scripts\pack-msix.ps1 -Arch x64 -Version 4.2.8.1 + .\scripts\pack-msix.ps1 -Arch x64 -Version 4.2.8.0 .\scripts\pack-msix.ps1 -Arch arm64 -ExePath dist\navis-release\windows\arm64\EvilFox.exe .\scripts\pack-msix.ps1 -Arch all -OutDir dist\microsoft-store + + Store note: Identity Version MUST end with .0 (revision). Partner Center rejects 4.2.8.1. #> [CmdletBinding()] param( @@ -23,9 +25,9 @@ param( [string]$Arch = "all", [string]$ExePath = "", [string]$OutDir = "", - [string]$Version = "4.2.8.1", - [string]$Name = "EvilFox.EvilFox", - [string]$Publisher = "CN=EvilFox", + [string]$Version = "4.2.8.0", + [string]$Name = "EvilFox.evilfox", + [string]$Publisher = "CN=9D58DFF7-7918-460E-845B-B3904A30562A", [string]$DisplayName = "EvilFox", [string]$PublisherDisplayName = "EvilFox", [string]$CertPath = "", @@ -57,6 +59,17 @@ function Find-SdkTool([string]$name) { $candidates += (Join-Path $_.FullName "x86\$name") } } + # MSIX Toolkit via winget (MakeAppx without full Windows SDK) + $wingetPkgs = Join-Path $env:LOCALAPPDATA "Microsoft\WinGet\Packages" + if (Test-Path $wingetPkgs) { + Get-ChildItem -Path $wingetPkgs -Directory -Filter "Microsoft.MSIX-Toolkit*" -ErrorAction SilentlyContinue | + ForEach-Object { + $candidates += (Join-Path $_.FullName "MSIX-Toolkit.x64\$name") + $candidates += (Join-Path $_.FullName "MSIX-Toolkit.x86\$name") + Get-ChildItem -Path $_.FullName -Recurse -Filter $name -ErrorAction SilentlyContinue | + ForEach-Object { $candidates += $_.FullName } + } + } foreach ($p in $candidates) { if (Test-Path -LiteralPath $p) { return $p } } @@ -235,8 +248,15 @@ foreach ($a in $archList) { $ManifestDst = Join-Path $Staging "AppxManifest.xml" $manifestText = Get-Content -LiteralPath $ManifestSrc -Raw -Encoding UTF8 # Prefer exact placeholder swaps so we never touch . + $manifestText = $manifestText.Replace('Name="EvilFox.evilfox"', "Name=`"$Name`"") $manifestText = $manifestText.Replace('Name="EvilFox.EvilFox"', "Name=`"$Name`"") + $manifestText = $manifestText.Replace('Publisher="CN=9D58DFF7-7918-460E-845B-B3904A30562A"', "Publisher=`"$Publisher`"") $manifestText = $manifestText.Replace('Publisher="CN=EvilFox"', "Publisher=`"$Publisher`"") + # Store requires Identity Version revision (4th component) to be 0. + if ($Version -notmatch '^\d+\.\d+\.\d+\.0$') { + Write-Host "WARNING: Partner Center rejects non-zero revision; use e.g. 4.2.8.0 (got '$Version')." -ForegroundColor Yellow + } + $manifestText = $manifestText.Replace('Version="4.2.8.0"', "Version=`"$Version`"") $manifestText = $manifestText.Replace('Version="4.2.8.1"', "Version=`"$Version`"") # Also accept older template version if someone reverts the manifest placeholder. $manifestText = $manifestText.Replace('Version="4.2.3.1"', "Version=`"$Version`"") diff --git a/store.csv b/store.csv index 0ffd9a0..f61756d 100644 --- a/store.csv +++ b/store.csv @@ -1,4 +1,4 @@ -Field,ID,Type (Тип),default,en +Field,ID,Type (Тип),default,en Description,2,Текст,"EvilFox — приложение для безопасного доступа в интернет на Windows. Защитите данные в публичных Wi‑Fi сетях: EvilFox шифрует трафик, скрывает ваш реальный IP-адрес и помогает предотвратить утечки DNS. Современный интерфейс на русском и английском, светлая и тёмная темы, удобный выбор серверов и понятный статус подключения. @@ -34,15 +34,75 @@ EvilFox is built for everyday browsing, travel, and privacy. You add your own co Website: https://evilfox.win/ Support: https://t.me/evilfox100Bot" -ReleaseNotes,3,Текст,"Обновление 4.2: улучшенный интерфейс для Microsoft Store, переключатель языка RU/EN, светлая тема по умолчанию, группировка серверов по IP с отображением доступных протоколов, исправления переключателей темы и языка, реальные флаги стран (SVG), Kill Switch и статистика.","Version 4.2: Microsoft Store–ready UI polish, RU/EN language switch, light theme by default, servers grouped by IP with available protocols, theme/language toggle fixes, real country flags (SVG), Kill Switch, and usage statistics." +ReleaseNotes,3,Текст,"EvilFox 4.2 — удобный и понятный клиент для безопасного доступа в интернет. + +Что нового для пользователей: +• Современный интерфейс: вкладки Защита, Мои серверы, Настройки, Статистика, Помощь +• Большая кнопка подключения и понятный статус защиты +• Светлая тема по умолчанию и переключение на тёмную +• Языки: русский и английский (RU | EN) +• Флаги стран у серверов (корректно на Windows) +• Серверы с одним IP объединяются в одну строку с доступными протоколами +• Добавление конфигурации по URL +• Режим прокси и полный режим защиты (TUN) +• Kill Switch — защита от утечек при обрыве соединения +• Автовыбор сервера с лучшим пингом +• Статистика трафика и сессий +• Политика конфиденциальности и условия использования в разделе Помощь +• Адаптивное окно под любой экран и масштаб Windows","EvilFox 4.2 — a clearer, more polished client for private internet access. + +What's new: +• Modern UI: Protection, My servers, Settings, Statistics, Help +• Large connect button and clear protection status +• Light theme by default, with dark theme toggle +• Russian and English languages (RU | EN) +• Country flags for servers (rendered correctly on Windows) +• Same-IP servers grouped into one row with available protocols +• Add configuration via URL +• Proxy mode and full protection mode (TUN) +• Kill Switch — leak protection if the connection drops +• Auto-select the lowest-ping server +• Traffic and session statistics +• Privacy Policy and Terms of Use in Help +• Adaptive window sizing for any screen and Windows display scale" Title,4,Текст,EvilFox,EvilFox ShortTitle,5,Текст,EvilFox,EvilFox SortTitle,6,Текст,EvilFox,EvilFox VoiceTitle,7,Текст,Evil Fox,Evil Fox ShortDescription,8,Текст,"Безопасный доступ в интернет: шифрование трафика, скрытие IP, защита от утечек DNS. Русский и английский. Современные протоколы, Kill Switch, удобный выбор серверов.","Secure internet access: encrypt traffic, hide your IP, help prevent DNS leaks. English & Russian. Modern protocols, Kill Switch, easy server selection." DevStudio,9,Текст,EvilFox,EvilFox -CopyrightTrademarkInformation,12,Текст,© EvilFox. All rights reserved. EvilFox and the EvilFox logo are trademarks of their respective owners.,© EvilFox. All rights reserved. EvilFox and the EvilFox logo are trademarks of their respective owners. -AdditionalLicenseTerms,13,Текст,Proprietary software. By installing EvilFox you agree to use the application in accordance with applicable laws. The app provides a client for encrypted network connections; server configurations are supplied by the user. See https://evilfox.win/ for support and terms.,Proprietary software. By installing EvilFox you agree to use the application in accordance with applicable laws. The app provides a client for encrypted network connections; server configurations are supplied by the user. See https://evilfox.win/ for support and terms. +CopyrightTrademarkInformation,12,Текст,"© 2026 EvilFox. Все права защищены. EvilFox, логотип EvilFox и связанные знаки являются товарными знаками или зарегистрированными товарными знаками EvilFox. Прочие названия продуктов и компаний, упомянутые в приложении или на странице продукта, могут быть товарными знаками соответствующих владельцев.","© 2026 EvilFox. All rights reserved. EvilFox, the EvilFox logo, and related marks are trademarks or registered trademarks of EvilFox. Other product and company names mentioned in the app or product listing may be trademarks of their respective owners." +AdditionalLicenseTerms,13,Текст,"Дополнительно к стандартным условиям лицензии Microsoft Store / приложения: + +1. EvilFox — клиент для защищённого сетевого подключения. Конфигурации серверов и URL подключения предоставляются вами и не являются частью покупки в Store (если применимо). + +2. Вы несёте ответственность за законность использования приложения и выбранных серверов в вашей юрисдикции. + +3. Издатель не гарантирует бесперебойную работу сторонних серверов, скорость или доступность конкретных узлов. + +4. Приложение может хранить настройки и конфигурации локально на устройстве. Политика конфиденциальности и полные условия использования доступны в разделе «Помощь» приложения и на https://evilfox.win/ + +5. Обновления через Microsoft Store заменяют самообновление приложения в сборке Store. + +6. Возможность runFullTrust / классическое настольное приложение требуется для работы клиента (WebView2, сетевые режимы). + +Контакты: https://evilfox.win/ · https://t.me/evilfox100Bot +","In addition to the standard Microsoft Store / app license terms: + +1. EvilFox is a client for protected network connectivity. Server configurations and connection URLs are supplied by you and are not part of any Store purchase (where applicable). + +2. You are responsible for using the app and chosen servers lawfully in your jurisdiction. + +3. The publisher does not warrant uninterrupted operation of third-party servers, speed, or availability of specific nodes. + +4. The app may store settings and configurations locally on your device. The Privacy Policy and full Terms of Use are available in the app Help section and at https://evilfox.win/ + +5. Updates delivered via the Microsoft Store replace in-app self-update in Store builds. + +6. The runFullTrust / classic desktop capability is required for the client to function (WebView2, network modes). + +Contact: https://evilfox.win/ · https://t.me/evilfox100Bot +" DesktopScreenshot1,100,Относительный путь (или URL-адрес файла в Центре партнеров),screen/1.ru.png,screen/7.en.png DesktopScreenshot2,101,Относительный путь (или URL-адрес файла в Центре партнеров),screen/2.ru.png,screen/8.en.png DesktopScreenshot3,102,Относительный путь (или URL-адрес файла в Центре партнеров),screen/3.ru.png,screen/9.png @@ -75,8 +135,8 @@ DesktopScreenshot29,128,Относительный путь (или URL-адре DesktopScreenshot30,129,Относительный путь (или URL-адрес файла в Центре партнеров),, DesktopScreenshotCaption1,150,Текст,Главный экран: подключение и статус защиты,Home: connect and protection status DesktopScreenshotCaption2,151,Текст,Список серверов с флагами и пингом,Server list with flags and ping -DesktopScreenshotCaption3,152,Текст,"Настройки: тема, язык, Kill Switch",App overview -DesktopScreenshotCaption4,153,Текст,Статистика использования,"Settings: theme, language, Kill Switch" +DesktopScreenshotCaption3,152,Текст,"Настройки: тема, язык, Kill Switch","Settings: theme, language, Kill Switch" +DesktopScreenshotCaption4,153,Текст,Статистика использования,Usage statistics DesktopScreenshotCaption5,154,Текст,Помощь и полезные ссылки,Statistics and help DesktopScreenshotCaption6,155,Текст,Добавление конфигурации,Dark theme: home DesktopScreenshotCaption7,156,Текст,Тёмная тема: главный экран,Dark theme: servers @@ -325,7 +385,7 @@ SurfaceHubScreenshotCaption29,578,Текст,, SurfaceHubScreenshotCaption30,579,Текст,, StoreLogo720x1080,600,Относительный путь (или URL-адрес файла в Центре партнеров),, StoreLogo1080x1080,601,Относительный путь (или URL-адрес файла в Центре партнеров),, -StoreLogo300x300,602,Относительный путь (или URL-адрес файла в Центре партнеров),, +StoreLogo300x300,602,Относительный путь (или URL-адрес файла в Центре партнеров),screen/1.ru.300x300.png,screen/1.ru.300x300.png OverrideLogosForWin10,603,True/False,,False StoreLogoOverride150x150,604,Относительный путь (или URL-адрес файла в Центре партнеров),, StoreLogoOverride71x71,605,Относительный путь (или URL-адрес файла в Центре партнеров),, diff --git a/tools/fill_store_csv.py b/tools/fill_store_csv.py new file mode 100644 index 0000000..3bc4e78 --- /dev/null +++ b/tools/fill_store_csv.py @@ -0,0 +1,218 @@ +# -*- coding: utf-8 -*- +"""Fill Microsoft Store listing CSV text fields (default=RU, en=EN).""" +import csv +from pathlib import Path + +path = Path(__file__).resolve().parents[1] / "store.csv" + +ru = { + "Description": ( + "EvilFox — приложение для безопасного доступа в интернет на Windows.\n" + "\n" + "Защитите данные в публичных Wi‑Fi сетях: EvilFox шифрует трафик, " + "скрывает ваш реальный IP-адрес и помогает предотвратить утечки DNS. " + "Современный интерфейс на русском и английском, светлая и тёмная темы, " + "удобный выбор серверов и понятный статус подключения.\n" + "\n" + "Возможности:\n" + "• Шифрование трафика с поддержкой современных протоколов\n" + "• Режим прокси и полный режим защиты (TUN) для всего трафика приложений\n" + "• Защита от утечек (Kill Switch) при обрыве соединения\n" + "• Автовыбор сервера с наименьшим пингом\n" + "• Список серверов с флагами стран и группировкой по хосту\n" + "• Добавление собственной конфигурации по URL\n" + "• Мониторинг использования трафика и статистика сессий\n" + "• Интерфейс на русском и английском языках\n" + "\n" + "EvilFox подходит для повседневной работы, путешествий и защиты приватности. " + "Конфигурацию подключения вы добавляете самостоятельно; " + "покупки внутри приложения не требуются.\n" + "\n" + "Сайт: https://evilfox.win/\n" + "Поддержка: https://t.me/evilfox100Bot" + ), + "ReleaseNotes": ( + "Обновление 4.2: улучшенный интерфейс для Microsoft Store, " + "переключатель языка RU/EN, светлая тема по умолчанию, " + "группировка серверов по IP с отображением доступных протоколов, " + "исправления переключателей темы и языка, реальные флаги стран (SVG), " + "Kill Switch и статистика." + ), + "Title": "EvilFox", + "ShortTitle": "EvilFox", + "SortTitle": "EvilFox", + "VoiceTitle": "Evil Fox", + "ShortDescription": ( + "Безопасный доступ в интернет: шифрование трафика, скрытие IP, " + "защита от утечек DNS. Русский и английский. Современные протоколы, " + "Kill Switch, удобный выбор серверов." + ), + "DevStudio": "EvilFox", + "CopyrightTrademarkInformation": ( + "© EvilFox. All rights reserved. EvilFox and the EvilFox logo " + "are trademarks of their respective owners." + ), + "AdditionalLicenseTerms": ( + "Proprietary software. By installing EvilFox you agree to use the " + "application in accordance with applicable laws. The app provides a " + "client for encrypted network connections; server configurations are " + "supplied by the user. See https://evilfox.win/ for support and terms." + ), + "Feature1": "Шифрование трафика и скрытие IP-адреса", + "Feature2": "Режим прокси и полный режим защиты (TUN)", + "Feature3": "Kill Switch — блокировка трафика при обрыве VPN", + "Feature4": "Автовыбор сервера с лучшим пингом", + "Feature5": "Серверы с флагами стран и группировкой протоколов", + "Feature6": "Добавление конфигурации по URL", + "Feature7": "Статистика трафика и сессий", + "Feature8": "Интерфейс на русском и английском", + "Feature9": "Светлая и тёмная темы оформления", + "Feature10": "Защита от утечек DNS", + "MinimumHardwareReq1": "Windows 10 version 1809 or later (x64)", + "MinimumHardwareReq2": "Internet connection", + "MinimumHardwareReq3": "100 MB free disk space", + "RecommendedHardwareReq1": "Windows 11 (x64)", + "RecommendedHardwareReq2": "Stable broadband connection", + "SearchTerm1": "VPN", + "SearchTerm2": "privacy", + "SearchTerm3": "secure internet", + "SearchTerm4": "encrypt traffic", + "SearchTerm5": "EvilFox", + "SearchTerm6": "proxy client", + "SearchTerm7": "kill switch", + "DesktopScreenshotCaption1": "Главный экран: подключение и статус защиты", + "DesktopScreenshotCaption2": "Список серверов с флагами и пингом", + "DesktopScreenshotCaption3": "Настройки: тема, язык, Kill Switch", + "DesktopScreenshotCaption4": "Статистика использования", +} + +en = { + "Description": ( + "EvilFox is a Windows app for private, secure internet access.\n" + "\n" + "Protect your data on public Wi‑Fi: EvilFox encrypts your traffic, " + "hides your real IP address, and helps prevent DNS leaks. " + "A modern interface in English and Russian, light and dark themes, " + "an easy server list, and a clear connection status.\n" + "\n" + "Features:\n" + "• Traffic encryption with modern protocol support\n" + "• Proxy mode and full protection mode (TUN) for all app traffic\n" + "• Leak protection (Kill Switch) if the connection drops\n" + "• Auto-select the server with the lowest ping\n" + "• Server list with country flags and host grouping\n" + "• Add your own configuration via URL\n" + "• Traffic usage monitoring and session stats\n" + "• English and Russian interface\n" + "\n" + "EvilFox is built for everyday browsing, travel, and privacy. " + "You add your own connection configuration; no in-app purchases are required.\n" + "\n" + "Website: https://evilfox.win/\n" + "Support: https://t.me/evilfox100Bot" + ), + "ReleaseNotes": ( + "Version 4.2: Microsoft Store–ready UI polish, RU/EN language switch, " + "light theme by default, servers grouped by IP with available protocols, " + "theme/language toggle fixes, real country flags (SVG), Kill Switch, " + "and usage statistics." + ), + "Title": "EvilFox", + "ShortTitle": "EvilFox", + "SortTitle": "EvilFox", + "VoiceTitle": "Evil Fox", + "ShortDescription": ( + "Secure internet access: encrypt traffic, hide your IP, help prevent " + "DNS leaks. English & Russian. Modern protocols, Kill Switch, " + "easy server selection." + ), + "DevStudio": "EvilFox", + "CopyrightTrademarkInformation": ( + "© EvilFox. All rights reserved. EvilFox and the EvilFox logo " + "are trademarks of their respective owners." + ), + "AdditionalLicenseTerms": ( + "Proprietary software. By installing EvilFox you agree to use the " + "application in accordance with applicable laws. The app provides a " + "client for encrypted network connections; server configurations are " + "supplied by the user. See https://evilfox.win/ for support and terms." + ), + "Feature1": "Encrypt traffic and hide your IP address", + "Feature2": "Proxy mode and full protection mode (TUN)", + "Feature3": "Kill Switch blocks traffic if VPN drops", + "Feature4": "Auto-select the lowest-ping server", + "Feature5": "Servers with country flags and protocol grouping", + "Feature6": "Add configuration via URL", + "Feature7": "Traffic and session statistics", + "Feature8": "English and Russian interface", + "Feature9": "Light and dark themes", + "Feature10": "DNS leak protection", + "MinimumHardwareReq1": "Windows 10 version 1809 or later (x64)", + "MinimumHardwareReq2": "Internet connection", + "MinimumHardwareReq3": "100 MB free disk space", + "RecommendedHardwareReq1": "Windows 11 (x64)", + "RecommendedHardwareReq2": "Stable broadband connection", + "SearchTerm1": "VPN", + "SearchTerm2": "privacy", + "SearchTerm3": "secure internet", + "SearchTerm4": "encrypt traffic", + "SearchTerm5": "EvilFox", + "SearchTerm6": "proxy client", + "SearchTerm7": "kill switch", + "DesktopScreenshotCaption1": "Home: connect and protection status", + "DesktopScreenshotCaption2": "Server list with flags and ping", + "DesktopScreenshotCaption3": "Settings: theme, language, Kill Switch", + "DesktopScreenshotCaption4": "Usage statistics", +} + + +def main() -> None: + with path.open("r", encoding="utf-8-sig", newline="") as f: + reader = csv.reader(f) + header = next(reader) + rows = [] + for r in reader: + while len(r) < len(header): + r.append("") + rows.append(r) + + # Field, ID, Type, default, en + default_idx = header.index("default") + en_idx = header.index("en") + + for r in rows: + if not r or not r[0]: + continue + field = r[0] + if field in ru: + r[default_idx] = ru[field] + if field in en: + r[en_idx] = en[field] + + with path.open("w", encoding="utf-8-sig", newline="") as f: + w = csv.writer(f, lineterminator="\n") + w.writerow(header) + w.writerows(rows) + + with path.open("r", encoding="utf-8-sig", newline="") as f: + for row in csv.DictReader(f): + if row["Field"] in ( + "Description", + "Title", + "ShortDescription", + "Feature1", + "AdditionalLicenseTerms", + "SearchTerm1", + ): + print( + row["Field"], + "default_len=", + len(row.get("default") or ""), + "en_len=", + len(row.get("en") or ""), + ) + print("wrote", path) + + +if __name__ == "__main__": + main() diff --git a/tools/fillstore/additional_license.go b/tools/fillstore/additional_license.go new file mode 100644 index 0000000..bb355e5 --- /dev/null +++ b/tools/fillstore/additional_license.go @@ -0,0 +1,59 @@ +package main + +import ( + "encoding/csv" + "os" + "path/filepath" +) + +func main() { + path := filepath.Join(`D:\vpn navi`, "store.csv") + f, err := os.Open(path) + if err != nil { + panic(err) + } + r := csv.NewReader(f) + r.FieldsPerRecord = -1 + r.LazyQuotes = true + all, err := r.ReadAll() + f.Close() + if err != nil { + panic(err) + } + h := all[0] + di, ei := 3, 4 + for i, x := range h { + if x == "default" { + di = i + } + if x == "en" { + ei = i + } + } + ruB, _ := os.ReadFile(filepath.Join(`D:\vpn navi`, "dist", "microsoft-store", "AdditionalLicense.ru.txt")) + enB, _ := os.ReadFile(filepath.Join(`D:\vpn navi`, "dist", "microsoft-store", "AdditionalLicense.en.txt")) + ru := string(ruB) + en := string(enB) + for i := 1; i < len(all); i++ { + for len(all[i]) < len(h) { + all[i] = append(all[i], "") + } + if all[i][0] == "AdditionalLicenseTerms" { + all[i][di] = ru + all[i][ei] = en + } + } + out, err := os.Create(path) + if err != nil { + panic(err) + } + _, _ = out.Write([]byte{0xEF, 0xBB, 0xBF}) + w := csv.NewWriter(out) + _ = w.WriteAll(all) + w.Flush() + out.Close() + listing := filepath.Join(`D:\vpn navi`, "dist", "microsoft-store", "listing", "store.csv") + if data, err := os.ReadFile(path); err == nil { + _ = os.WriteFile(listing, data, 0644) + } +} diff --git a/tools/fillstore/copyright.go b/tools/fillstore/copyright.go new file mode 100644 index 0000000..3347416 --- /dev/null +++ b/tools/fillstore/copyright.go @@ -0,0 +1,61 @@ +package main + +import ( + "encoding/csv" + "os" + "path/filepath" +) + +func main() { + path := filepath.Join(`D:\vpn navi`, "store.csv") + f, err := os.Open(path) + if err != nil { + panic(err) + } + r := csv.NewReader(f) + r.FieldsPerRecord = -1 + r.LazyQuotes = true + all, err := r.ReadAll() + f.Close() + if err != nil { + panic(err) + } + h := all[0] + di, ei := 3, 4 + for i, x := range h { + if x == "default" { + di = i + } + if x == "en" { + ei = i + } + } + ru := "© 2026 EvilFox. Все права защищены. EvilFox, логотип EvilFox и связанные знаки являются товарными знаками или зарегистрированными товарными знаками EvilFox. Прочие названия продуктов и компаний, упомянутые в приложении или на странице продукта, могут быть товарными знаками соответствующих владельцев." + en := "© 2026 EvilFox. All rights reserved. EvilFox, the EvilFox logo, and related marks are trademarks or registered trademarks of EvilFox. Other product and company names mentioned in the app or product listing may be trademarks of their respective owners." + for i := 1; i < len(all); i++ { + for len(all[i]) < len(h) { + all[i] = append(all[i], "") + } + if all[i][0] == "CopyrightTrademarkInformation" { + all[i][di] = ru + all[i][ei] = en + } + } + out, err := os.Create(path) + if err != nil { + panic(err) + } + if _, err := out.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil { + panic(err) + } + w := csv.NewWriter(out) + if err := w.WriteAll(all); err != nil { + panic(err) + } + w.Flush() + out.Close() + listing := filepath.Join(`D:\vpn navi`, "dist", "microsoft-store", "listing", "store.csv") + if data, err := os.ReadFile(path); err == nil { + _ = os.WriteFile(listing, data, 0644) + } +} diff --git a/tools/fillstore/logo300.go b/tools/fillstore/logo300.go new file mode 100644 index 0000000..ba69e00 --- /dev/null +++ b/tools/fillstore/logo300.go @@ -0,0 +1,18 @@ +package main +import ("encoding/csv";"os";"path/filepath") +func main() { + path := filepath.Join(`D:\vpn navi`,"store.csv") + f,_ := os.Open(path); r := csv.NewReader(f); r.FieldsPerRecord=-1; r.LazyQuotes=true; all,_ := r.ReadAll(); f.Close() + h := all[0]; di,ei := 3,4 + for i,x := range h { if x=="default"{di=i}; if x=="en"{ei=i} } + for i:=1;i 0 && row[0] == want { + fmt.Printf("%s default=%d en=%d\n", want, len(row[defIdx]), len(row[enIdx])) + } + } + } + fmt.Println("wrote", path) +} diff --git a/tools/fillstore/notes.go b/tools/fillstore/notes.go new file mode 100644 index 0000000..bb8de31 --- /dev/null +++ b/tools/fillstore/notes.go @@ -0,0 +1,63 @@ +package main + +import ( + "encoding/csv" + "os" + "path/filepath" +) + +func main() { + path := filepath.Join(`D:\vpn navi`, "store.csv") + f, err := os.Open(path) + if err != nil { + panic(err) + } + r := csv.NewReader(f) + r.FieldsPerRecord = -1 + r.LazyQuotes = true + all, err := r.ReadAll() + f.Close() + if err != nil { + panic(err) + } + header := all[0] + di, ei := 3, 4 + for i, h := range header { + if h == "default" { + di = i + } + if h == "en" { + ei = i + } + } + ru := "EvilFox 4.2 — удобный и понятный клиент для безопасного доступа в интернет.\n\nЧто нового для пользователей:\n• Современный интерфейс: вкладки Защита, Мои серверы, Настройки, Статистика, Помощь\n• Большая кнопка подключения и понятный статус защиты\n• Светлая тема по умолчанию и переключение на тёмную\n• Языки: русский и английский (RU | EN)\n• Флаги стран у серверов (корректно на Windows)\n• Серверы с одним IP объединяются в одну строку с доступными протоколами\n• Добавление конфигурации по URL\n• Режим прокси и полный режим защиты (TUN)\n• Kill Switch — защита от утечек при обрыве соединения\n• Автовыбор сервера с лучшим пингом\n• Статистика трафика и сессий\n• Политика конфиденциальности и условия использования в разделе Помощь\n• Адаптивное окно под любой экран и масштаб Windows" + en := "EvilFox 4.2 — a clearer, more polished client for private internet access.\n\nWhat's new:\n• Modern UI: Protection, My servers, Settings, Statistics, Help\n• Large connect button and clear protection status\n• Light theme by default, with dark theme toggle\n• Russian and English languages (RU | EN)\n• Country flags for servers (rendered correctly on Windows)\n• Same-IP servers grouped into one row with available protocols\n• Add configuration via URL\n• Proxy mode and full protection mode (TUN)\n• Kill Switch — leak protection if the connection drops\n• Auto-select the lowest-ping server\n• Traffic and session statistics\n• Privacy Policy and Terms of Use in Help\n• Adaptive window sizing for any screen and Windows display scale" + for i := 1; i < len(all); i++ { + for len(all[i]) < len(header) { + all[i] = append(all[i], "") + } + if all[i][0] == "ReleaseNotes" { + all[i][di] = ru + all[i][ei] = en + } + } + out, err := os.Create(path) + if err != nil { + panic(err) + } + out.Write([]byte{0xEF, 0xBB, 0xBF}) + w := csv.NewWriter(out) + if err := w.WriteAll(all); err != nil { + panic(err) + } + w.Flush() + out.Close() + _ = os.MkdirAll(`D:\vpn navi\dist\microsoft-store`, 0755) + _ = os.WriteFile(`D:\vpn navi\dist\microsoft-store\WhatsNew.ru.txt`, []byte(ru+"\n"), 0644) + _ = os.WriteFile(`D:\vpn navi\dist\microsoft-store\WhatsNew.en.txt`, []byte(en+"\n"), 0644) + listing := `D:\vpn navi\dist\microsoft-store\listing\store.csv` + if _, err := os.Stat(filepath.Dir(listing)); err == nil { + data, _ := os.ReadFile(path) + _ = os.WriteFile(listing, data, 0644) + } +} diff --git a/tools/fillstore/shots.go b/tools/fillstore/shots.go new file mode 100644 index 0000000..1341cac --- /dev/null +++ b/tools/fillstore/shots.go @@ -0,0 +1,185 @@ +package main + +import ( + "encoding/csv" + "fmt" + "os" + "path/filepath" + "strings" +) + +func setField(all [][]string, header []string, field, col, value string) { + colIdx := -1 + for i, h := range header { + if h == col { + colIdx = i + break + } + } + if colIdx < 0 { + panic(col) + } + for i := 1; i < len(all); i++ { + for len(all[i]) < len(header) { + all[i] = append(all[i], "") + } + if all[i][0] == field { + all[i][colIdx] = value + return + } + } + panic("missing " + field) +} + +func getField(all [][]string, header []string, field, col string) string { + colIdx := -1 + for i, h := range header { + if h == col { + colIdx = i + break + } + } + for i := 1; i < len(all); i++ { + if len(all[i]) > 0 && all[i][0] == field && colIdx >= 0 && colIdx < len(all[i]) { + return all[i][colIdx] + } + } + return "" +} + +func main() { + root := `D:\vpn navi` + path := filepath.Join(root, "store.csv") + f, err := os.Open(path) + if err != nil { + panic(err) + } + r := csv.NewReader(f) + r.FieldsPerRecord = -1 + r.LazyQuotes = true + all, err := r.ReadAll() + f.Close() + if err != nil { + panic(err) + } + header := all[0] + + // Relative paths for Partner Center: upload folder with store.csv + screen/ + ruShots := []string{ + "screen/1.ru.png", + "screen/2.ru.png", + "screen/3.ru.png", + "screen/4.ru.png", + "screen/5.ru.png", + "screen/6.ru.png", + "screen/12dark.png", + "screen/13dark.png", + "screen/14dark.png", + "screen/15dark.png", + "screen/16dark.png", + "screen/9.png", + } + enShots := []string{ + "screen/7.en.png", + "screen/8.en.png", + "screen/9.png", + "screen/10.en.png", + "screen/11.en.png", + "screen/12dark.png", + "screen/13dark.png", + "screen/14dark.png", + "screen/15dark.png", + "screen/16dark.png", + } + + ruCaptions := [][2]string{ + {"Главный экран: подключение и статус защиты", "Home: connect and protection status"}, + {"Список серверов с флагами и пингом", "Server list with flags and ping"}, + {"Настройки: тема, язык, Kill Switch", "Settings: theme, language, Kill Switch"}, + {"Статистика использования", "Usage statistics"}, + {"Помощь и полезные ссылки", "Help and useful links"}, + {"Добавление конфигурации", "Add configuration"}, + {"Тёмная тема: главный экран", "Dark theme: home"}, + {"Тёмная тема: серверы", "Dark theme: servers"}, + {"Тёмная тема: настройки", "Dark theme: settings"}, + {"Тёмная тема: статистика", "Dark theme: statistics"}, + {"Тёмная тема: помощь", "Dark theme: help"}, + {"Общий вид приложения", "App overview"}, + } + enCaptions := []string{ + "Home: connect and protection status", + "Server list with flags and ping", + "App overview", + "Settings: theme, language, Kill Switch", + "Statistics and help", + "Dark theme: home", + "Dark theme: servers", + "Dark theme: settings", + "Dark theme: statistics", + "Dark theme: help", + } + + for i, p := range ruShots { + setField(all, header, fmt.Sprintf("DesktopScreenshot%d", i+1), "default", p) + } + for i, p := range enShots { + setField(all, header, fmt.Sprintf("DesktopScreenshot%d", i+1), "en", p) + } + // Clear en slots beyond enShots so Partner Center falls back to default for RU-only extras + for i := len(enShots); i < 30; i++ { + setField(all, header, fmt.Sprintf("DesktopScreenshot%d", i+1), "en", "") + } + // Clear default slots beyond ruShots + for i := len(ruShots); i < 30; i++ { + setField(all, header, fmt.Sprintf("DesktopScreenshot%d", i+1), "default", "") + } + + for i, c := range ruCaptions { + field := fmt.Sprintf("DesktopScreenshotCaption%d", i+1) + setField(all, header, field, "default", c[0]) + en := c[1] + if i < len(enCaptions) { + en = enCaptions[i] + } + setField(all, header, field, "en", en) + } + for i := len(ruCaptions); i < 30; i++ { + field := fmt.Sprintf("DesktopScreenshotCaption%d", i+1) + setField(all, header, field, "default", "") + setField(all, header, field, "en", "") + } + + out, err := os.Create(path) + if err != nil { + panic(err) + } + if _, err := out.Write([]byte{0xEF, 0xBB, 0xBF}); err != nil { + panic(err) + } + w := csv.NewWriter(out) + if err := w.WriteAll(all); err != nil { + panic(err) + } + w.Flush() + out.Close() + + for i := 1; i <= 12; i++ { + d := getField(all, header, fmt.Sprintf("DesktopScreenshot%d", i), "default") + e := getField(all, header, fmt.Sprintf("DesktopScreenshot%d", i), "en") + if d == "" && e == "" { + continue + } + fmt.Printf("%d default=%s en=%s\n", i, d, e) + for _, p := range []string{d, e} { + if p == "" { + continue + } + full := filepath.Join(root, filepath.FromSlash(p)) + if _, err := os.Stat(full); err != nil { + fmt.Println(" MISSING", full) + } + } + } + fmt.Println("updated", path, "rows", len(all)) + _ = strings.TrimSpace +} diff --git a/tools/mk300/main.go b/tools/mk300/main.go new file mode 100644 index 0000000..6405750 --- /dev/null +++ b/tools/mk300/main.go @@ -0,0 +1,82 @@ +package main + +import ( + "fmt" + "image" + "image/color" + "image/draw" + "image/png" + "os" + "path/filepath" + + xdraw "golang.org/x/image/draw" +) + +func writePNG(path string, img image.Image) { + _ = os.MkdirAll(filepath.Dir(path), 0755) + out, err := os.Create(path) + if err != nil { + panic(err) + } + defer out.Close() + enc := png.Encoder{CompressionLevel: png.BestCompression} + if err := enc.Encode(out, img); err != nil { + panic(err) + } + fmt.Println("wrote", path) +} + +func main() { + root := `D:\vpn navi` + srcPath := filepath.Join(root, "screen", "1.ru.png") + f, err := os.Open(srcPath) + if err != nil { + panic(err) + } + src, err := png.Decode(f) + f.Close() + if err != nil { + panic(err) + } + sb := src.Bounds() + sw, sh := sb.Dx(), sb.Dy() + side := sw + if sh < side { + side = sh + } + // Center crop to square — no stretch/distortion. + ox := sb.Min.X + (sw-side)/2 + oy := sb.Min.Y + (sh-side)/2 + crop := image.NewRGBA(image.Rect(0, 0, side, side)) + draw.Draw(crop, crop.Bounds(), src, image.Pt(ox, oy), draw.Src) + + dst := image.NewRGBA(image.Rect(0, 0, 300, 300)) + xdraw.CatmullRom.Scale(dst, dst.Bounds(), crop, crop.Bounds(), xdraw.Over, nil) + + writePNG(filepath.Join(root, "screen", "1.ru.300x300.png"), dst) + writePNG(filepath.Join(root, "dist", "microsoft-store", "listing", "screen", "1.ru.300x300.png"), dst) + writePNG(filepath.Join(root, "packaging", "msix", "Assets", "StoreLogo300x300.png"), dst) + + // Padded fit (full frame, letterbox) — no crop. + fit := image.NewRGBA(image.Rect(0, 0, 300, 300)) + draw.Draw(fit, fit.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src) + scale := float64(300) / float64(sw) + if float64(sh)*scale > 300 { + scale = float64(300) / float64(sh) + } + nw := int(float64(sw) * scale) + nh := int(float64(sh) * scale) + if nw < 1 { + nw = 1 + } + if nh < 1 { + nh = 1 + } + resized := image.NewRGBA(image.Rect(0, 0, nw, nh)) + xdraw.CatmullRom.Scale(resized, resized.Bounds(), src, sb, xdraw.Over, nil) + off := image.Pt((300-nw)/2, (300-nh)/2) + draw.Draw(fit, image.Rect(off.X, off.Y, off.X+nw, off.Y+nh), resized, image.Point{}, draw.Over) + writePNG(filepath.Join(root, "screen", "1.ru.300x300.fit.png"), fit) + + fmt.Printf("source %dx%d -> crop %dx%d -> 300x300 (CatmullRom)\n", sw, sh, side, side) +}