Обновить
32K+
17
RCQ@rcq

Пользователь

32
Рейтинг
48
Подписчики
Отправить сообщение

Уже объясняли в других ветках, что большая часть команды не владеет языком, а также это экономит уйму времени, как в статье так и в комментариях все написано по делу, вопрос эстетики - это оффтоп.

Предлагаете использовать четки вместо калькулятора? Печально.

С радостью! Но мы живем на донатах :'(

Мы и написали своё, вы точно понимаете что описывается в статье? Мы поставили пометку сложности, если что. Дистрибьютор наш, пуш-сервер наш, сокет наш. UnifiedPush это не реализация, а интерфейс между приложением и тем, кто ему доставляет: четыре системных бродкаста, REGISTERUNREGISTERNEW_ENDPOINTMESSAGE. Свой «более подходящий протокол» был бы ровно тем же foreground-сервисом с тем же сокетом, только несовместимым ни с чем.

Пользователь, у которого уже стоит ntfy или NextPush со своим сервером, остаётся на нём. Мы не обязаны быть единственной точкой, через которую ходят чужие уведомления. Для мессенджера, который продаёт «не доверяйте нам на слово», это не украшение, а свойство.

Сервер остаётся тупым: он делает POST на URL и всё. У нас федерация, сервер открыт и его поднимают у себя. Такому острову не нужно поднимать ещё и пуш-сервер, он может слать в любой UnifiedPush-эндпоинт, какой выберет его владелец.

И самое практичное: в июне это позволило отгрузить пуши без единой строчки пуш-инфраструктуры на нашей стороне, а в июле заменить транспорт целиком, не тронув ни одной строки в коде уведомлений. Именно это в статье и описано: тот же MESSAGE-бродкаст, та же библиотека, тот же обработчик, новый транспорт под ними.

Про размер APK, цифры из сборки v0.75, arm64 около 105 МБ:

libsignal (сквозное шифрование) 70,6 МБ
sing-box для обхода блокировок 41,1 МБ
WebRTC для звонков 11,0 МБ
SQLCipher 5,5 МБ
UnifiedPush connector 165 КБ

Connector это 0,16% сборки. Честный минус назову сам: он тянет tink (3,2 МБ до шринкера), потому что умеет расшифровывать WebPush-полезную нагрузку. Откажись мы от совместимости с WebPush-дистрибьюторами, эту зависимость можно выбросить. Вот это единственная реальная цена вопроса, и она пара мегабайт на фоне ста двадцати, которые занимают шифрование, обход блокировок и звонки.

Так что архитектуру он не переусложнил, он зафиксировал границу, по которой мы потом безболезненно поменяли всё, что за ней.

Про ИИ отвечу коротко, я это уже писал в соседней ветке.
Да, тексты пишутся с ИИ, часть команды по-русски не пишет вообще. Это не тайна и не оправдание, это способ производства (эх, четки и калькуляторы). Проверять имеет смысл не то, кто держал клавиатуру, а сходятся ли факты: два фрагмента из исходников ntfy, RFC 8030, наш код в push/embedded, живой curl https://push.rcq.app/v1/health и sha256 сборок в описании релиза.

По первому пункту вы правы, это дыра в тексте. Слово «туннель» я использую так, будто читатель уже знает, о чём речь, а он не знает. Дописал абзац: внутри приложения живёт sing-box, он поднимает локальный прокси и уводит трафик через наши релеи по VLESS + Reality или Hysteria2, когда прямое соединение до сервера не проходит. Отдельного VPN ставить не надо, системного профиля не появляется. Спасибо, поправил.

По второму. Да, тексты мы пишем с ИИ и скрывать это не вижу смысла. Часть команды по-русски не пишет вообще, материал собирается на английском и переводится, отсюда ровный и слегка стерильный тон, который вы и почувствовали. Инструмент при этом остаётся инструментом: он не делает утверждение верным и не делает его ложным. Спорить сегодня о том, пользоваться им или нет, мне кажется примерно так же содержательно, как спорить о подсветке синтаксиса.

Поэтому единственный честный ответ на «пахнет ИИ» это «проверьте». В статье почти всё проверяемо без нас:

  • оба фрагмента, на которых держится весь разбор, лежат в исходниках ntfy: limitRequestsWithTopic в server/server_middleware.go и проверка на 507 в handlePublishInternal. Откройте и убедитесь сами, что лимит списывается с подписчика, а не с отправителя;

  • обязательность заголовка TTL это RFC 8030, раздел 5.2, читается за минуту;

  • код дистрибьютора, о котором речь, лежит в push/embedded в github.com/rcq-messenger/rcq-android, там же вся история коммитов с датами;

  • пуш-сервер, о котором речь, отвечает прямо сейчас: curl https://push.rcq.app/v1/health;

  • в описании релиза v0.75 лежат sha256 всех APK, те же файлы отдаёт rcq.app, хеши обязаны совпасть. Если не совпадут, это будет гораздо более интересная новость, чем стиль статьи.

Чего проверить нельзя, скажу прямо: цифры отказов взяты из журнала нашего прода, и тут остаётся верить на слово. Всё остальное открыто.

Замыслы удобнее проверять не по стилю комментариев, а по тому, что можно открыть и посмотреть:

  • клиенты под AGPL-3.0, сервер тоже открыт и поднимается у себя, аккаунт не обязан жить у нас;

  • протокол выложен отдельным документом, а не «доверьтесь нам»;

  • при регистрации не спрашивается ни телефон, ни почта, ни имя. Это проверяется за минуту установкой;

  • ни рекламы, ни аналитических SDK в сборке, проект живёт на донатах.

Если конкретное утверждение из статьи вызывает сомнение, назовите его, и я покажу коммит, строчку в чужих исходниках или живой ответ сервера. В таком формате спор имеет смысл, в формате «текст звучит не так» его нет.

Но с «firebase единственная возможность, если приложение смахнуто» я поспорю, тут важная разница, на которую мы сами не сразу посмотрели внимательно.

Смахивание из недавних и force stop это разные вещи. Force stop убивает всё, включая доставку через FCM: система перестаёт будить приложение, пока пользователь сам его не откроет. А обычное смахивание из списка недавних на стоковом Android не убивает foreground-сервис, и постоянное соединение переживает его спокойно. Именно так живёт ntfy, и именно так теперь живём мы: свой сокет в foreground-сервисе, ценой постоянного уведомления в шторке. Firebase выигрывает не в том, что он один умеет пережить смахивание, а в том, что при нём вашему приложению вообще не надо держать соединение и тратить батарею. Отдельная история это вендорские «оптимизаторы», вот они убивают и то, и другое, и с ними не воюет никто.

Дублирование на почту через 10 минут это честное инженерное решение, и оно закрывает ровно ту дыру, которая остаётся: сигнал не дошёл, но информация всё равно доехала. Нам этот путь закрыт по построению, у нас нет почты пользователя, её отсутствие это и есть продукт. Плюс для сквозного шифрования второй канал в открытом виде это шаг назад: содержимое уходит из системы к почтовому провайдеру.

Мы решили ту же задачу иначе: пуш-сервер держит сигнал в кэше 12 часов, а клиент при переподключении просит всё, что пришло после последнего доставленного, и догоняет пропущенное. Уведомление в этом случае приходит поздно, но не теряется. По сути та же гарантия, что у вас, только вторым каналом служит не почта, а само переподключение.

Интересно, как люди реагируют на дубли. Со стороны кажется, что это ровно та функция, которую часть пользователей попросит выключить, а часть не заметит вовсе. У вас есть переключатель?

Точно, и это оказалось хуже, чем я сначала подумал. У организации действительно не было страницы: GitHub рисует её из специального репозитория .github, а его у нас просто не существовало. Человек приходил на организацию и видел список из восьми репозиториев без единого слова о том, что это и с чего начинать.

Сделали: github.com/rcq-messenger теперь открывается описанием проекта, таблицей «хочу сделать это, идти сюда» по всем репозиториям, ссылками на спеку, приватность и условия.

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

По всем трём пунктам справедливо, спасибо. По порядку.

Про «как вы помните»: вы правы, так писать нельзя, читатель видит нас впервые. Поправили начало статьи, ссылка на сайт и на репозитории теперь в первом абзаце, а не в футере.

Про README: полез проверять и нашёл кое-что похуже. В репозиториях клиентов README есть, но у Android он был написан задолго до текущего состояния и сообщал, что это pre-alpha, в Play не выкладывается и кросс-платформенная совместимость ещё допиливается. Всё это давно неправда. Устаревший README хуже отсутствующего, потому что он отвечает на вопрос, и отвечает неверно. Переписали: что это, где скачать, что где лежит в коде, как собрать. Заодно нашли публичный репозиторий со спекой, у которого README действительно не было, добавили. Если вы заходили в какой-то третий репозиторий, скажите в какой, посмотрим и его.

Про Bluetooth и Wi-Fi Direct: это целиком наш косяк в тексте, а не ваше невнимание. Обычная переписка идёт через интернет, как в любом мессенджере. Bluetooth и Wi-Fi Direct это отдельный режим (Радиочат) на случай, когда сети нет совсем: устройства рядом находят друг друга и передают сообщения напрямую. Слайд онбординга был написан так, что читался как описание всего продукта. Текст переписали, в следующей сборке он начинается со слов о том, что обычная переписка идёт через интернет.

Концепт рабочий, и вы, по сути, независимо пришли к той же архитектуре, что и UnifiedPush: приложение получает у дистрибьютора адрес, сервер шлёт туда, дистрибьютор будит устройство. Разница в транспорте (у вас MQTT, у нас HTTP плюс WebSocket) и в том, что у вас адресом служит GUID группы, а у нас топик.

MQTT тут выбран удачнее, чем кажется на первый взгляд. У него дешёвый keepalive и нативный fan-out на нескольких подписчиков, а «раздать одно уведомление на телефон, планшет и часы» это ровно pub/sub. Мы остались на WebSocket только потому, что переиспользовали готовый ntfy, а если бы писали с нуля именно под несколько устройств одного человека, MQTT был бы честным кандидатом.

Три вещи, о которых стоит подумать, если проект выйдет за пределы личного пользования.

Первое. GUID у вас одновременно и адрес, и пароль: кто его узнал, тот и читает ваши уведомления, и подсовывает свои. У нас та же модель для топика, и это осознанный размен, но содержимое до сервера уже зашифровано, сервер видит шифротекст. У вас, если я правильно понял, текст уведомления идёт через сервер как есть, и это единственное место, где стоит навести порядок в первую очередь.

Второе. Дедупликация. Когда на одну группу подписаны телефон и часы, полезно, чтобы прочтение на одном гасило уведомление на другом, иначе часы будут вибрировать тем, что вы уже посмотрели.

Третье. Doze и вендорские «оптимизаторы» убивают долгоживущее соединение с большим удовольствием, и MQTT тут не защищён ничем по сравнению с WebSocket. Держите соединение foreground-сервисом и смотрите на интервал keepalive: слишком короткий ест батарею, слишком длинный даёт минуты задержки после выхода из сна.

Встречный вопрос, самому интересно: как вы снимаете уведомления с исходных телефонов, через NotificationListenerService? И что делаете с пачками, когда мессенджер присылает десяток уведомлений подряд, схлопываете или льёте как есть?

Спасибо, но тут смешаны два уровня, разведу.

Про IP вы правы, и в статье это прямым текстом: IP горят одинаково, relay у нас расходник, вся ставка на быструю ротацию адресов. Reality никогда и не обещал спасти IP, он про другое.

Про протокол XOR и Reality не равны. XOR-обфускация держится ровно до тех пор, пока цензор не смотрит активно. Как только он включает активный пробинг (сам стучится на ваш сервер) или ставит DPI по сигнатуре, XOR и классические VPN-протоколы палятся, и режут не один ваш IP, а весь класс трафика разом, по сигнатуре. Именно так в РФ и Иране массово выпиливают OpenVPN, WireGuard, IKEv2 и простые обфускаторы. Reality на пробинг отвечает чужим легитимным сайтом, сигнатуры протокола нет.

Отсюда вся разница, и она не в красоте, а в цене для цензора. XOR умирает от одного обновления сигнатуры сразу на всех серверах. Reality заставляет банить по одному IP, по мере обнаружения, вручную и дорого. «И там и там в итоге IP-бан» верно по форме, но скорость и стоимость отличаются на порядок. В этом весь смысл, а не в трюкачестве.

И да, конкретно эта статья вообще не про обход, она про метаданные: чтобы один relay по дороге не видел ваш IP и адрес назначения сразу. Одиночный XOR-VPN эту задачу не решает в принципе, там ваш единственный сервер видит всё.

Про слои согласен, плотно. Суть в одной фразе: два relay вместо одного, вход залипает, выход крутится, и если что-то падает, всё откатывается на однохоп. Остальное детали.

Про сбои и нагрузку отвечу конкретно.

Сбои. Однохоп это пол. Умер выход, urltest перевыбирает живую выходную цепочку. Умер вход (подтверждённая блокировка, около минуты), клиент ротирует вход и пересобирает транспорт. Живых relay в пуле меньше двух или онион выключен, клиент сам падает на однохоп, тот самый, что работал и до онион. Худший случай по связности это не «всё легло», а «онион выключился, работаем как раньше». Обрыв входа посреди сессии рвёт всю цепочку (выход идёт внутри входа), клиент переподключается, это секунды переустановки, не потеря данных.

Нагрузка. Онион удваивает стоимость на активную цепочку: вход несёт внутри себя весь выходной туннель, и Reality с vision считаются на двух хопах вместо одного. Для мессенджера ок, трафик маленький и это в основном простаивающий WebSocket плюс короткие сообщения. Для видео я бы по умолчанию не включал. Стационарная добавка к задержке это один лишний хоп RTT, а +0.7s из статьи это разовая установка соединения, не на каждый пакет.

Мир меняется и мы тоже. Думаете такое бы нейронка не сказала в ответ на ваш комментарий? Или мы ответили не по делу, что пуши тут вообще никак не связаны со статьей и сутью проекта?

Спасибо, вопросы правильные, и большинство из них честнее считать не решёнными, а постоянной борьбой. По пунктам.

Магазины и верификация -согласен, и именно поэтому мы на магазины не опираемся. На Android основная раздача это прямой APK с сайта плюс встроенный апдейтер, не Play. Верификация разработчиков ужесточается, да, но прямую установку и открытый код пережить отзыв из стора проще, чем приложению, которое живёт только в магазине. iOS тут реально слабое место: Apple контролирует раздачу целиком и по жалобе выпилит, крыть нечем. Единственное смягчение, iOS-клиент открыт (AGPL, на GitHub), его можно собрать и поставить мимо App Store, плюс в ЕС появились альтернативные сторы. Идеально это не закрывает (появится нужда - откатимся к эре Jailbreak'а, почему нет?).

Блокировки и запрет -тут работает сама архитектура, а не один обходной костыль. Смысл в том, что инфраструктура размазана по пользователям. Остров это просто почтовый ящик, его поднимает кто угодно у себя, и данные не лежат в одной точке, которую можно изъять. Транспорт это релеи, и их задумано много -дешёвые, одноразовые, поднимаемые самими пользователями, "сегодня здесь, завтра там", как гидра. Рубишь одну голову, остальные живут, единой точки входа, которую гасят одним махом, нет. Поверх этого идёт onion-маршрутизация через несколько релеев, чтобы ни один из них не видел разом и кто ты, и куда идёшь, и чтобы прятался сам факт обращения к конкретному острову.

Честно про статус -часть уже работает (наши релеи, обфускация, подписанный конфиг с ротацией без обновления приложения, self-host островов), а массовый пользовательский рой релеев и onion это то, к чему мы идём по этапам, не всё уже включено. И есть по-настоящему трудный кусок, не решённый ни у кого -первичный бутстрап, когда заблокировано всё известное (та же проблема, что у Tor с мостами, серебряной пули нет). А если само использование объявят вне закона и начнут смотреть телефоны, это уже не инженерная задача -улики убрать можно (нет телефона, сжигаемые аккаунты, decoy-PIN, приложение не кричит "запрещёнка", итд), но закон софтом не отменить.

Аудитория, проблема Jabber -cамый сильный и самый честный пункт, и он сложнее любой криптографии. XMPP технически имел всё и умер на сетевом эффекте и UX. Мы не делаем ставку "построим, и придут". У нас есть клин, которого у джаббера не было -люди под реальной цензурой, которым обход нужен прямо сейчас, это совсем другое давление к адопшену. И есть небольшая, но настоящая аудитория, под тысячу зарегистрированных, пришедшая именно из-за этого, а не вопреки UX. Урок джаббера учли буквально -одно опрятное приложение, а не двадцать клиентов на выбор, шифрование по умолчанию, а не "настройте OMEMO". Победим ли мы проблему аудитории вообще, честно, открытый вопрос, тут можно лечь как все. Но клин реальный, и первая тяга есть.

Монетизация -само приложение бесплатное, и навсегда. Платят не люди, а организации. Логика тут стандартная для open-source -код открыт, остров можно поднять самому бесплатно, но большинству это не нужно или некогда, и за удобство и инфраструктуру платят охотно. Что конкретно -бизнесу (редакции, юристы, фонды, команды, которым нельзя в Telegram или WhatsApp) готовая закрытая сеть островов в их контуре под ключ, с настройкой и поддержкой, плюс управляемый хостинг "свой остров в один клик" для тех, кто не хочет возиться с VPS. Тем, кому защита реально нужна и кто платить не может (журналисты, активисты), всё бесплатно по заявке. На рекламе и данных не зарабатываем принципиально, это убило бы смысл. Что коммерция и бескомпромиссная приватность не противоположности, уже показал SimpleX, мы той же дорогой -продаём удобство и инфраструктуру, а не пользователя.

Замечание по делу, пуши действительно главная точка централизации, и на iOS вы абсолютно правы -фоновые уведомления это только APNs, ни один сторонний сервер этого не обойдёт, это ограничение ОС, а не приложения. Лоббировать Apple с Google нам не по силам, не будем притворяться.

Пара уточнений по тому, что реально можно. Это не "всё или ничего" -свой остров подключает собственный ключ APNs, и тогда пуш идёт остров -> Apple напрямую, мимо нашего центра, то есть даже пуш не централизован через нас (в self-host это настраивается). На Android мы FCM сегодня вообще не используем, доставка идёт по живому сокету пока приложение работает, а полноценный фоновый будильник пока отложен. Его, кстати, на Android можно сделать без Google, постоянным foreground-сервисом, как у Briar и FOSS-XMPP клиентов, ценой батареи. На iOS без APNs надёжного фона нет, тут крыть нечем.

И главное по сути -централизация пуша ортогональна(!) тому, что мы децентрализуем. Пуш это всего лишь "пинг, проверь ящик". Аккаунт, переписка и ключи лежат на островах, а не у Apple с Google. Отвалится пуш-канал, вы потеряете не сеть и не данные, а только мгновенность уведомления, сообщения дойдут при следующем открытии. Мы защищаемся от того, что центр выключат, как это случилось с ICQ, а не строим идеальную децентрализацию каждого байта. Пуши важная, но решаемая в рабочем порядке деталь, а не сердце системы.

Нет, это другой уровень. Reticulum это сетевой стек -адресация, маршрутизация и шифрование поверх любой среды, хоть LoRa и радио, вообще без интернета. Мессенджеры (LXMF, Sideband) строят уже поверх него. Мы сеть с нуля не делаем -у нас обычный интернет и модель почтовых ящиков. Остров это тупой ящик с очередью, клиент сам кладёт запечатанный конверт в ящик(и) получателя и сам их опрашивает (читайте статью внимательнее, пожалуйста). По духу это ближе к email или Nostr, чем к Reticulum. Общее есть -идентичность это ключ, центрального авторитета нет, всё шифровано. Ближе всего к миру Reticulum у нас офлайн-режим, радиочат по Bluetooth и Wi-Fi Direct без серверов и интернета, но он намного проще и только локальный, не маршрутизируемый стек. Reticulum отличная штука, просто решает другую задачу.

Рады, что зашло. Только держите план Б наготове: это гонка, и «идеально» сегодня вполне может поплыть завтра, когда подтянут правила. Мы поэтому и закладываемся на UDP плюс обфускацию и на ротацию точек, чтобы при первом шевелении можно было переехать без боли. И спасибо, что отписались по результату, такие репорты полезнее любых наших логов.

Согласен, Reticulum отличная штука, и мы её не игнорируем: это действительно полноценный криптографический сетевой стек, транспортно-агностичный, и как mesh он на голову выше нашего Radio. Тут спорить не с чем.

Но мы решаем другую задачу и на другом слое. Reticulum это СЕТЬ: как пакеты находят друг друга через любую среду. RCQ это МЕССЕНДЖЕР как продукт: кроссплатформенный (iOS, Android, веб / в будущем Desktop-версии), libsignal с forward secrecy, sealed sender, пуши, добавление контакта по короткому номеру, встроенный обход блокировок. Центр тяжести у нас не mesh, а «обычный приватный мессенджер для не-гика», а Radio это офлайн-fallback на случай «интернета нет вообще, люди рядом», сознательно минимальный (ноль настройки, без доп-железа).

Если задача это именно транспортно-агностичная сеть планетарного-галактического-вселенного масштаба, Reticulum правильный инструмент, и переизобретать его мы не пытаемся :)

Если задача «чтобы друзья на айфонах переписывались приватно, с пушами, чтобы при блокировках работало, а при отключении сети остался хоть локальный режим», то это другой продукт. Reticulum и его мобильные клиенты пока для тех, кто готов разбираться, мы целимся в тех, кто разбираться не хочет.

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

У RCQ это два конца одного спектра. Один конец это ровно ваш сценарий «настроил один раз»: сервер RCQ можно поднять локально, хоть на старом ноуте или Raspberry Pi в доме, и соседи цепляются к нему по обычному WiFi, без выхода в интернет вообще. Получается приватный «остров» на дом или район, со всем шифрованием и без связи наружу. Другой конец это Radio, когда даже точки доступа нет: телефоны напрямую, ноль инфраструктуры, ценой радиуса.

А вот «связать это всё в единое децентрализованное, чтобы не играть в хакера» это честно самая сложная часть, и красиво её пока никто не закрыл. Мы скорее даём набор кубиков (локальный сервер плюс direct-радио), чем обещаем один волшебный mesh. Но вектор вы описали верно: спрос на локалки при первом же серьёзном рубильнике вырастет очень быстро.

Справедливо, и да: если человек стоит рядом, проще сказать вслух. Radio не про это. Он про координацию ГРУППЫ без интернета, когда вы не все в одной точке.

Во-первых, радиус это не «несколько метров». Несколько метров это BLE-маячок для обнаружения, а сами сообщения идут по Wi-Fi Direct, до сотни метров в прямой видимости. Это этаж здания, двор, небольшая площадь, вагон. Голосом через толпу или сквозь стены вы туда не докричитесь, а текст в комнату доходит всем разом.

Во-вторых, текст делает то, что голос не умеет: тихо (в толпе не хочется орать чувствительное вслух), сразу всем участникам и со структурой (координаты, ссылка, фото, закреплённый план).

Про USB-C приёмопередатчик с антенной на километры: это ровно тот путь, о котором выше писали с Meshtastic. Отдельная LoRa-железка на sub-GHz реально берёт километры, ценой отдельного устройства, низкого битрейта и текста без медиа. Направление интересное, но это другой продукт: ты носишь с собой донгл. Radio сознательно про обратный размен, ноль доп-железа и настройки, телефон уже в кармане, ценой радиуса. Разные инструменты под разные сценарии.

Информация

В рейтинге
259-й
Откуда
Тель-Авив, Тель-Авив, Израиль
Дата рождения
Зарегистрирован
Активность

Специализация

Фулстек разработчик, Инженер по обеспечению качества
Ведущий
SQL
Git
PostgreSQL
Python
Английский язык
Docker
FastAPI
Celery
Redis