Skip to content

Commit 4198ed1

Browse files
committed
fix: store device token in IMAP METADATA on each connection
APNS tokens never expire unless the user uninstalls the application. Because of this in most cases the token remains valid forever and chatmail server never removes the token even if it is unencrypted or the user has removed Delta Chat profile from the device but not the whole application. We want to modify chatmail servers to remember the last time the token was stored and remove them after some time. Before we do this, we need to modify the client to store the device token each time so the server knows which tokens are used and can update their timestamps.
1 parent 6f5620d commit 4198ed1

File tree

3 files changed

+52
-23
lines changed

3 files changed

+52
-23
lines changed

src/config.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,13 @@ pub enum Config {
455455
/// If it has not changed, we do not store
456456
/// the device token again.
457457
DeviceToken,
458+
459+
/// Device token encrypted with OpenPGP.
460+
///
461+
/// We store encrypted token next to `device_token`
462+
/// to avoid encrypting it differently and
463+
/// storing the same token multiple times on the server.
464+
EncryptedDeviceToken,
458465
}
459466

460467
impl Config {

src/context.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1778,6 +1778,7 @@ mod tests {
17781778
"key_id",
17791779
"webxdc_integration",
17801780
"device_token",
1781+
"encrypted_device_token",
17811782
];
17821783
let t = TestContext::new().await;
17831784
let info = t.get_info().await.unwrap();

src/imap.rs

Lines changed: 44 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,15 +1589,15 @@ impl Session {
15891589
};
15901590

15911591
if self.can_metadata() && self.can_push() {
1592-
let device_token_changed =
1593-
context.get_config(Config::DeviceToken).await?.as_ref() != Some(&device_token);
1592+
let old_encrypted_device_token =
1593+
context.get_config(Config::EncryptedDeviceToken).await?;
15941594

1595-
if device_token_changed {
1596-
let folder = context
1597-
.get_config(Config::ConfiguredInboxFolder)
1598-
.await?
1599-
.context("INBOX is not configured")?;
1595+
// Whether we need to update encrypted device token.
1596+
let device_token_changed = old_encrypted_device_token.is_none()
1597+
|| context.get_config(Config::DeviceToken).await?.as_ref() != Some(&device_token);
16001598

1599+
let new_encrypted_device_token;
1600+
if device_token_changed {
16011601
let encrypted_device_token = encrypt_device_token(&device_token)
16021602
.context("Failed to encrypt device token")?;
16031603

@@ -1606,22 +1606,23 @@ impl Session {
16061606
// <https://www.rfc-editor.org/rfc/rfc7888>.
16071607
let encrypted_device_token_len = encrypted_device_token.len();
16081608

1609-
if encrypted_device_token_len <= 4096 {
1610-
self.run_command_and_check_ok(&format_setmetadata(
1611-
&folder,
1612-
&encrypted_device_token,
1613-
))
1614-
.await
1615-
.context("SETMETADATA command failed")?;
1609+
// Store device token saved on the server
1610+
// to prevent storing duplicate tokens.
1611+
// The server cannot deduplicate on its own
1612+
// because encryption gives a different
1613+
// result each time.
1614+
context
1615+
.set_config_internal(Config::DeviceToken, Some(&device_token))
1616+
.await?;
1617+
context
1618+
.set_config_internal(
1619+
Config::EncryptedDeviceToken,
1620+
Some(&encrypted_device_token),
1621+
)
1622+
.await?;
16161623

1617-
// Store device token saved on the server
1618-
// to prevent storing duplicate tokens.
1619-
// The server cannot deduplicate on its own
1620-
// because encryption gives a different
1621-
// result each time.
1622-
context
1623-
.set_config_internal(Config::DeviceToken, Some(&device_token))
1624-
.await?;
1624+
if encrypted_device_token_len <= 4096 {
1625+
new_encrypted_device_token = Some(encrypted_device_token);
16251626
} else {
16261627
// If Apple or Google (FCM) gives us a very large token,
16271628
// do not even try to give it to IMAP servers.
@@ -1633,9 +1634,29 @@ impl Session {
16331634
// of any length, but there is no reason for tokens
16341635
// to be that large even after OpenPGP encryption.
16351636
warn!(context, "Device token is too long for LITERAL-, ignoring.");
1637+
new_encrypted_device_token = None;
16361638
}
1639+
} else {
1640+
new_encrypted_device_token = old_encrypted_device_token;
1641+
}
1642+
1643+
// Store new encrypted device token on the server
1644+
// even if it is the same as the old one.
1645+
if let Some(encrypted_device_token) = new_encrypted_device_token {
1646+
let folder = context
1647+
.get_config(Config::ConfiguredInboxFolder)
1648+
.await?
1649+
.context("INBOX is not configured")?;
1650+
1651+
self.run_command_and_check_ok(&format_setmetadata(
1652+
&folder,
1653+
&encrypted_device_token,
1654+
))
1655+
.await
1656+
.context("SETMETADATA command failed")?;
1657+
1658+
context.push_subscribed.store(true, Ordering::Relaxed);
16371659
}
1638-
context.push_subscribed.store(true, Ordering::Relaxed);
16391660
} else if !context.push_subscriber.heartbeat_subscribed().await {
16401661
let context = context.clone();
16411662
// Subscribe for heartbeat notifications.

0 commit comments

Comments
 (0)