mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2025-04-19 02:50:54 +00:00
188 lines
5.8 KiB
Rust
188 lines
5.8 KiB
Rust
use std::collections::HashMap;
|
|
use std::str::FromStr;
|
|
|
|
use actix_web::{HttpRequest, HttpResponse, web};
|
|
use actix_web::dev::HttpResponseBuilder;
|
|
use actix_web::http::{HeaderName, HeaderValue, StatusCode};
|
|
use serde::Serialize;
|
|
|
|
use crate::api_data::http_error::HttpError;
|
|
use crate::controllers::routes::RequestResult;
|
|
use crate::data::api_client::APIClient;
|
|
use crate::data::base_request_handler::{BaseRequestHandler, RequestValue};
|
|
use crate::data::config::conf;
|
|
use crate::data::error::{Res, ResultBoxError};
|
|
use crate::data::user_token::UserAccessToken;
|
|
use crate::helpers::{account_helper, api_helper};
|
|
|
|
/// Http request handler
|
|
///
|
|
/// @author Pierre Hubert
|
|
|
|
pub struct HttpRequestHandler {
|
|
request: web::HttpRequest,
|
|
body: HashMap<String, RequestValue>,
|
|
response: Option<web::HttpResponse>,
|
|
headers: HashMap<String, String>,
|
|
client: Option<APIClient>,
|
|
curr_user_token: Option<UserAccessToken>,
|
|
}
|
|
|
|
impl HttpRequestHandler {
|
|
/// Construct a new request handler
|
|
pub fn new(req: HttpRequest, body: HashMap<String, RequestValue>) -> HttpRequestHandler {
|
|
HttpRequestHandler {
|
|
request: req,
|
|
body,
|
|
response: None,
|
|
headers: HashMap::new(),
|
|
client: None,
|
|
curr_user_token: None,
|
|
}
|
|
}
|
|
|
|
/// Check if a response has been set for this request
|
|
pub fn has_response(&self) -> bool {
|
|
self.response.is_some()
|
|
}
|
|
|
|
/// Get the response status code, eg. 200 or 404
|
|
pub fn response_status_code(&self) -> u16 {
|
|
self.response.as_ref().unwrap().status().as_u16()
|
|
}
|
|
|
|
/// Take the response from this struct
|
|
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)
|
|
}
|
|
|
|
|
|
/// Get the path of the request
|
|
pub fn request_path(&self) -> String {
|
|
self.request.path().to_string()
|
|
}
|
|
|
|
/// Get information about the client which made the request
|
|
pub fn api_client(&self) -> &APIClient {
|
|
self.client.as_ref().unwrap()
|
|
}
|
|
|
|
/// Check API client tokens
|
|
pub fn check_client_token(&mut self) -> RequestResult {
|
|
// TODO : remove fallback
|
|
let client_name = self.post_string_with_fallback("client", "serviceName")?;
|
|
|
|
let client = self.ok_or_bad_request(
|
|
api_helper::get_client(&client_name),
|
|
"Client not recognized!",
|
|
)?;
|
|
|
|
|
|
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(())
|
|
}
|
|
|
|
/// Check login token
|
|
pub fn check_user_token(&mut self) -> Res {
|
|
// TODO : remove fallback
|
|
let token = self.post_string_with_fallback("token", "userToken1")?;
|
|
|
|
// Find user
|
|
match account_helper::find_user_by_login_token(&token, self.api_client()) {
|
|
Ok(token) => {
|
|
if token.need_refresh() {
|
|
account_helper::refresh_access_token(&token)?;
|
|
}
|
|
|
|
self.curr_user_token = Some(token);
|
|
|
|
Ok(())
|
|
}
|
|
Err(e) => {
|
|
println!("Error marking login tokens as invalid: {}", e);
|
|
self.response = Some(
|
|
actix_web::HttpResponse::
|
|
build(actix_web::http::StatusCode::from_u16(412)?)
|
|
.json(HttpError::new(412, "Please check your login tokens!")));
|
|
Err(e)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BaseRequestHandler for HttpRequestHandler {
|
|
/// Get request parameter
|
|
fn post_parameter_opt(&self, name: &str) -> Option<&RequestValue> {
|
|
self.body.get(name)
|
|
}
|
|
|
|
/// Set request response
|
|
fn set_response<T: Serialize>(&mut self, data: T) -> RequestResult {
|
|
self.response = Some(HttpResponse::Ok().json(data));
|
|
Ok(())
|
|
}
|
|
|
|
/// Set request error
|
|
fn set_error(&mut self, error: HttpError) {
|
|
self.response = Some(HttpResponseBuilder::new(StatusCode::from_u16(error.error.code).unwrap())
|
|
.json(error));
|
|
}
|
|
|
|
/// Get the remote IP address
|
|
fn remote_ip(&self) -> String {
|
|
let mut ip = self.request.peer_addr().unwrap().ip().to_string();
|
|
|
|
// We check if the request comes from a trusted reverse proxy
|
|
if let Some(proxy) = conf().proxy.as_ref() {
|
|
if ip.eq(proxy) {
|
|
if let Some(header) = self.request.headers().get("X-Forwarded-For") {
|
|
let header: Vec<String> = header
|
|
.to_str()
|
|
.unwrap()
|
|
.to_string()
|
|
.split(",")
|
|
.map(|f| f.to_string())
|
|
.collect();
|
|
|
|
if header.len() > 0 {
|
|
ip = header[0].to_string();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ip
|
|
}
|
|
|
|
fn user_access_token(&self) -> Option<&UserAccessToken> {
|
|
self.curr_user_token.as_ref()
|
|
}
|
|
} |