api!: remove heartbeat push notifications

Heartbeat notifications are only used on iOS for classic mail servers
but both code and privacy wise (notification server sees IP addresses from those users)
not something we want to support any longer (was discussed with bjoern).
This commit is contained in:
holger krekel
2026-07-24 00:04:14 +02:00
parent 0e4574cd41
commit 461a328915
10 changed files with 18 additions and 119 deletions
+11 -71
View File
@@ -13,7 +13,6 @@ use anyhow::{Context as _, Result};
use base64::Engine as _;
use pgp::crypto::aead::{AeadAlgorithm, ChunkSize};
use pgp::crypto::sym::SymmetricKeyAlgorithm;
use tokio::sync::RwLock;
use crate::context::Context;
use crate::key::DcKey;
@@ -27,13 +26,9 @@ use crate::key::DcKey;
///
/// Each account (context) can then retrieve device token
/// from this structure and give it to the email server.
/// If email server does not support push notifications,
/// account can call `subscribe` method
/// to register device token with the heartbeat
/// notification provider server as a fallback.
#[derive(Debug, Clone, Default)]
pub struct PushSubscriber {
inner: Arc<RwLock<PushSubscriberState>>,
device_token: Arc<parking_lot::RwLock<Option<String>>>,
}
/// The key was generated with
@@ -103,8 +98,8 @@ impl PushSubscriber {
/// Sets device token for Apple Push Notification service
/// or Firebase Cloud Messaging.
pub(crate) async fn set_device_token(&self, token: &str) {
self.inner.write().await.device_token = Some(token.to_string());
pub(crate) fn set_device_token(&self, token: &str) {
*self.device_token.write() = Some(token.to_string());
}
/// Retrieves device token.
@@ -117,59 +112,9 @@ impl PushSubscriber {
///
/// IMAP loop should periodically check if device token is available
/// and send the token to the email server if it supports push notifications.
pub(crate) async fn device_token(&self) -> Option<String> {
self.inner.read().await.device_token.clone()
pub(crate) fn device_token(&self) -> Option<String> {
self.device_token.read().clone()
}
/// Subscribes for heartbeat notifications with previously set device token.
#[cfg(target_os = "ios")]
pub(crate) async fn subscribe(&self, context: &Context) -> Result<()> {
use crate::net::http;
let mut state = self.inner.write().await;
if state.heartbeat_subscribed {
return Ok(());
}
let Some(ref token) = state.device_token else {
return Ok(());
};
info!(context, "Subscribing for heartbeat notifications.");
if http::post_string(
context,
"https://notifications.delta.chat/register",
format!("{{\"token\":\"{token}\"}}"),
)
.await?
{
info!(context, "Subscribed for heartbeat notifications.");
state.heartbeat_subscribed = true;
}
Ok(())
}
/// Placeholder to skip subscribing to heartbeat notifications outside iOS.
#[cfg(not(target_os = "ios"))]
pub(crate) async fn subscribe(&self, _context: &Context) -> Result<()> {
let mut state = self.inner.write().await;
state.heartbeat_subscribed = true;
Ok(())
}
pub(crate) async fn heartbeat_subscribed(&self) -> bool {
self.inner.read().await.heartbeat_subscribed
}
}
#[derive(Debug, Default)]
pub(crate) struct PushSubscriberState {
/// Device token.
device_token: Option<String>,
/// If subscribed to heartbeat push notifications.
heartbeat_subscribed: bool,
}
/// Push notification state
@@ -180,20 +125,15 @@ pub enum NotifyState {
#[default]
NotConnected = 0,
/// Subscribed to heartbeat push notifications.
Heartbeat = 1,
/// Subscribed to push notifications for new messages.
Connected = 2,
}
impl Context {
/// Returns push notification subscriber state.
pub async fn push_state(&self) -> NotifyState {
pub fn push_state(&self) -> NotifyState {
if self.push_subscribed.load(Ordering::Relaxed) {
NotifyState::Connected
} else if self.push_subscriber.heartbeat_subscribed().await {
NotifyState::Heartbeat
} else {
NotifyState::NotConnected
}
@@ -204,13 +144,13 @@ impl Context {
mod tests {
use super::*;
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
async fn test_set_device_token() {
#[test]
fn test_set_device_token() {
let push_subscriber = PushSubscriber::new();
assert_eq!(push_subscriber.device_token().await, None);
assert_eq!(push_subscriber.device_token(), None);
push_subscriber.set_device_token("some-token").await;
let device_token = push_subscriber.device_token().await.unwrap();
push_subscriber.set_device_token("some-token");
let device_token = push_subscriber.device_token().unwrap();
assert_eq!(device_token, "some-token");
}