Habr•August 1, 2026•🇷🇺Translated from Russian

UnifiedPush and Public ntfy.sh: Why Push Notifications Fail on Android Without Google Services

Developers of a messenger operating in a region where Google services are unavailable faced the familiar problem of replacing FCM. The standard open-source answer is UnifiedPush, which splits delivery among the app, the application server, and a distributor that maintains a connection to a push server. The team implemented this approach in June using the popular ntfy distributor paired with the public ntfy.sh instance.

One and a half months later, user complaints about missing notifications prompted an examination of production logs. Over a 36-hour window the server recorded 100 successful deliveries against 507 responses with code 507 (Insufficient Storage), 351 with code 429 (Too Many Requests), and 69 with code 400 (Bad Request). Failures had been present since the feature launch; they simply went unnoticed on always-connected test devices.

The 507 errors stem from a deliberate design choice in ntfy: when visitor-subscriber rate limiting is enabled, a UnifiedPush topic must have an active subscriber before any message can be published. The official ntfy client from Google Play uses Firebase for instant delivery and only maintains a persistent WebSocket when the F-Droid build is used. In regions without Google services the client never registers a subscriber, so every server POST receives an immediate 507 and the message is discarded rather than queued.

Code 429 responses arise because rate-limit buckets are attached to the subscriber’s IP address, not the sender. Mobile carriers place hundreds of users behind a single NAT address; a single group message can exhaust the shared 60-request bucket and cause subsequent deliveries to fail for unrelated users sharing the same IP. Many endpoints alternated between 429 and 507 within a single day, producing the intermittent behavior reported by users.

Endpoints pointing at updates.push.services.mozilla.com returned 400 because the server implements the WebPush specification (RFC 8030), which requires a TTL header. The original implementation omitted the header, assuming ntfy behavior would apply to every endpoint. The team now sends a minimal WebPush-compliant request containing Content-Type, TTL, and Urgency headers for all destinations.

Purchasing a paid ntfy.sh plan does not resolve the problem. Both the subscriber-existence check and the rate-limit logic operate on the recipient side; elevating the sender’s quota has no effect. The developers therefore deployed a self-hosted ntfy instance with visitor-subscriber-rate-limiting disabled, a generous burst limit of 200 requests, and an exempt host list that includes the backend address.

Even a private push server leaves users with the burden of installing and configuring a separate distributor application. To remove this friction the team implemented an embedded distributor directly inside the messenger. The component consists of a BroadcastReceiver that answers REGISTER requests and a foreground service maintaining a WebSocket to the private server. The WebSocket reconnect logic includes a “since” parameter so cached messages are delivered after network interruptions.

Two device-only bugs surfaced during live testing. Re-registration generates a fresh topic, yet the service continued listening on the old topic until an explicit comparison was added. Closing an obsolete socket triggered an onClosed handler that scheduled a duplicate reconnect, resulting in duplicate notifications; a generation counter now prevents the second connection from processing events.

Finally, the push WebSocket must traverse the same anti-censorship tunnel used by the rest of the application. Because OkHttp caches the route at client creation time, the service recreates the HTTP client whenever the tunnel state changes, ensuring notifications remain available even when the primary domain is blocked.

Related articles

Habr•Privacy & Surveillance

Russia Freezes Entire Hosting Networks to Block VPN Traffic, Investigation Finds

An independent test of 435 endpoints across 154 hosting providers revealed that Russian internet providers are throttling connections to entire autonomous systems rather than individual IP addresses. Networks belonging to Hetzner, OVH, DigitalOcean, M247 and HostPapa are frozen after roughly 25 TCP packets, causing downloads to stall at around 16 KB while UDP-based WireGuard tunnels remain unaffected. The blocking is applied uniformly by multiple Russian operators including Beeline, MTS and home broadband providers, indicating a centrally distributed rule from Roskomnadzor via the TSPU filtering system. Smaller providers that rent IP space from the affected autonomous systems are also impacted, regardless of their own brand or location. Cloudflare-hosted resources currently pass the test, but the list of blocked networks has remained stable since mid-2025. The researcher published an open-source script that allows anyone to reproduce the measurements in under a minute.

Habr•Privacy & Surveillance

macOS Builds Undocumented Personal Knowledge Graph Since Version 13, Inferring Family Ties via On-Device ML

Since macOS 13 in 2022, two daemons named knowledgeconstructiond and intelligenceplatformd have been constructing a comprehensive personal knowledge graph on every Mac. The system aggregates data from Contacts, Calendar, Photos, Messages, Mail, Family Sharing, Health emergency contacts, Screen Time, and behavioral signals to map users, their relationships, locations, and activities. Results are stored in ~/Library/IntelligencePlatform as SQLite databases, including graph.db containing 181 entity classes and 278 predicates. Two CoreML models, EntityTagging_Family.mlmodelc and EntityTagging_FamilyAndFriends.mlmodelc, use 144 behavioral and photographic features to classify family and friend relationships with daily updates in entityTagging.db. An embedded LLM and embedding models further label unnamed faces and infer relationships from message text when Apple Intelligence is enabled. The graph remains queryable locally and is designed to feed personalized AI features while operating entirely on-device under Full Disk Access protections.

Habr•Privacy & Surveillance

Breaking the Ice: Claude AI Maps TSPU Deep Packet Inspection and Censorship Bypass Methods in Russia

An analysis conducted by Claude AI examines the current state of Russia's TSPU censorship infrastructure as of November 2026, based on real-world testing from the Rostelecom network. The report details how DPI equipment blocks traffic by IP addresses, SNI inspection, protocol signatures, and active probing, with specific freezes occurring after approximately 16 KB on many foreign hosting providers. Multiple circumvention techniques are evaluated, including VLESS combined with Reality and XTLS Vision, cascaded connections through Russian entry nodes, and local tools such as zapret and GoodbyeDPI. The study highlights that large providers including Hetzner, OVH, Vultr, Scaleway, and AWS are heavily restricted, while alternatives like Leaseweb and certain academic networks remain functional. Recommendations emphasize using self-hosted domains with valid certificates, Reality-based masking, and regular IP testing to maintain connectivity. The article stresses that all information is presented strictly for research purposes.

AntiMalware•Privacy & Surveillance

Apple to Scan iCloud Photos and Files Shared via Public Links Starting with iOS 27.3

Apple announced that it will begin scanning content stored in iCloud when users share files or photos through public links. The feature activates with the release of iOS 27.3, iPadOS 27.3, macOS 27.3, and visionOS 27.3. Any file made accessible to anyone with the link will now be checked by Apple for malicious materials. This change effectively means that sharing via public links grants Apple visibility into the shared content for security purposes. The move aims to detect harmful files before they reach other users through shared links.