1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-26 15:29:21 +00:00

Add support for admin routes

This commit is contained in:
Pierre HUBERT 2021-05-09 16:17:58 +02:00
parent 56539d3476
commit ffe6d464d7
8 changed files with 98 additions and 7 deletions

View File

@ -70,6 +70,9 @@ rtc-relay:
allow-video: true allow-video: true
max-users-per-video-calls: 6 max-users-per-video-calls: 6
# Admin URL
admin-url: https://console.communiquons.org
# List of #Forez groups # List of #Forez groups
# #
# This option allows to enable some extra features for these groups # This option allows to enable some extra features for these groups

View File

@ -0,0 +1,12 @@
//! # Admin account controller
//!
//! @author Pierre Hubert
use crate::data::http_request_handler::HttpRequestHandler;
use crate::routes::RequestResult;
use crate::data::base_request_handler::BaseRequestHandler;
/// Get admin auth options
pub fn get_auth_options(r: &mut HttpRequestHandler) -> RequestResult {
r.ok()
}

View File

@ -0,0 +1,5 @@
//! # Admin controllers
//!
//! @author Pierre Hubert
pub mod admin_account_controller;

View File

@ -1,3 +1,5 @@
pub mod admin;
pub mod server_controller; pub mod server_controller;
pub mod user_ws_controller; pub mod user_ws_controller;
pub mod rtc_relay_controller; pub mod rtc_relay_controller;

View File

@ -51,6 +51,7 @@ pub struct Config {
pub independent_push_service: Option<IndependentPushService>, pub independent_push_service: Option<IndependentPushService>,
pub database: DatabaseConfig, pub database: DatabaseConfig,
pub rtc_relay: Option<RtcRelayConfig>, pub rtc_relay: Option<RtcRelayConfig>,
pub admin_url: String,
pub forez_groups: Vec<GroupID>, pub forez_groups: Vec<GroupID>,
} }
@ -152,6 +153,8 @@ impl Config {
rtc_relay: rtc_config, rtc_relay: rtc_config,
admin_url: Self::yaml_str(parsed, "admin-url"),
forez_groups: parsed["forez_groups"] forez_groups: parsed["forez_groups"]
.as_vec() .as_vec()
.unwrap_or(&vec![]) .unwrap_or(&vec![])

View File

@ -129,6 +129,17 @@ impl HttpRequestHandler {
} }
} }
} }
/// Check admin origin
pub fn check_admin_origin(&mut self) -> Res {
if let Some(header) = self.request.headers().get("Origin") {
if header.to_str()?.eq(&conf().admin_url) {
return Ok(());
}
}
self.bad_request("Invalid origin for admin requests!".to_string())
}
} }
impl BaseRequestHandler for HttpRequestHandler { impl BaseRequestHandler for HttpRequestHandler {

View File

@ -1,6 +1,7 @@
use std::error::Error; use std::error::Error;
use crate::controllers::{account_controller, comments_controller, conversations_controller, forez_controller, friends_controller, groups_controller, likes_controller, notifications_controller, posts_controller, push_notifications_controller, search_controller, server_controller, settings_controller, surveys_controller, user_controller, user_ws_controller, virtual_directory_controller, web_app_controller}; use crate::controllers::{account_controller, comments_controller, conversations_controller, forez_controller, friends_controller, groups_controller, likes_controller, notifications_controller, posts_controller, push_notifications_controller, search_controller, server_controller, settings_controller, surveys_controller, user_controller, user_ws_controller, virtual_directory_controller, web_app_controller};
use crate::controllers::admin::*;
use crate::data::http_request_handler::HttpRequestHandler; use crate::data::http_request_handler::HttpRequestHandler;
use crate::routes::Method::{GET, POST}; use crate::routes::Method::{GET, POST};
@ -34,6 +35,15 @@ pub enum LimitPolicy {
ANY(u64), ANY(u64),
} }
/// Scope of the route
pub enum RouteScope {
// Route accessible by a "normal" user of Comunic
USER,
// Route accessible by an administrator of Comunic
ADMIN,
}
impl LimitPolicy { impl LimitPolicy {
pub fn is_none(&self) -> bool { pub fn is_none(&self) -> bool {
matches!(self, LimitPolicy::NONE) matches!(self, LimitPolicy::NONE)
@ -54,6 +64,9 @@ pub type RequestResult = Result<(), Box<dyn Error>>;
pub type RequestProcess = Box<dyn Fn(&mut HttpRequestHandler) -> RequestResult>; pub type RequestProcess = Box<dyn Fn(&mut HttpRequestHandler) -> RequestResult>;
pub struct Route { pub struct Route {
/// Route scope
pub scope: RouteScope,
/// The Verb used for the request /// The Verb used for the request
pub method: Method, pub method: Method,
@ -73,6 +86,7 @@ pub struct Route {
impl Route { impl Route {
pub fn get_without_login(uri: &'static str, func: RequestProcess) -> Route { pub fn get_without_login(uri: &'static str, func: RequestProcess) -> Route {
Route { Route {
scope: RouteScope::USER,
method: GET, method: GET,
need_login: false, need_login: false,
uri, uri,
@ -83,6 +97,7 @@ impl Route {
pub fn post_without_login(uri: &'static str, func: RequestProcess) -> Route { pub fn post_without_login(uri: &'static str, func: RequestProcess) -> Route {
Route { Route {
scope: RouteScope::USER,
method: POST, method: POST,
need_login: false, need_login: false,
uri, uri,
@ -93,6 +108,7 @@ impl Route {
pub fn limited_post_without_login(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route { pub fn limited_post_without_login(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route {
Route { Route {
scope: RouteScope::USER,
method: POST, method: POST,
need_login: false, need_login: false,
uri, uri,
@ -103,6 +119,7 @@ impl Route {
pub fn post(uri: &'static str, func: RequestProcess) -> Route { pub fn post(uri: &'static str, func: RequestProcess) -> Route {
Route { Route {
scope: RouteScope::USER,
method: POST, method: POST,
need_login: true, need_login: true,
uri, uri,
@ -113,6 +130,7 @@ impl Route {
pub fn limited_post(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route { pub fn limited_post(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route {
Route { Route {
scope: RouteScope::USER,
method: POST, method: POST,
need_login: true, need_login: true,
uri, uri,
@ -120,6 +138,17 @@ impl Route {
limit_policy, limit_policy,
} }
} }
pub fn limited_admin_post_without_login(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route {
Route {
scope: RouteScope::ADMIN,
method: POST,
need_login: false,
uri,
func,
limit_policy,
}
}
} }
/// Get the list of routes available /// Get the list of routes available
@ -301,5 +330,12 @@ pub fn get_routes() -> Vec<Route> {
// Forez controller // Forez controller
Route::post("/forez/get_groups", Box::new(forez_controller::get_list_groups)), Route::post("/forez/get_groups", Box::new(forez_controller::get_list_groups)),
Route::post("/forez/get_member_info", Box::new(forez_controller::get_member_info)), Route::post("/forez/get_member_info", Box::new(forez_controller::get_member_info)),
// === ADMIN ROUTES ===
// Admin accounts controller
Route::limited_admin_post_without_login("/admin/accounts/auth_options", Box::new(admin_account_controller::get_auth_options), LimitPolicy::FAILURE(5)),
] ]
} }

View File

@ -18,7 +18,7 @@ use crate::data::base_request_handler::{BaseRequestHandler, PostFile, RequestVal
use crate::data::config::Config; use crate::data::config::Config;
use crate::data::http_request_handler::HttpRequestHandler; use crate::data::http_request_handler::HttpRequestHandler;
use crate::helpers::{api_helper, requests_limit_helper}; use crate::helpers::{api_helper, requests_limit_helper};
use crate::routes::{get_routes, RequestResult, Route}; use crate::routes::{get_routes, RequestResult, Route, RouteScope};
use crate::routes::Method::{GET, POST}; use crate::routes::Method::{GET, POST};
use crate::utils::user_data_utils::user_data_path; use crate::utils::user_data_utils::user_data_path;
@ -209,14 +209,33 @@ fn process_simple_route(route: &Route, req: &mut HttpRequestHandler) -> RequestR
req.too_many_requests("Too many request. Please try again later.")?; req.too_many_requests("Too many request. Please try again later.")?;
} }
// Validate client token // Check if the user is allowed to access the route
req.check_client_token()?; match route.scope {
// Check user token, if required // "Normal" user route
if route.need_login || req.has_post_parameter("userToken1") { RouteScope::USER => {
req.check_user_token()?; // Validate client token
req.check_client_token()?;
// Check user token, if required
if route.need_login || req.has_post_parameter("token") {
req.check_user_token()?;
}
},
// "Admin" user scope
RouteScope::ADMIN => {
req.check_admin_origin()?;
if route.need_login {
// TODO : implement
unimplemented!();
}
}
} }
let res: RequestResult = (route.func)(req); let res: RequestResult = (route.func)(req);
requests_limit_helper::trigger_after(res.is_ok(), req, route)?; requests_limit_helper::trigger_after(res.is_ok(), req, route)?;
@ -250,7 +269,7 @@ async fn process_request(custom_req: CustomRequest) -> HttpResponse {
// Check if a route was found // Check if a route was found
if let None = route { if let None = route {
return HttpResponse::NotFound().json(HttpError::not_found("Method not found!")); return HttpResponse::NotFound().json(HttpError::not_found("Route not found!"));
} }
let route = route.unwrap(); let route = route.unwrap();