autoendpoint/extractors/
router_data_input.rs

1use 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/// Extracts the router data from the request body and validates the token
14/// against the given router's token schema (taken from request path params).
15#[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            // Validate the token according to each router's token schema
39            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}