nks-talk-notify
Vlastní brána pro push oznámení z Nextcloud Talk do telefonů s Androidem a iOS přes FCM a APNs. Vznikla pro OwnTalk, obsah zpráv nepřečte.
Kdo vyvíjí vlastního klienta pro Nextcloud Talk, narazí dřív nebo později na upozornění. Aplikace funguje, zprávy chodí, dokud je otevřená, ale jakmile ji systém uspí, telefon zmlkne. Na iOS se to stane během několika sekund. Zavřenou aplikaci probudí jen Apple Push Notification service (APNs) nebo Firebase Cloud Messaging (FCM) a k oběma službám potřebuje odesílatel klíče, které patří právě té aplikaci. nks-talk-notify je brána, která tyhle klíče drží na vlastním serveru a doručuje přes ně oznámení z Nextcloudu. Vznikla pro OwnTalk, klienta Nextcloud Talk pro Android, iOS a počítače, ale použije ji každý klient, který mluví protokolem push-v2.
Proč nestačí proxy od Nextcloudu
Nextcloud sám s Applem ani Googlem nemluví. Aplikace notifications každé oznámení zašifruje pro konkrétní zařízení, podepíše klíčem uživatele a pošle na adresu push proxy, kterou si klient zvolil při registraci. Teprve proxy drží přístupové klíče k APNs a FCM.
Výchozí proxy push-notifications.nextcloud.com provozuje Nextcloud GmbH a posílá s vlastním klíčem APNs a vlastním projektem ve Firebase. Apple i Google doručí zprávu jen odesílateli, jehož klíče patří přijímající aplikaci, takže tahle proxy dosáhne jen na oficiální aplikace. Aplikace třetí strany s vlastním identifikátorem a vlastním projektem ve Firebase potřebuje proxy vlastní.
Co brána provozovateli dává
Oznámení pro vlastní aplikaci na obou platformách
Na iOS posílá upozornění s příznakem mutable-content, takže je rozšíření aplikace před zobrazením dešifruje. Příchozí hovor doručí přes PushKit, pokud zařízení zaregistrovalo token VoIP; jinak přijde jako běžné upozornění. Tichou zprávou umí upozornění zase stáhnout. Na Android jde čistě datová zpráva s prioritou převzatou z Nextcloudu, takže systém šifrovaný text nikdy sám neukáže.
Jedna brána pro víc serverů
Brána přijme oznámení od každého Nextcloudu, jehož klíč předplatného zná. Klíčů může být v konfiguraci víc, takže jednu instanci sdílí několik serverů, třeba firemní a rodinný Nextcloud nebo servery několika zákazníků.
Obsah zpráv zůstává nečitelný
Text oznámení je zašifrovaný klíčem, který existuje jen v telefonu. Brána ho předává dál, ale přečíst ho nemůže.
Jeden proces a jeden soubor
Je to jeden proces v Pythonu 3.12 s knihovnami httpx a cryptography a jedním souborem SQLite. Obraz Dockeru běží pod neprivilegovaným uživatelem s kontrolou stavu, GET /health vrátí počet registrovaných zařízení. Výměna klíče APNs nebo servisního účtu Firebase znamená restart brány; klienti nic měnit nemusí.
Jak zpráva projde
- Aplikace se zaregistruje u Nextcloudu a jako adresu proxy uvede veřejnou adresu brány. Nextcloud dostane jen otisk SHA-512 push tokenu, ne token samotný.
- Skutečný token pošle aplikace bráně na
POST /devicesspolu s podpisem, který vydal Nextcloud. Brána podpis ověří a uloží si veřejný klíč uživatele. - Při novém oznámení pošle Nextcloud na
POST /notificationstext zašifrovaný klíčem zařízení a podepsaný klíčem uživatele. Brána ověří podpis proti uloženému klíči a předá zprávu APNs nebo FCM. - Rozšíření aplikace v telefonu text dešifruje a teprve pak ho ukáže. Když dešifrování selže, uživatel uvidí obecný titulek „Nextcloud Talk“.
Zařízení, které brána ohlásí Nextcloudu jako neznámé, Nextcloud smaže ze své evidence. Brána ho proto tak označí jen tehdy, když ho nikdy neviděla, nebo když Apple či Google ohlásí, že token zanikl.
Kde se brána hodí
- Vývojář vlastního klienta Nextcloud Talk, který má vlastní účet Apple Developer a projekt ve Firebase a potřebuje doručovat upozornění do zavřené aplikace.
- Správce firemního Nextcloudu, jehož lidé používají OwnTalk: bránu povolí příkazem
occa vloží klíč předplatného do její konfigurace, upozornění pak chodí přes server, který má pod kontrolou.
Co brána vidí a ukládá
Do souboru SQLite ukládá k zařízení jeho identifikátor, veřejný klíč uživatele, push token a jeho otisk, poskytovatele, prostředí APNs, případný token PushKit a časy registrace. Identifikátor zařízení je otisk SHA-512, který Nextcloud spočítá z účtu a relace; vstupy brána nevidí. Jména uživatelů, adresy serverů, IP adresy ani metadata zpráv neukládá. Při přenosu vidí, které zařízení dostává oznámení a kdy, IP adresu serveru Nextcloud a registrujících se telefonů a velikost šifrovaného textu; totéž vidí Apple a Google u všeho, co přes ně jde.
Do logu nikdy nejde dotazovací řetězec a logování klientů APNs a FCM je ztlumené, protože adresa APNs obsahuje token zařízení. Databáze vzniká s právy 0600, protože tokeny v ní leží v čitelné podobě.
Ochrana proti zneužití
Požadavky od Nextcloudu se ověřují dvakrát: klíčem předplatného a u každé položky podpisem RSA, který umí vyrobit jen Nextcloud. První klíč zaregistrovaný k zařízení se zamkne, takže registrace pod cizím klíčem skončí kódem 403. Po úspěšném odeslání si brána pět minut pamatuje podpis zprávy a opakované doručení zahodí. Tělo požadavku má strop 1 MiB, dávka 100 položek, registrace 20 požadavků za minutu z jedné adresy a oznámení 120. Za hodinu ohlásí Nextcloudu jako neznámá nejvýš 10 zařízení, aby chybná konfigurace nebo ztracená databáze nesmazala na straně Nextcloudu všechny registrace naráz.
Stav a omezení
Protokol je ověřený proti zdrojovému kódu aplikace notifications a proti běžícímu Nextcloudu 34; starší verze vyzkoušené nejsou. Jediným vyzkoušeným klientem je zatím OwnTalk. V repozitáři je 121 testů, které pracují s vygenerovanými klíči a falešnými odpověďmi poskytovatelů, takže Apple ani Google nekontaktují.
Brána je jeden proces s jedním souborem a horizontálně se neškáluje. Frontu pro opakované odeslání nemá: zprávu, kterou APNs nebo FCM odmítnou, ohlásí Nextcloudu jako neúspěšnou a Nextcloud ji znovu neposílá. Kdo zná identifikátor zařízení dřív než jeho majitel, mohl by ho zaregistrovat první a skutečné zařízení zablokovat; k tomu jsou ale potřeba hodnoty z nitra serveru Nextcloud. Formát push-v2 nemá jednorázovou hodnotu ani časové razítko, takže pětiminutová paměť podpisů opakování omezí, ale úplně nevyloučí; stejně je na tom i proxy Nextcloud GmbH.
Server může jako subscription_aware_server uvést jen jednu proxy. Jakmile uvede tuhle bránu, přestane posílat svůj podnikový klíč předplatného na proxy Nextcloud GmbH, což pocítí velké instalace, které zároveň používají oficiální aplikace.
Jak začít
Před bránu patří reverzní proxy s platným certifikátem, protože Nextcloud nepřijme jinou adresu než https://. Pro iOS je potřeba účet Apple Developer, klíč APNs a identifikátor aplikace, pro Android projekt ve Firebase a klíč servisního účtu. Stačí jeden z poskytovatelů.
cp .env.example .env
$EDITOR .env # key ids, topic, host paths of the key files
mkdir -p data && chown 10001:10001 data # the container runs as uid 10001
docker compose up -d --build
curl http://127.0.0.1:8080/health
Na straně Nextcloudu stačí aplikace notifications, která je součástí instalace, a funkční cron. Správce nastaví adresu brány:
occ config:app:set notifications subscription_aware_server --value="https://push.example.com"
Klíč předplatného, který Nextcloud při prvním odeslání vygeneruje, přečte příkazem occ config:app:get notifications push_subscription_key a vloží ho do konfigurace brány.
Zdrojový kód
Kód je na GitHubu v repozitáři nks-hub/nks-talk-notify pod licencí GPL-3.0-or-later, stejnou jako OwnTalk. Vydané verze ani hotový obraz Dockeru repozitář nemá, obraz se sestaví z přiloženého Dockerfile.