From 27f15f7b02ef6524789985983bc95017ced318d8 Mon Sep 17 00:00:00 2001 From: IAmTomahawkx Date: Fri, 5 Jul 2024 20:43:08 -0700 Subject: [PATCH] change apns to use sandbox, and (somewhat) provide a custom payload Signed-off-by: IAmTomahawkx --- crates/core/config/Revolt.toml | 1 + crates/core/config/src/lib.rs | 1 + .../database/src/tasks/apple_notifications.rs | 56 +++++++++++++++++-- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/crates/core/config/Revolt.toml b/crates/core/config/Revolt.toml index 611edfa0..64a5fe92 100644 --- a/crates/core/config/Revolt.toml +++ b/crates/core/config/Revolt.toml @@ -30,6 +30,7 @@ public_key = "BGcvgR-i2z4IQ5Mw841vJvkLjt8wY-FjmWrw83jOLCY52qcGZS0OF7nfLzuYbjsQIS api_key = "" [api.apn] +sandbox = false pkcs8 = "" key_id = "" team_id = "" diff --git a/crates/core/config/src/lib.rs b/crates/core/config/src/lib.rs index 46cfb82e..5c49f238 100644 --- a/crates/core/config/src/lib.rs +++ b/crates/core/config/src/lib.rs @@ -79,6 +79,7 @@ pub struct ApiFcm { #[derive(Deserialize, Debug, Clone)] pub struct ApiApn { + pub sandbox: bool, pub pkcs8: String, pub key_id: String, pub team_id: String, diff --git a/crates/core/database/src/tasks/apple_notifications.rs b/crates/core/database/src/tasks/apple_notifications.rs index cbf9a634..4271afe5 100644 --- a/crates/core/database/src/tasks/apple_notifications.rs +++ b/crates/core/database/src/tasks/apple_notifications.rs @@ -6,13 +6,23 @@ use base64::{ }; use deadqueue::limited::Queue; use once_cell::sync::Lazy; -use revolt_a2::{Client, ClientConfig, DefaultNotificationBuilder}; +use revolt_a2::{Client, ClientConfig, DefaultNotificationBuilder, Endpoint}; use revolt_a2::{Error, ErrorBody, ErrorReason, NotificationBuilder, Response}; use revolt_config::config; -use revolt_models::v0::PushNotification; +use revolt_models::v0::{Message, PushNotification}; use crate::Database; +/// Payload information +#[derive(Debug)] +pub struct ApnCustomPayload { + message: Message, + serverId: String, + authorAvatar: String, + authorDisplayName: String, + channelName: String, +} + /// Task information #[derive(Debug)] pub struct ApnTask { @@ -30,9 +40,24 @@ pub struct ApnTask { /// Thread Id thread_id: String, + + /// Category (informs the client what kind of notification is being sent.) + category: String, + + /// Payload used by the iOS client to modify the notification + payload: ApnCustomPayload, } impl ApnTask { + fn format_title(notification: &PushNotification) -> String { + // ideally this changes depending on context + // in a server, it would look like "Sendername, #channelname in servername" + // in a group, it would look like "Sendername in groupname" + // in a dm it should just be "Sendername". + // not sure how feasible all those are given the PushNotification object as it currently stands. + todo!(); + } + pub fn from_notification( session_id: String, device_token: String, @@ -41,9 +66,17 @@ impl ApnTask { ApnTask { session_id, device_token, - title: notification.author.to_string(), + title: ApnTask::format_title(notification), body: notification.body.to_string(), thread_id: notification.tag.to_string(), + category: "ALERT_MESSAGE".to_string(), + payload: ApnCustomPayload { + message: (), + serverId: (), + authorAvatar: notification.icon.to_string(), + authorDisplayName: notification.author.to_string(), + channelName: (), + }, } } } @@ -67,15 +100,24 @@ pub async fn worker(db: Database) { return; } + let endpoint = if config.api.apn.sandbox { + Endpoint::Sandbox + } else { + Endpoint::Production + }; + let pkcs8 = engine::general_purpose::STANDARD .decode(config.api.apn.pkcs8) .expect("valid `pcks8`"); + let client_config = ClientConfig::default(); + client_config.endpoint = endpoint; + let client = Client::token( &mut Cursor::new(pkcs8), config.api.apn.key_id, config.api.apn.team_id, - ClientConfig::default(), + client_config, ) .expect("could not create APN client"); @@ -85,8 +127,14 @@ pub async fn worker(db: Database) { .set_title(&task.title) .set_body(&task.body) .set_thread_id(&task.thread_id) + .set_category(&task.category) + .set_mutable_content() // allows the service extension to execute .build(&task.device_token, Default::default()); + payload.data = &task.payload; // this looks like a job for someone more rust-inclined than me. -tom + + println!("sending APNS payload: {:?}", payload.data); + if let Err(err) = client.send(payload).await { match err { Error::ResponseError(Response {