From 479af38ca16da9eac7d3d7302669ba1acdb8e083 Mon Sep 17 00:00:00 2001 From: link2xt Date: Wed, 20 Nov 2024 19:36:22 +0000 Subject: [PATCH] feat: encrypt notification tokens --- src/accounts.rs | 2 +- src/push.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/src/accounts.rs b/src/accounts.rs index 425139d71b..637684b206 100644 --- a/src/accounts.rs +++ b/src/accounts.rs @@ -372,7 +372,7 @@ impl Accounts { /// Sets notification token for Apple Push Notification service. pub async fn set_push_device_token(&self, token: &str) -> Result<()> { - self.push_subscriber.set_device_token(token).await; + self.push_subscriber.set_device_token(token).await?; Ok(()) } } diff --git a/src/push.rs b/src/push.rs index fbdf7ff5ad..32c961e229 100644 --- a/src/push.rs +++ b/src/push.rs @@ -1,10 +1,13 @@ use std::sync::atomic::Ordering; use std::sync::Arc; -use anyhow::Result; +use anyhow::{Context as _, Result}; +use pgp::crypto::sym::SymmetricKeyAlgorithm; +use rand::thread_rng; use tokio::sync::RwLock; use crate::context::Context; +use crate::key::DcKey; /// Manages subscription to Apple Push Notification services. /// @@ -24,20 +27,56 @@ pub struct PushSubscriber { inner: Arc>, } +/// The key was generated with +/// `rsop generate-key --profile rfc9580`. +const NOTIFIERS_PUBLIC_KEY: &str = "-----BEGIN PGP PUBLIC KEY BLOCK----- + +xjMEZz4rkBYJKwYBBAHaRw8BAQdAux0BQpM9vB6Gz4spfQRa20i7ZnxA3aBeDkck +Z+EwNPHNGG5vdGlmaWNhdGlvbnNAZGVsdGEuY2hhdMKPBBAWCAA3AhkBBQJnPiuQ +AhsDCAsJCAcKDQwLBRUKCQgLAhYCAScWIQRCLgVwMzvy1Tei7Aw17KwQK2f7BAAK +CRA17KwQK2f7BNs9AQDCWE31mxPPb43nke0uLTFa7cP/YDyw0ACTTt0RU1v8HgEA +00kjlk/KDRgdkUAnrKc2S4PYUkxtGU+kLH4qrPGJtg7OOARnPiuQEgorBgEEAZdV +AQUBAQdAV8nr+yHIGVsBe/FAsFb8tyQKZ/PkwsInY4BT2k0PcQ8DAQgHwngEGBYI +ACAFAmc+K5ACGwwWIQRCLgVwMzvy1Tei7Aw17KwQK2f7BAAKCRA17KwQK2f7BLfE +AP45ntrZXh3A52AC/15774HwdD3mK0AVPsyFEFm2xfqXzAD/WMBshtUGYBgaVCOQ +rgpBlliZYe3XokCcc/qmVzeiIwo= +=NICb +-----END PGP PUBLIC KEY BLOCK-----"; + impl PushSubscriber { /// Creates new push notification subscriber. pub(crate) fn new() -> Self { Default::default() } - /// Sets device token for Apple Push Notification service. - pub(crate) async fn set_device_token(&self, token: &str) { - self.inner.write().await.device_token = Some(token.to_string()); + /// Sets device token for Apple Push Notification service + /// or Firebase Cloud Messaging. + /// + /// The token is encrypted with OpenPGP. + pub(crate) async fn set_device_token(&self, token: &str) -> Result<()> { + let public_key = pgp::composed::SignedPublicKey::from_asc(&NOTIFIERS_PUBLIC_KEY)?.0; + let encryption_subkey = public_key + .public_subkeys + .first() + .context("No encryption subkey found")?; + let literal_message = pgp::composed::Message::new_literal("", token); + let mut rng = thread_rng(); + let encrypted_message = literal_message.encrypt_to_keys_seipdv1( + &mut rng, + SymmetricKeyAlgorithm::AES128, + &[&encryption_subkey], + )?; + let encoded_message = encrypted_message.to_armored_string(Default::default())?; + self.inner.write().await.device_token = Some(encoded_message); + Ok(()) } /// Retrieves device token. /// + /// The token is encrypted with OpenPGP. + /// /// Token may be not available if application is not running on Apple platform, + /// does not have Google Play services, /// failed to register for remote notifications or is in the process of registering. /// /// IMAP loop should periodically check if device token is available @@ -121,3 +160,22 @@ impl Context { } } } + +#[cfg(test)] +mod tests { + use super::*; + + #[tokio::test(flavor = "multi_thread", worker_threads = 2)] + async fn test_set_device_key() { + let push_subscriber = PushSubscriber::new(); + assert_eq!(push_subscriber.device_token().await, None); + + push_subscriber + .set_device_token("some-token") + .await + .expect("Failed to set device token"); + let device_token = push_subscriber.device_token().await.unwrap(); + assert!(device_token.starts_with("-----BEGIN PGP MESSAGE-----")); + assert!(device_token.ends_with("-----END PGP MESSAGE-----\n")); + } +}