autoendpoint/extractors/
router_data_input.rs1use crate::error::{ApiError, ApiErrorKind};
2use crate::extractors::{registration_path_args::RegistrationPathArgs, routers::RouterType};
3use actix_web::{dev::Payload, web, FromRequest, HttpRequest};
4use futures::{future::LocalBoxFuture, FutureExt};
5use lazy_static::lazy_static;
6use regex::Regex;
7use uuid::Uuid;
8
9lazy_static! {
10 static ref VALID_TOKEN: Regex = Regex::new(r"^[^ ]{8,}$").unwrap();
11}
12
13#[derive(serde::Deserialize)]
16pub struct RouterDataInput {
17 pub token: String,
18 #[serde(rename = "channelID")]
19 pub channel_id: Option<Uuid>,
20 pub key: Option<String>,
21 pub aps: Option<String>,
22}
23
24impl FromRequest for RouterDataInput {
25 type Error = ApiError;
26 type Future = LocalBoxFuture<'static, Result<Self, Self::Error>>;
27
28 fn from_request(req: &HttpRequest, payload: &mut Payload) -> Self::Future {
29 let req = req.clone();
30 let mut payload = payload.take();
31
32 async move {
33 let path_args = RegistrationPathArgs::extract(&req).into_inner()?;
34 let data: web::Json<Self> = web::Json::from_request(&req, &mut payload)
35 .await
36 .map_err(ApiErrorKind::PayloadError)?;
37
38 let is_valid = match path_args.router_type {
40 RouterType::WebPush => true,
41 RouterType::FCM | RouterType::GCM | RouterType::APNS => {
42 VALID_TOKEN.is_match(&data.token)
43 }
44 #[cfg(feature = "stub")]
45 RouterType::STUB => data.token.as_str() == "success",
46 };
47
48 if !is_valid {
49 return Err(ApiErrorKind::InvalidRouterToken.into());
50 }
51
52 Ok(data.into_inner())
53 }
54 .boxed_local()
55 }
56}