1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-12-27 22:18:51 +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
max-users-per-video-calls: 6
# Admin URL
admin-url: https://console.communiquons.org
# List of #Forez 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 user_ws_controller;
pub mod rtc_relay_controller;

View File

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

View File

@ -1,6 +1,7 @@
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::admin::*;
use crate::data::http_request_handler::HttpRequestHandler;
use crate::routes::Method::{GET, POST};
@ -34,6 +35,15 @@ pub enum LimitPolicy {
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 {
pub fn is_none(&self) -> bool {
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 struct Route {
/// Route scope
pub scope: RouteScope,
/// The Verb used for the request
pub method: Method,
@ -73,6 +86,7 @@ pub struct Route {
impl Route {
pub fn get_without_login(uri: &'static str, func: RequestProcess) -> Route {
Route {
scope: RouteScope::USER,
method: GET,
need_login: false,
uri,
@ -83,6 +97,7 @@ impl Route {
pub fn post_without_login(uri: &'static str, func: RequestProcess) -> Route {
Route {
scope: RouteScope::USER,
method: POST,
need_login: false,
uri,
@ -93,6 +108,7 @@ impl Route {
pub fn limited_post_without_login(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route {
Route {
scope: RouteScope::USER,
method: POST,
need_login: false,
uri,
@ -103,6 +119,7 @@ impl Route {
pub fn post(uri: &'static str, func: RequestProcess) -> Route {
Route {
scope: RouteScope::USER,
method: POST,
need_login: true,
uri,
@ -113,6 +130,7 @@ impl Route {
pub fn limited_post(uri: &'static str, func: RequestProcess, limit_policy: LimitPolicy) -> Route {
Route {
scope: RouteScope::USER,
method: POST,
need_login: true,
uri,
@ -120,6 +138,17 @@ impl Route {
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
@ -301,5 +330,12 @@ pub fn get_routes() -> Vec<Route> {
// Forez controller
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)),
// === 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::http_request_handler::HttpRequestHandler;
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::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.")?;
}
// Validate client token
req.check_client_token()?;
// Check if the user is allowed to access the route
match route.scope {
// Check user token, if required
if route.need_login || req.has_post_parameter("userToken1") {
req.check_user_token()?;
// "Normal" user route
RouteScope::USER => {
// 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);
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
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();