mirror of
				https://gitlab.com/comunic/comunicapiv3
				synced 2025-11-04 09:34:04 +00:00 
			
		
		
		
	Check client tokens
This commit is contained in:
		@@ -15,7 +15,7 @@ server-port: 3000
 | 
			
		||||
proxy: none
 | 
			
		||||
 | 
			
		||||
# If set to true Access-Control-Allow-Origin will be set for https
 | 
			
		||||
force-https: false
 | 
			
		||||
force-https: true
 | 
			
		||||
 | 
			
		||||
# User data storage
 | 
			
		||||
storage-url: https://devweb.local/comunic/current/user_data/
 | 
			
		||||
 
 | 
			
		||||
@@ -61,6 +61,6 @@ pub fn get_routes() -> Vec<Route> {
 | 
			
		||||
 | 
			
		||||
        // Account controller
 | 
			
		||||
        Route::post_without_login("/account/login", Box::new(account_controller::login_user)),
 | 
			
		||||
        Route::post_without_login("/account/connectUSER", Box::new(account_controller::login_user)),
 | 
			
		||||
        Route::post_without_login("/user/connectUSER", Box::new(account_controller::login_user)),
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
@@ -172,7 +172,14 @@ async fn process_request(custom_req: CustomRequest) -> HttpResponse {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    request.response()
 | 
			
		||||
    // Send the response
 | 
			
		||||
    match request.response() {
 | 
			
		||||
        Ok(s) => s,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            println!("Error while getting response: {}", e);
 | 
			
		||||
            HttpResponse::InternalServerError().body("Response error")
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,36 +3,45 @@ use serde::Serialize;
 | 
			
		||||
/// HTTP request error
 | 
			
		||||
///
 | 
			
		||||
/// @author Pierre Hubert
 | 
			
		||||
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
pub struct HttpError {
 | 
			
		||||
pub struct InnerHTTPError {
 | 
			
		||||
    pub code: u16,
 | 
			
		||||
    pub message: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl HttpError {
 | 
			
		||||
#[derive(Serialize)]
 | 
			
		||||
pub struct HttpError {
 | 
			
		||||
    pub error: InnerHTTPError
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl HttpError {
 | 
			
		||||
    /// Generate a 404 error
 | 
			
		||||
    pub fn not_found(message: &str) -> HttpError {
 | 
			
		||||
        HttpError {
 | 
			
		||||
            code: 404,
 | 
			
		||||
            message: message.to_string()
 | 
			
		||||
            error: InnerHTTPError {
 | 
			
		||||
                code: 404,
 | 
			
		||||
                message: message.to_string(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Generate a 500 error
 | 
			
		||||
    pub fn internal_error(message: &str) -> HttpError {
 | 
			
		||||
        HttpError {
 | 
			
		||||
            code: 500,
 | 
			
		||||
            message: message.to_string()
 | 
			
		||||
            error: InnerHTTPError {
 | 
			
		||||
                code: 500,
 | 
			
		||||
                message: message.to_string(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Generate a 401 error
 | 
			
		||||
    pub fn bad_request(message: &str) -> HttpError {
 | 
			
		||||
        HttpError {
 | 
			
		||||
            code: 401,
 | 
			
		||||
            message: message.to_string()
 | 
			
		||||
            error: InnerHTTPError {
 | 
			
		||||
                code: 401,
 | 
			
		||||
                message: message.to_string(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,6 +6,10 @@ use serde::Serialize;
 | 
			
		||||
use crate::data::error::{ResultBoxError, ExecError};
 | 
			
		||||
use std::collections::HashMap;
 | 
			
		||||
use crate::helpers::api_helper;
 | 
			
		||||
use actix_web::http::{HeaderName, HeaderValue};
 | 
			
		||||
use std::str::FromStr;
 | 
			
		||||
use crate::data::config::conf;
 | 
			
		||||
use crate::data::api_client::APIClient;
 | 
			
		||||
 | 
			
		||||
/// Http request handler
 | 
			
		||||
///
 | 
			
		||||
@@ -34,6 +38,8 @@ pub struct HttpRequestHandler {
 | 
			
		||||
    request: web::HttpRequest,
 | 
			
		||||
    body: HashMap<String, RequestValue>,
 | 
			
		||||
    response: Option<web::HttpResponse>,
 | 
			
		||||
    headers: HashMap<String, String>,
 | 
			
		||||
    client: Option<APIClient>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl HttpRequestHandler {
 | 
			
		||||
@@ -43,6 +49,8 @@ impl HttpRequestHandler {
 | 
			
		||||
            request: req,
 | 
			
		||||
            body,
 | 
			
		||||
            response: None,
 | 
			
		||||
            headers: HashMap::new(),
 | 
			
		||||
            client: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -57,8 +65,17 @@ impl HttpRequestHandler {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Take the response from this struct
 | 
			
		||||
    pub fn response(self) -> HttpResponse {
 | 
			
		||||
        self.response.unwrap()
 | 
			
		||||
    pub fn response(self) -> ResultBoxError<HttpResponse> {
 | 
			
		||||
        let mut response = self.response.unwrap();
 | 
			
		||||
 | 
			
		||||
        // Put additional headers if required
 | 
			
		||||
        for (k, v) in &self.headers {
 | 
			
		||||
            response.headers_mut().insert(HeaderName::from_str(k)?,
 | 
			
		||||
                                          HeaderValue::from_str(v)?,
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(response)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Success message
 | 
			
		||||
@@ -91,7 +108,7 @@ impl HttpRequestHandler {
 | 
			
		||||
                println!("Error leading to bad request: {}", err);
 | 
			
		||||
                self.bad_request(msg.to_string())?;
 | 
			
		||||
                unreachable!()
 | 
			
		||||
            },
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -133,11 +150,30 @@ impl HttpRequestHandler {
 | 
			
		||||
 | 
			
		||||
        let client = self.ok_or_bad_request(
 | 
			
		||||
            api_helper::get_client(&api_name, &api_token),
 | 
			
		||||
            "Client not recognized!"
 | 
			
		||||
            "Client not recognized!",
 | 
			
		||||
        )?;
 | 
			
		||||
 | 
			
		||||
        // TODO  : continue here
 | 
			
		||||
        println!("{:#?}", client);
 | 
			
		||||
 | 
			
		||||
        if let Some(domain) = &client.domain {
 | 
			
		||||
            let allowed_origin =  match conf().force_https {
 | 
			
		||||
                true => format!("https://{}", domain),
 | 
			
		||||
                false => format!("http://{}", domain)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            match self.request.headers().get("Referer") {
 | 
			
		||||
                None => self.bad_request("Unknown origin!".to_string())?,
 | 
			
		||||
                Some(s) => {
 | 
			
		||||
                    if !s.to_str()?.starts_with(&allowed_origin) {
 | 
			
		||||
                        self.bad_request("Use of this client is prohibited from this domain!".to_string())?;
 | 
			
		||||
                    }
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            self.headers.insert("Access-Control-Allow-Origin".to_string(), allowed_origin);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.client = Some(client);
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -20,7 +20,7 @@ pub fn get_client(name: &str, token: &str) -> ResultBoxError<APIClient> {
 | 
			
		||||
                    id: res.get_int64("id")? as u32,
 | 
			
		||||
                    name: res.get_str("service_name")?,
 | 
			
		||||
                    token: res.get_str("token")?,
 | 
			
		||||
                    domain: res.get_optional_str("domain")?,
 | 
			
		||||
                    domain: res.get_optional_str("client_domain")?,
 | 
			
		||||
                })
 | 
			
		||||
            }
 | 
			
		||||
    )
 | 
			
		||||
 
 | 
			
		||||
@@ -3,11 +3,11 @@ use std::error::Error;
 | 
			
		||||
use std::ops::Add;
 | 
			
		||||
use std::sync::{Arc, Mutex};
 | 
			
		||||
 | 
			
		||||
use mysql::{Binary, Pool, ResultSet};
 | 
			
		||||
use mysql::{Binary, Pool, ResultSet, Value};
 | 
			
		||||
use mysql::prelude::Queryable;
 | 
			
		||||
 | 
			
		||||
use crate::data::config::DatabaseConfig;
 | 
			
		||||
use crate::data::error::ExecError;
 | 
			
		||||
use crate::data::error::{ExecError, ResultBoxError};
 | 
			
		||||
 | 
			
		||||
/// Database access helper
 | 
			
		||||
///
 | 
			
		||||
@@ -107,30 +107,43 @@ impl<'a> RowResult<'a> {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Find an integer included in the request
 | 
			
		||||
    pub fn get_int64(&self, name: &str) -> Result<i64, ExecError> {
 | 
			
		||||
        let value: Option<i64> = self.row.get(self.find_col(name)?);
 | 
			
		||||
    pub fn get_int64(&self, name: &str) -> Result<i64, Box<dyn Error>> {
 | 
			
		||||
        let value = self.row.get_opt(self.find_col(name)?);
 | 
			
		||||
 | 
			
		||||
        match value {
 | 
			
		||||
            None => Err(ExecError(format!("Could not extract integer field {} !", name))),
 | 
			
		||||
            Some(s) => Ok(s)
 | 
			
		||||
            None => Err(ExecError::boxed_string(
 | 
			
		||||
                format!("Could not extract integer field {} !", name))),
 | 
			
		||||
            Some(s) => Ok(s?)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Find a string included in the request
 | 
			
		||||
    pub fn get_str(&self, name: &str) -> Result<String, ExecError> {
 | 
			
		||||
        let value: Option<String> = self.row.get(self.find_col(name)?);
 | 
			
		||||
    pub fn get_str(&self, name: &str) -> Result<String, Box<dyn Error>> {
 | 
			
		||||
        let value = self.row.get_opt(self.find_col(name)?);
 | 
			
		||||
 | 
			
		||||
        match value {
 | 
			
		||||
            None => Err(ExecError(format!("Could not extract string field {} !", name))),
 | 
			
		||||
            Some(s) => Ok(s)
 | 
			
		||||
            None => Err(ExecError::boxed_string(
 | 
			
		||||
                format!("Could not extract string field {} !", name))),
 | 
			
		||||
            Some(s) => Ok(s?)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get an optional string
 | 
			
		||||
    pub fn get_optional_str(&self, name: &str) -> Result<Option<String>, ExecError> {
 | 
			
		||||
        match self.find_col(name) {
 | 
			
		||||
            Ok(col) => Ok(self.row.get(col)),
 | 
			
		||||
            Err(_) => Ok(None),
 | 
			
		||||
    /// Check out whether a given value is null or not
 | 
			
		||||
    pub fn is_null(&self, name: &str) -> ResultBoxError<bool> {
 | 
			
		||||
        let value = self.row.get_opt(self.find_col(name)?);
 | 
			
		||||
 | 
			
		||||
        match value {
 | 
			
		||||
            None => Ok(true),
 | 
			
		||||
            Some(Ok(Value::NULL)) => Ok(true),
 | 
			
		||||
            _ => Ok(false)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Get an optional string => Set to None if string is null
 | 
			
		||||
    pub fn get_optional_str(&self, name: &str) -> ResultBoxError<Option<String>> {
 | 
			
		||||
        match self.is_null(name)? {
 | 
			
		||||
            true => Ok(None),
 | 
			
		||||
            false => Ok(Some(self.get_str(name)?))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user