Реалити-шоу «Беременна в 16» изначально было создано в США. Оно выходило на канале MTV с 2009 по 2014 год. kinopoisk.ru ru.ruwiki.ru gorbilet.ru Позже аналогичное шоу появилось в Украине в 2012 году.
а то, женщина, мать трёх детей, живу в Ростове БУГАГА 》》
товарищ уже не посылает на банку! вообще не рыпается ответить! до этого трёхэтажным матом крыл, а тут притих!
Вопрос, почему?
потому что ты еблан. не понял еще? хуй из жопы вынь, мож тогда прочухаешь свободу мысли
слушай, хотел спросить у тебя, ты же в этом разбираешься, как я вижу, МАХ не очень хороший мессенджер, да? ГЫ
Ты настолько упорот что еще не понял?
чего там по ящику после "беременна в 16" идёт в Ростове? Телемарафон «Единые новости» ? или «От пацанки до панянки»
# MaxLight: что программа делает сверх того, о чём написано
**Аудит исходного кода — приватность и права пользователя**
| | | |---|---| | Репозиторий | `ComradeBingo/MaxLight` | | Коммит | `411a87d` (v2.0.4), ветка `main` | | Объём | 5 916 строк кода (.cs / .xaml / .js), 31 файл | | Дата аудита | 02.09.2026 | | Ревизия | 2 — все находки первой редакции перепроверены, добавлено 13 новых |
Обёртка web.max.ru на WPF + WebView2. Скрытой передачи данных наружу нет. Зато часть заявленных защит в коде отсутствует, два действия с системой пользователя выполняются без его согласия, а канал обновлений сломан для части установленной базы.
**Итог в четырёх числах:**
- **0** — скрытых сетевых адресов, телеметрии и сторонних SDK. Наружу уходят только `web.max.ru`, `api.github.com` и GitHub Releases. - **5** — заявленных функций, которых в коде нет или которые никогда не вызываются. - **2** — действия с системой без согласия: автозапуск и завершение чужих процессов Edge. - **1** — сломанный канал доставки исправлений: у пользователей версий 2.1.0–2.3.1 обновления не придут никогда.
---
## 1. Недокументированное вмешательство в систему
Действия, которые программа выполняет за пределами своего окна и о которых нет ни слова ни в README, ни в интерфейсе.
### #1 · КРИТИЧНО — При выходе принудительно убивает процессы Edge и WebView2, включая чужие
При закрытии приложение перебирает *все* процессы в системе и вызывает `Kill()` для каждого, чьё имя содержит `msedge`, `WebView2` или `MicrosoftEdge` и который стартовал позже MaxLight. Проверки на родительский процесс нет — `StartTime > currentProcess.StartTime` это не проверка родства.
На практике под удар попадают: открытый после MaxLight браузер Microsoft Edge со всеми вкладками, а также любое приложение на движке WebView2 — новый Outlook, Teams, панели Office, множество сторонних программ. **Убийство без сохранения — это потеря несохранённых данных пользователя в чужих приложениях.**
Код продублирован в двух местах и срабатывает по трём сценариям: выход через трей, закрытие окна и — что не очевидно — **смена настроек прокси**, где приложение само себя перезапускает через `Process.Start` + `Environment.Exit(0)`, попутно вызвав `TrayManager.Dispose()`. То есть пользователь, поменявший порт прокси, закрывает себе Edge. При штатном выходе оба блока отрабатывают друг за другом, то есть система обходится дважды.
### #2 · КРИТИЧНО — Автозапуск Windows включается сам и включается заново после выключения
При открытии окна настроек метод `LoadAutoStartState()` читает ключ `HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run`, и если ключа нет — **сам записывает его** и ставит галочку. Пользователь просто открыл настройки; согласия никто не спрашивал.
Хуже то, что это неустранимо штатными средствами: снятая галочка удаляет ключ, но при следующем открытии настроек ключ снова отсутствует — и программа снова прописывает себя в автозагрузку. Настройка, которую пользователь выключил, молча возвращается. Про автозапуск README не упоминает вообще.
Дополнительно: ветка «ключ есть» тоже безусловно выставляет `IsChecked = true`, так что состояние «выключено» этот экран показать не может в принципе. Запись в реестр при этом идёт по двум путям сразу — из XAML-обработчика `ChkAutoStart_CheckedChanged` и из подписки `AutoStartToggled` в `MainWindow`, причём вторая вычисляет новое значение инверсией текущего состояния реестра, а не состояния галочки.
### #3 · ВЫСОКИЙ — Запрос аватарки уходит мимо прокси: деанонимизация при включённом прокси
Настройка прокси применяется только к WebView2 (аргумент `--proxy-server`). Картинку аватара для всплывающего уведомления скачивает отдельный `HttpClient` без какой-либо прокси-конфигурации, то есть напрямую с реального IP-адреса пользователя.
Получается сценарий, обратный ожиданиям: пользователь включил прокси именно чтобы скрыть адрес, но **каждое входящее сообщение порождает прямой запрос к серверу мессенджера с настоящего IP**. URL берётся из DOM страницы (`img.src`) и никак не ограничен доменом: абсолютный адрес уходит в запрос как есть, к домену `web.max.ru` дописывается только относительный путь.
Побочно: `HttpClient` создаётся заново на каждое уведомление и тут же уничтожается — классический источник исчерпания сокетов при потоке сообщений.
### #4 · ВЫСОКИЙ — Любая внешняя ссылка запускается через ShellExecute без проверки схемы
Всё, что не относится к `max.ru` и `oneme.ru`, передаётся в `Process.Start(UseShellExecute = true)` как есть. Список разрешённых схем отсутствует, подтверждения нет. Ссылка из сообщения со схемой вроде `file:`, `ms-msdt:`, `search-ms:` или любым зарегистрированным в системе обработчиком запускается одним кликом.
Обычный браузер в такой ситуации показывает диалог «разрешить открытие приложения». Здесь этот барьер снят, а содержимое ссылок приходит от собеседника.
### #5 · СРЕДНИЙ — Выход из аккаунта молча стирает PIN-код
Кнопка «Выйти из аккаунта» вызывает `ClearAuthData()`, где вместе с токеном обнуляется и `PinHash` — с комментарием «на всякий случай пин-код тоже сносим». Диалог подтверждения об этом не сообщает, README тоже.
Пользователь, который выходил из аккаунта чтобы перелогиниться, после этого остаётся без установленной им защиты и не получает об этом уведомления.
### #6 · СРЕДНИЙ — При каждом старте запускается `dotnet` из неквалифицированного пути
Перед показом окна приложение вызывает `Process.Start` с `FileName = "dotnet"` и `UseShellExecute = false`. Полный путь не указан, поэтому Windows разрешает имя по стандартному порядку поиска: **сначала каталог самого приложения, затем текущий рабочий каталог**, и только потом системные папки и `PATH`. Подложенный в любую из этих папок `dotnet.exe` выполняется при каждом запуске MaxLight. Каталог установки (`%LocalAppData%\MaxLight\current\`) доступен на запись самому пользователю, а рабочим каталогом становится та папка, из которой открыли ярлык или файл.
Сама проверка при этом бессмысленна: код, который её выполняет, уже исполняется на .NET 10 — иначе он бы не запустился. Зато она даёт ложноотрицательный результат, если рантайм установлен, а CLI `dotnet` в `PATH` отсутствует: приложение откажется стартовать и предложит скачать то, что уже стоит.
> `Program.cs:68–86` (проверка и диалог) · `Program.cs:176–200` (IsDotNetRuntimeInstalled)
---
## 2. Защиты и функции, которых в коде нет
Пункты из README и окна «О программе», которые не подтверждаются исходным кодом. Это не «реализовано слабо» — это отсутствует либо никогда не выполняется.
### #7 · КРИТИЧНО — Блокировка трекеров не работает: обработчик написан, но не подключён
Метод `OnWebResourceRequested`, который должен отдавать 204 на запросы с трекерными подстроками, **нигде не подписан на событие** `CoreWebView2.WebResourceRequested`, и `AddWebResourceRequestedFilter` не вызывается ни разу. Без фильтра событие не возбуждается в принципе. Массив `_trackingKeywords` и весь метод — мёртвый код.
Это центральное заявленное преимущество продукта: в сравнительной таблице README стоит «MAX — 8 трекеров слежения / MaxLight — трекеры заблокированы», в окне «О программе» — пункт «🛡️ Блокировка трекеров». **Фактически весь трафик страницы, включая аналитику, проходит без изменений.** Вдобавок список ключевых слов в README (`apptracer`, `sdk-api`, `crashtoken`…) не совпадает со списком в коде — документация описывает несуществующую версию фильтра.
> `WebView2Handler.cs:24–30` (список) · `WebView2Handler.cs:374–375` (обработчик) · подписки нет во всём проекте (проверено `grep -rn "WebResourceRequested"` — единственное вхождение это само объявление)
### #8 · КРИТИЧНО — Раздела «Защита от XSS» не существует: ни CSP, ни санитизации
README отводит отдельный раздел под «внедрение специальных скриптов защиты в WebView2», «санитизацию ввода» и «CSP-заголовки». Поиск по всем файлам репозитория (`.cs`, `.js`, `.xaml`, `.md`) по подстрокам `csp`, `content-security`, `sanitiz`, `xss`, `escapehtml` даёт **ноль совпадений**.
Единственная функция экранирования в проекте — `EscapeJsString` для подстановки токена в JS-строку, к защите отображаемого контента отношения не имеющая.
> `README.md` §«Безопасность» · `grep -rni` по .cs/.js/.xaml/.md — 0 результатов
### #9 · ВЫСОКИЙ — Блокировка рекламного баннера не работает: класс никогда не создаётся
Удаление баннера (`.infobar…`) живёт в классе `PageModifier`. Выражения `new PageModifier(...)` в проекте нет: поле `_pageModifier` объявлено и трижды проверяется на `null`, но никогда не инициализируется. Все 321 строка файла и обе зарегистрированные модификации DOM не выполняются.
Вместе с классом мертва и вторая его половина — `InterceptClicksViaJavaScriptAsync`, перехват кликов по ссылкам и подмена `window.open`. То есть отключён не только баннер, но и единственный слой, который отсекал схемы `javascript:` до передачи ссылки наружу (см. #4).
Пункт «🚫 Блокировка рекламного баннера» указан в окне «О программе» как действующая функция.
### #10 · СРЕДНИЙ — «Счётчик непрочитанных сообщений» считает не непрочитанные сообщения
JS-парсер честно вычисляет количество непрочитанных, суммируя числа в бейджах, и шлёт результат в C# сообщением `unread_count`. В C# это сообщение **явно проигнорировано** — `case "unread_count": // Игнорируем`. Функция `sendUnreadCount()` в скрипте, вместе с логикой пересчёта бейджей в `MutationObserver`, — мёртвый код.
Реально в трее и на иконке в панели задач показывается внутренний счётчик `_unreadCount`, который увеличивается на единицу при каждом *показанном всплывающем окне* и обнуляется при активации главного окна. То есть это счётчик пропущенных уведомлений, а не непрочитанных сообщений: он не видит сообщения, пришедшие при активном окне, сбрасывается от простого клика по окну и режется собственным антиспамом (не чаще одного уведомления в 2 секунды — и в JS, и в C#).
README дополнительно обещает «указание количества непрочитанных сообщений при наведении курсора на трей» — подсказка трея содержит только строку «Max Light — есть новые сообщения», без числа.
### #11 · СРЕДНИЙ — Режим «инкогнито» держится не на инкогнито, а на временной папке
Аргумент `--incognito` передаётся в `AdditionalBrowserArguments`, но WebView2 такой режим не поддерживает и аргумент игнорирует. Приватность в реальности обеспечивает другое: профиль каждый раз кладётся в новую папку с GUID-именем.
Важнее расхождение в жизненном цикле этой папки. README: «временная папка для работы удаляется автоматически после завершения работы». В коде удаление (`SafeCleanupOldSessions`) выполняется **при следующем запуске**. До него профиль со всей историей сессии лежит в папке установки; если приложение больше не запускать или удалить — данные остаются на диске навсегда.
> `WebView2Handler.cs:53–56, 243–253, 255–261`
---
## 3. Хранение данных, токен и PIN
Механизм описан в README верно по смыслу — приложение перехватывает токен авторизации и переживает его между сессиями. Неверны детали, от которых зависит оценка риска.
### #12 · ВЫСОКИЙ — Данные лежат не в реестре, а в JSON-файле рядом с программой
README: «все чувствительные данные (токен, deviceId, PIN-код) хранятся в зашифрованном виде в реестре Windows». Фактически всё это — `config.json` в каталоге на уровень выше исполняемого файла (для установленной версии это `%LocalAppData%\MaxLight\config.json`), в portable-режиме — прямо в папке программы. В реестр пишется только ключ автозапуска.
Разница существенна: файл виден в проводнике, копируется вместе с папкой portable-версии, попадает в бэкапы и в синхронизацию облачных дисков — а пользователь по описанию ожидает защищённое системное хранилище.
### #13 · ВЫСОКИЙ — При сбое шифрования токен молча записывается открытым текстом
Обёртка над DPAPI построена так: `catch { return plainText; }`. Если `ProtectedData.Protect` по любой причине не сработает (перемещаемый профиль, повреждённый ключ, нестандартная конфигурация), **токен авторизации уходит в config.json в чистом виде**, а приложение продолжает работать как ни в чём не бывало — ни исключения, ни записи, ни предупреждения пользователю.
Расшифровка симметрично возвращает шифротекст при ошибке, так что состояние «шифрование отвалилось» внешне неотличимо от нормального. Побочный эффект: обработчик ошибок расшифровки в `LoadConfig`, который должен был обнулять испорченный токен, недостижим — `DecryptString` исключение не пробрасывает, а возвращает строку, и в `localStorage` уезжает шифротекст вместо токена.
### #14 · СРЕДНИЙ — «AES-256» — это DPAPI с публичной энтропией из открытого кода
README и окно «О программе» обещают «зашифрованное хранилище (AES-256)». Под этим — `ProtectedData.Protect` с областью `CurrentUser` и энтропией `"MaxLight_Secure_Store_2024"`, захардкоженной в открытом исходном коде.
Это штатная и разумная для десктопа схема, но её граница защиты стоит ровно там, где граница учётной записи Windows: **любой процесс, запущенный от имени того же пользователя, расшифровывает токен пятью строками кода**, зная энтропию из GitHub. От вредоносного ПО в профиле пользователя это не защищает — а формулировка «AES-256» создаёт впечатление обратного.
### #15 · ВЫСОКИЙ — PIN-код не защищает данные и снимается блокнотом
PIN проверяется только внутри интерфейса; токен лежит в том же `config.json` и от PIN никак не зависит. Достаточно удалить из файла поле `PinHash` — и приложение стартует с сохранённой сессией без единого вопроса.
Сам хэш — `SHA-256` без соли и без растяжения, PIN ограничен 4–6 цифрами: полный перебор всего пространства занимает секунды. Кроме того README расходится с кодом сразу трижды: заявлено «3 попытки» — в коде 5; «блокировка» — на деле просто закрытие приложения, после перезапуска снова 5 попыток; «проверка при каждом запуске» — **PIN спрашивается только если сохранён токен**, иначе приложение молча предлагает задать новый.
### #16 · СРЕДНИЙ — PIN переустанавливается без знания текущего, если нет сохранённого токена
Диалог смены PIN в настройках сделан правильно: он требует ввести текущий PIN перед заменой. Но ветка старта в обход него: если сохранённого токена нет, `MainWindow_Loaded` **безусловно** показывает окно установки PIN и по кнопке «Сохранить» вызывает `SavePinCode`, перезаписывая существующий `PinHash` без всякой проверки.
Сценарий достижим: пользователь задал PIN при первом запуске и не завершил авторизацию, либо вышел из аккаунта (см. #5). Практический ущерб невелик именно потому, что PIN и так ничего не защищает (#15), но заявленная модель «PIN меняется только по предъявлении старого» ломается.
> `MainWindow.xaml.cs:106–128` · сравнить с `PinSettingsDialog.xaml.cs:22–33`
### #17 · НИЗКИЙ — Последние 4 символа токена пишутся в конфиг открытым текстом
Помимо `EncryptedToken` в `config.json` сохраняется поле `TokenPreview` — «...» плюс последние четыре символа токена в чистом виде. Функциональной нагрузки в текущем коде у поля нет: нигде, кроме собственного пересохранения, оно не читается. Это чистая утечка фрагмента секрета в незашифрованную часть файла.
> `ConfigManager.cs:182–184, 519`
---
## 4. Обновления как канал доверия
### #18 · ВЫСОКИЙ — Версия откачена назад: часть пользователей больше не получит ни одного обновления
История версий в `MaxLight.csproj` идёт так: `2.0.0 → 2.1.0 → 2.3.0 → 2.3.1` (все 21.08.2026), затем коммит «v2.0.0: переход на NET10» от 24.08 **сбрасывает `AssemblyVersion` обратно на 2.0.0**, и дальше нумерация идёт заново — 2.0.1, 2.0.2, 2.0.3, 2.0.4.
Velopack сравнивает версии семантически и предлагает только более новую. Для всех, кто установил сборку из линии 2.1.0–2.3.1, актуальный релиз 2.0.4 — это версия *ниже* установленной. **Обновление им не будет предложено никогда**, а кнопка «Проверить обновления» в настройках честно ответит «Обновлений нет». Единственный выход — ручная переустановка, о необходимости которой пользователь не узнает.
Это не косметическая проблема: канал доставки исправлений для части установленной базы закрыт молча и бессрочно.
### #19 · СРЕДНИЙ — Фоновое автообновление без подписи кода: тихий канал выполнения кода
Velopack проверяет GitHub Releases через 5 секунд после старта и далее каждые 6 часов, скачивает и применяет обновление в фоне с перезапуском. README подаёт это так: «целостность файлов (SHA1) при обновлении контролируется Velopack».
SHA1 берётся из того же `releases.json`, что и сам пакет, и подтверждает лишь отсутствие повреждений при скачивании — но не подлинность автора. Подписи кода в проекте нет. **Кто получит контроль над репозиторием или аккаунтом сопровождающего, тихо выполнит произвольный код на машинах всех пользователей при ближайшем запуске.** Это свойство архитектуры, а не ошибка реализации, — но пользователь, читающий про «контроль целостности», понимает написанное иначе.
Отдельно: README §5 утверждает, что парсер «зашит в .exe файл, чтобы избежать внесения изменений злоумышленниками». Скрипт действительно упакован как `EmbeddedResource`, но исполняемый файл не подписан и его целостность ничем не проверяется — встраивание ресурса не является защитой от модификации.
### #20 · СРЕДНИЙ — Утерян принятый фикс атомарного сохранения конфига
24.07.2026 в проект был принят PR #4 (`2120351`, слит в `d2a1e49`): запись `config.json` через временный файл + `File.rерlасе`, резервная копия `.bak`, сохранение битого файла как `.corrupt-<дата>` и межпроцессный мьютекс вокруг load/save. Причина в описании коммита названа прямо: «File.WriteAllText не атомарен, при гонке старого и нового процесса во время рестарта Velopack файл обрезается, а LoadConfig на битом JSON молча возвращал пустой конфиг (терялись Auth/Pin/настройки)».
В коммите `c7b64a6` «Полная замена на версию 2.0.0» история была переписана, и весь этот код исчез. **В текущей версии снова `File.WriteAllText` без временного файла, без резервной копии и без межпроцессной блокировки**, а `LoadConfig` на исключении по-прежнему тихо подставляет пустой `ConfigData`. Тот самый баг «после обновления слетела авторизация» вернулся вместе с сохранением конфига в каталог, который Velopack перезаписывает при рестарте.
> `ConfigManager.cs:210` (запись) · `ConfigManager.cs:152–157` (сброс на пустой конфиг) · утраченная реализация: `git show 2120351`
### #21 · НИЗКИЙ — Лицензии MIT в актуальной ветке нет
README заявляет «открытый исходный код, MIT лицензия» и делает из этого пункт сравнения с официальным клиентом. Файла `LICENSE` в ветке `main` нет, в ветке `master` тоже, заголовков лицензии в исходниках нет.
Узнаёт о родительской папке — а именно там маркер и оказывается в раскладке Velopack — весь проект, **кроме `ConfigManager`**. В результате в такой сборке приложение считает себя portable в интерфейсе и в логике автозапуска, но `ConfigManager` считает режим обычным. Практическое следствие: `GetDownloadPath()` возвращает `%UserProfile%\Downloads` вместо папки `Downloads` внутри портативного каталога — то есть «портативная» версия оставляет файлы в профиле пользователя, чего от неё как раз и не ждут.
### #23 · СРЕДНИЙ — Второй экземпляр стирает рабочий профиль первого
Мьютекс единственного экземпляра в portable-режиме не ставится сознательно. При этом `SafeCleanupOldSessions()` при старте удаляет из `WebView2Sessions` **все** подпапки, кроме собственной. Запуск второй копии портативной версии уничтожает живой профиль WebView2 уже работающей первой — вместе с её сессией.
Тот же мьютекс обходится любым аргументом командной строки, содержащим подстроку `--apply` (проверка на признак обновления Velopack сделана через `Contains`, без разбора аргументов), — то есть и в обычной установленной версии.
### #24 · НИЗКИЙ — В portable-режиме проверка обновлений всегда молчит
`UpdateChecker` принимает флаг `isPortable` в конструктор, сохраняет в поле `_isPortable` и **больше нигде его не использует**. Фоновый и ручной опрос запускаются одинаково, но `UpdateManager` в неустановленной сборке выбрасывает исключение, которое перехватывается и уходит в `Debug.WriteLine`. Наружу это выглядит как «Обновлений нет» — независимо от того, вышла новая версия или нет. Диалог обновления при этом умеет дописывать пометку «(Portable)», то есть сценарий предполагался, но не доведён.
## 6. Мёртвый код и расхождения внутри самого проекта
### #25 · НИЗКИЙ — Защитные проверки в JS-парсере не срабатывают никогда
`messageInterceptor.js` в семи местах проверяет `window._tokenParserActive` и `window._maxLightTokenInterceptorInstalled`, чтобы не разбирать чаты, пока активен перехватчик токена. Ни одного из этих флагов не существует: C#-скрипт перехвата выставляет только `window._maxLightTokenInterceptorOriginalSetItem`. Все семь проверок всегда ложны, парсер работает и во время перехвата токена. Признак расхождения версий скрипта и хоста.
### #26 · НИЗКИЙ — Перехватчик токена восстанавливается после каждой перезагрузки страницы
`StopTokenParser()` возвращает оригинальный `localStorage.setItem` и сбрасывает `_tokenParserActive`, но сам скрипт остаётся зарегистрированным через `AddScriptToExecuteOnDocumentCreatedAsync` и заново подменяет `setItem` при любой навигации или перезагрузке. Снять его повторно уже нельзя — флаг сброшен, и `StopTokenParser` выходит по первой строке. Токен перезахватывается и пересохраняется при каждой перезагрузке страницы.
> `WebView2Handler.cs:70, 265–270`
### #27 · НИЗКИЙ — `VelopackApp.Build().Run()` вызывается последним, а не первым
Точка входа Velopack, обрабатывающая хуки установки, удаления и первого запуска, вызвана после инициализации `ConfigManager`, после мьютекса и после диалога о .NET-рантайме. Документированное требование Velopack — вызывать её как можно раньше в `Main`. Побочный эффект уже наблюдаем в коде: `ConfigManager.EnsureConfigExists()` стоит первой строкой `Main` и создаёт `config.json` в том числе при запусках, которые Velopack делает для своих хуков.
> `Program.cs:21, 89`
### #28 · НИЗКИЙ — `README.md` внесён в `.gitignore`
Начиная с коммита `349e157` (v1.1.8) файл `README.md` перечислен в `.gitignore`. Документ уцелел только потому, что уже был под версионным контролем и правило на отслеживаемые файлы не действует. Побочный эффект: в свежем клоне правка README не показывается как изменение до явного `git add -f`, а новый файл с этим именем создать «как обычно» не получится. Единственный документ, по которому проект оценивают снаружи, помечен как игнорируемый.
> `.gitignore:11`
---
## 7. Заявлено и фактически
Сводка расхождений README и окна «О программе» с кодом на коммите `411a87d`.
| Заявлено | Фактически в коде | | |---|---|---| | Трекеры заблокированы (8 трекеров) | Обработчик не подключён, фильтр не установлен — фильтрации нет | **Нет** | | Защита от XSS, санитизация ввода, CSP-заголовки | В коде отсутствует полностью | **Нет** | | Блокировка рекламного баннера | `PageModifier` никогда не создаётся | **Нет** | | Счётчик непрочитанных сообщений | Сообщение `unread_count` игнорируется; считаются показанные уведомления | **Нет** | | Число непрочитанных в подсказке трея | Подсказка без числа: «есть новые сообщения» | **Нет** | | Хранение в реестре Windows | `config.json` на диске рядом с программой | Иначе | | AES-256 через Windows Crypto API | DPAPI CurrentUser, энтропия опубликована в исходниках | Иначе | | PIN: 3 попытки до блокировки | 5 попыток; «блокировка» = закрытие, при перезапуске счётчик сбрасывается | Иначе | | PIN проверяется при каждом запуске | Только при наличии сохранённого токена | Иначе | | Временная папка удаляется после завершения работы | Удаляется при следующем запуске; иначе остаётся на диске | Иначе | | Целостность обновлений контролируется SHA1 | SHA1 из того же манифеста; подписи кода нет | Слабее | | Парсер «зашит в .exe, чтобы избежать изменений» | Ресурс внутри неподписанного exe; целостность не проверяется | Слабее | | Обновление при каждом запуске | Для версий 2.1.0–2.3.1 обновлений не будет никогда (версия откачена) | **Сломано** | | MIT лицензия | Файла `LICENSE` ни в одной ветке нет (есть в утерянном первом коммите) | **Нет** | | Требуется .NET Framework 4.7.2 | `net10.0-windows`; без .NET Runtime 10 приложение не стартует | Устарело | | Автозапуск — не упомянут | Включается сам при открытии настроек и возвращается после выключения | **Скрыто** | | Завершение чужих процессов — не упомянуто | `Kill()` всех msedge / WebView2 при выходе и при смене прокси | **Скрыто** |
---
## 8. Что проверено и претензий не вызывает
Отдельно стоит сказать, чего в коде *нет* — это главный положительный итог аудита.
- **Скрытых сетевых адресов нет.** Полный перечень исходящих соединений, подтверждённый сплошным поиском по URL в исходниках: `web.max.ru` (сам мессенджер и аватарки), `api.github.com` и GitHub Releases (обновления и описание версии), `dotnet.microsoft.com` (открывается в браузере, если нет рантайма), `github.com/ComradeBingo/MaxLight` (кнопка в окне «О программе»). Ни аналитики, ни телеметрии, ни сторонних SDK. Сетевых клиентов в проекте ровно два `HttpClient`, оба перечислены выше. - **Парсер сообщений ничего не отправляет наружу.** `messageInterceptor.js` читает из DOM имя, текст и аватар только для локального всплывающего уведомления и передаёт их исключительно в C#-хост через `chrome.webview.postMessage`. Никаких fetch/XHR/WebSocket в скрипте нет. - **Перехват токена документирован.** Подмена `localStorage.setItem` для получения `__oneme_auth` прямо описана в README (пункт 3) как механизм «авторизация один раз» — это заявленное поведение, а не скрытая функция. Восстановление токена в страницу выполнено с двойным экранированием и собирает корректный JSON — ошибки внедрения здесь нет. - **История git чистая по секретам.** Ключей, паролей и собранных бинарников самого приложения в коммитах нет; крупные объекты в истории — NuGet-пакеты старой .NET Framework-версии проекта (`packages/`, до 21 МБ на объект). История переписывалась минимум трижды: в репозитории четыре независимых корневых коммита. - **Отладочные логи не пишутся на диск.** `Debug.WriteLine` печатает префикс токена и содержимое конфига, но в Release-сборке эти вызовы вырезаются компилятором. Риск существует только для отладочных сборок. - **Реестр используется минимально** — единственный ключ, к которому обращается программа, это `Run` для автозапуска (см. #2). - **Зависимостей всего три**, все от известных поставщиков и с фиксированными версиями: `Hardcodet.NotifyIcon.Wpf` 2.0.1, `Microsoft.Web.WebView2` 1.0.4129.50, `Velopack` 1.2.0.
---
## 9. Что чинить в первую очередь
1. Убрать массовое завершение процессов Edge/WebView2 — закрывать только собственный экземпляр WebView2 через `Dispose` хоста (#1). 2. Не включать автозапуск самостоятельно: состояние читать из реестра как есть, а запись выполнять только по клику пользователя, и одним путём, а не двумя (#2). 3. Поднять версию выше `2.3.1` (например, `2.4.0`) и выпустить релиз — иначе потерянная часть пользователей не получит ни одно из перечисленных исправлений (#18). 4. Вернуть атомарное сохранение конфига из принятого PR #4 — `git show 2120351` (#20). 5. Привести README и окно «О программе» в соответствие с кодом — либо подключить фильтр трекеров и `PageModifier`, либо убрать эти пункты из описания (#7, #8, #9, #10). 6. Подписать `HttpClient` для аватарок теми же настройками прокси, что и WebView2, либо грузить картинку внутри страницы (#3). 7. Добавить белый список схем (`http`, `https`, `mailto`) перед `Process.Start` (#4). 8. Указать полный путь к `dotnet.exe` или убрать проверку рантайма целиком — она всё равно выполняется уже внутри работающего .NET 10 (#6). 9. Убрать `catch { return plainText; }` — при сбое DPAPI отказывать в сохранении токена и сообщать пользователю (#13). 10. Исправить описание PIN, не удалять PIN при выходе из аккаунта, требовать текущий PIN при замене и не обещать защиту данных, которую PIN не даёт (#5, #15, #16). 11. Свести четыре реализации определения portable-режима в одну (#22). 12. Вернуть файл `LICENSE`: `git show dbec7d4:LICENSE > LICENSE` (#21).
---
## Границы аудита
Аудит выполнен по исходному коду коммита `411a87d` ветки `main`, статически; дополнительно просмотрена вся доступная история git (49 коммитов, 4 корневых). Опубликованные в разделе Releases бинарники не проверялись и не сопоставлялись с исходниками — воспроизводимой сборки в проекте нет, поэтому соответствие исполняемого файла этому коду на веру не принимается и не подтверждается. Динамического анализа (запуск, трассировка трафика) не проводилось. Ссылки на строки соответствуют коммиту `411a87d` и в ревизии 2 сверены заново.
Это сообщение отредактировал mpishi - 2 сен 2026 в 02:16
### #1 · КРИТИЧНО — При выходе принудительно убивает процессы Edge и WebView2, включая чужие
Ну то есть оно ещё и под Винду. А нам втирают про незасирание "системы" )))
пофиг. ты завершил работу, а папка с __oneme_auth осталась. ну json без всякой фигни. иными словами, достаточно спереть папку и можно что-то вымутить. но надо разбираться предметно.
самое главное, что ты не можешь проверить сборку .exe ;) типа, если автора ломанули со всеми 2FA, то .exe на github можно выложить новый.
это всё нейрослоп и надо разбираться предметно.
подозрительно, что автор не чекнул эту потеху нейронкой.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии. Авторизуйтесь, пожалуйста, или зарегистрируйтесь, если не зарегистрированы.
10 Пользователей читают эту тему (1 Гостей и 3 Скрытых Пользователей)