Page MenuHomePhabricator

D12935.id43237.diff
No OneTemporary

D12935.id43237.diff

diff --git a/lib/types/tunnelbroker/notif-types.js b/lib/types/tunnelbroker/notif-types.js
--- a/lib/types/tunnelbroker/notif-types.js
+++ b/lib/types/tunnelbroker/notif-types.js
@@ -23,7 +23,15 @@
+payload: string,
};
+export type TunnelbrokerWNSNotif = {
+ +type: 'WNSNotif',
+ +clientMessageID: string,
+ +deviceID: string,
+ +payload: string,
+};
+
export type TunnelbrokerNotif =
| TunnelbrokerAPNsNotif
| TunnelbrokerFCMNotif
- | TunnelbrokerWebPushNotif;
+ | TunnelbrokerWebPushNotif
+ | TunnelbrokerWNSNotif;
diff --git a/services/tunnelbroker/src/notifs/mod.rs b/services/tunnelbroker/src/notifs/mod.rs
--- a/services/tunnelbroker/src/notifs/mod.rs
+++ b/services/tunnelbroker/src/notifs/mod.rs
@@ -14,7 +14,7 @@
APNs,
FCM,
WebPush,
- WNs,
+ WNS,
}
impl NotifClientType {
@@ -25,7 +25,7 @@
}
NotifClientType::FCM => platform == Platform::Android,
NotifClientType::WebPush => platform == Platform::Web,
- NotifClientType::WNs => platform == Platform::Windows,
+ NotifClientType::WNS => platform == Platform::Windows,
}
}
}
diff --git a/services/tunnelbroker/src/notifs/wns/error.rs b/services/tunnelbroker/src/notifs/wns/error.rs
--- a/services/tunnelbroker/src/notifs/wns/error.rs
+++ b/services/tunnelbroker/src/notifs/wns/error.rs
@@ -1,5 +1,7 @@
use derive_more::{Display, Error, From};
+use super::response::WNSErrorResponse;
+
#[derive(Debug, From, Display, Error)]
pub enum Error {
Reqwest(reqwest::Error),
@@ -12,4 +14,6 @@
ReadLock,
#[display(fmt = "Failed to acquire write lock")]
WriteLock,
+ #[display(fmt = "WNS Notification Error: {}", _0)]
+ WNSNotification(WNSErrorResponse),
}
diff --git a/services/tunnelbroker/src/notifs/wns/mod.rs b/services/tunnelbroker/src/notifs/wns/mod.rs
--- a/services/tunnelbroker/src/notifs/wns/mod.rs
+++ b/services/tunnelbroker/src/notifs/wns/mod.rs
@@ -1,4 +1,6 @@
use crate::notifs::wns::config::WNSConfig;
+use reqwest::StatusCode;
+use response::WNSErrorResponse;
use std::{
sync::{Arc, RwLock},
time::{Duration, SystemTime},
@@ -6,6 +8,7 @@
pub mod config;
mod error;
+mod response;
#[derive(Debug, Clone)]
pub struct WNSAccessToken {
@@ -13,6 +16,12 @@
expires: SystemTime,
}
+#[derive(Debug, Clone)]
+pub struct WNSNotif {
+ pub device_token: String,
+ pub payload: String,
+}
+
#[derive(Clone)]
pub struct WNSClient {
http_client: reqwest::Client,
@@ -30,9 +39,48 @@
})
}
- pub async fn get_wns_token(
- &mut self,
- ) -> Result<Option<String>, error::Error> {
+ pub async fn send(&self, notif: WNSNotif) -> Result<(), error::Error> {
+ let wns_access_token = self
+ .get_wns_token()
+ .await?
+ .ok_or(error::Error::TokenNotFound)?;
+
+ let url = notif.device_token;
+
+ // Send the notification
+ let response = self
+ .http_client
+ .post(&url)
+ .header("Content-Type", "application/octet-stream")
+ .header("X-WNS-Type", "wns/raw")
+ .bearer_auth(wns_access_token.clone())
+ .body(notif.payload)
+ .send()
+ .await?;
+
+ match response.status() {
+ StatusCode::OK => {
+ tracing::debug!("Successfully sent WNS notif to {}", wns_access_token);
+ Ok(())
+ }
+ error_status => {
+ let body = response
+ .text()
+ .await
+ .unwrap_or_else(|error| format!("Error occurred: {}", error));
+ tracing::error!(
+ "Failed sending FCM notification to: {}. Status: {}. Body: {}",
+ wns_access_token,
+ error_status,
+ body
+ );
+ let fcm_error = WNSErrorResponse::from_status(error_status, body);
+ Err(error::Error::WNSNotification(fcm_error))
+ }
+ }
+ }
+
+ pub async fn get_wns_token(&self) -> Result<Option<String>, error::Error> {
const EXPIRY_WINDOW: Duration = Duration::from_secs(10);
{
diff --git a/services/tunnelbroker/src/notifs/wns/response.rs b/services/tunnelbroker/src/notifs/wns/response.rs
new file mode 100644
--- /dev/null
+++ b/services/tunnelbroker/src/notifs/wns/response.rs
@@ -0,0 +1,75 @@
+use derive_more::{Display, Error};
+use reqwest::StatusCode;
+
+#[derive(PartialEq, Debug, Clone, Display, Error)]
+pub struct InvalidArgumentError {
+ pub details: String,
+}
+
+#[derive(PartialEq, Debug, Display, Error)]
+pub enum WNSErrorResponse {
+ /// No more information is available about this error.
+ UnspecifiedError,
+
+ /// HTTP error code = 400.
+ /// One or more headers were specified incorrectly or conflict with another header.
+ BadRequest(InvalidArgumentError),
+
+ /// HTTP error code = 401.
+ /// The cloud service did not present a valid authentication ticket.
+ Unauthorized,
+
+ /// HTTP error code = 403.
+ /// The cloud service is not authorized to send a notification to this URI.
+ Forbidden,
+
+ /// HTTP error code = 404.
+ /// The channel URI is not valid or is not recognized by WNS.
+ NotFound,
+
+ /// HTTP error code = 405.
+ /// Invalid method (GET, CREATE); only POST (Windows or Windows Phone) or DELETE (Windows Phone only) is allowed.
+ MethodNotAllowed,
+
+ /// HTTP error code = 406.
+ /// The cloud service exceeded its throttle limit.
+ NotAcceptable,
+
+ /// HTTP error code = 410.
+ /// The channel expired.
+ Gone,
+
+ /// HTTP error code = 413.
+ /// The notification payload exceeds the 5000 byte size limit.
+ RequestEntityTooLarge,
+
+ /// HTTP error code = 500.
+ /// An internal failure caused notification delivery to fail.
+ InternalServerError,
+
+ /// HTTP error code = 503.
+ /// The server is currently unavailable.
+ ServiceUnavailable,
+}
+
+impl WNSErrorResponse {
+ pub fn from_status(status: StatusCode, body: String) -> Self {
+ match status {
+ StatusCode::BAD_REQUEST => {
+ WNSErrorResponse::BadRequest(InvalidArgumentError { details: body })
+ }
+ StatusCode::UNAUTHORIZED => WNSErrorResponse::Unauthorized,
+ StatusCode::FORBIDDEN => WNSErrorResponse::Forbidden,
+ StatusCode::NOT_FOUND => WNSErrorResponse::NotFound,
+ StatusCode::METHOD_NOT_ALLOWED => WNSErrorResponse::MethodNotAllowed,
+ StatusCode::NOT_ACCEPTABLE => WNSErrorResponse::NotAcceptable,
+ StatusCode::GONE => WNSErrorResponse::Gone,
+ StatusCode::PAYLOAD_TOO_LARGE => WNSErrorResponse::RequestEntityTooLarge,
+ StatusCode::INTERNAL_SERVER_ERROR => {
+ WNSErrorResponse::InternalServerError
+ }
+ StatusCode::SERVICE_UNAVAILABLE => WNSErrorResponse::ServiceUnavailable,
+ _ => WNSErrorResponse::UnspecifiedError,
+ }
+ }
+}
diff --git a/services/tunnelbroker/src/websockets/session.rs b/services/tunnelbroker/src/websockets/session.rs
--- a/services/tunnelbroker/src/websockets/session.rs
+++ b/services/tunnelbroker/src/websockets/session.rs
@@ -40,6 +40,7 @@
AndroidConfig, AndroidMessagePriority, FCMMessage,
};
use crate::notifs::web_push::WebPushNotif;
+use crate::notifs::wns::WNSNotif;
use crate::notifs::{apns, NotifClient, NotifClientType};
use crate::{identity, notifs};
@@ -77,6 +78,7 @@
MissingAPNsClient,
MissingFCMClient,
MissingWebPushClient,
+ MissingWNSClient,
MissingDeviceToken,
InvalidDeviceToken,
InvalidNotifProvider,
@@ -581,6 +583,46 @@
self.get_message_to_device_status(&notif.client_message_id, result),
)
}
+ DeviceToTunnelbrokerMessage::WNSNotif(notif) => {
+ if !self.device_info.is_authenticated {
+ debug!(
+ "Unauthenticated device {} tried to send WNS notif. Aborting.",
+ self.device_info.device_id
+ );
+ return Some(MessageSentStatus::Unauthenticated);
+ }
+ debug!("Received WNS notif for {}", notif.device_id);
+
+ let Some(wns_client) = self.notif_client.wns.clone() else {
+ return Some(self.get_message_to_device_status(
+ &notif.client_message_id,
+ Err(SessionError::MissingWNSClient),
+ ));
+ };
+
+ let device_token = match self
+ .get_device_token(notif.device_id, NotifClientType::WNS)
+ .await
+ {
+ Ok(token) => token,
+ Err(e) => {
+ return Some(
+ self
+ .get_message_to_device_status(&notif.client_message_id, Err(e)),
+ )
+ }
+ };
+
+ let wns_notif = WNSNotif {
+ device_token,
+ payload: notif.payload,
+ };
+
+ let result = wns_client.send(wns_notif).await;
+ Some(
+ self.get_message_to_device_status(&notif.client_message_id, result),
+ )
+ }
_ => {
error!("Client sent invalid message type");
Some(MessageSentStatus::InvalidRequest)
diff --git a/shared/tunnelbroker_messages/src/messages/mod.rs b/shared/tunnelbroker_messages/src/messages/mod.rs
--- a/shared/tunnelbroker_messages/src/messages/mod.rs
+++ b/shared/tunnelbroker_messages/src/messages/mod.rs
@@ -46,6 +46,7 @@
APNsNotif(APNsNotif),
FCMNotif(FCMNotif),
WebPushNotif(WebPushNotif),
+ WNSNotif(WNSNotif),
MessageToDeviceRequest(MessageToDeviceRequest),
MessageReceiveConfirmation(MessageReceiveConfirmation),
MessageToTunnelbrokerRequest(MessageToTunnelbrokerRequest),
diff --git a/shared/tunnelbroker_messages/src/messages/notif.rs b/shared/tunnelbroker_messages/src/messages/notif.rs
--- a/shared/tunnelbroker_messages/src/messages/notif.rs
+++ b/shared/tunnelbroker_messages/src/messages/notif.rs
@@ -35,3 +35,14 @@
pub device_id: String,
pub payload: String,
}
+
+/// WNS notif built on client.
+#[derive(Serialize, Deserialize, TagAwareDeserialize, PartialEq, Debug)]
+#[serde(tag = "type", remote = "Self", rename_all = "camelCase")]
+pub struct WNSNotif {
+ #[serde(rename = "clientMessageID")]
+ pub client_message_id: String,
+ #[serde(rename = "deviceID")]
+ pub device_id: String,
+ pub payload: String,
+}

File Metadata

Mime Type
text/plain
Expires
Fri, Sep 20, 9:15 AM (18 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2147841
Default Alt Text
D12935.id43237.diff (9 KB)

Event Timeline