From 82b845c603d7590a6f3aed27b964e215f3b3b255 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Fri, 5 Feb 2021 10:37:37 +0100 Subject: [PATCH] Can get WebSocket access token --- config.yaml | 4 +- src/api_data/mod.rs | 3 +- src/api_data/res_get_ws_token.rs | 15 +++ src/constants.rs | 6 ++ src/controllers/mod.rs | 1 + src/controllers/routes.rs | 5 +- src/controllers/user_web_socket_controller.rs | 92 +++++++++++++++++++ src/lib.rs | 7 ++ 8 files changed, 129 insertions(+), 4 deletions(-) create mode 100644 src/api_data/res_get_ws_token.rs create mode 100644 src/controllers/user_web_socket_controller.rs diff --git a/config.yaml b/config.yaml index 0efe32a..550251d 100644 --- a/config.yaml +++ b/config.yaml @@ -7,14 +7,14 @@ # Server listening information server-address: 0.0.0.0 -server-port: 3001 +server-port: 3000 # Server proxy (none = no proxy) # This value is used to trust upstream proxy proxy: "127.0.0.1" # If set to true Access-Control-Allow-Origin will be set for https -force-https: false +force-https: true # User data storage storage-url: http://devweb.local/comunic/current/user_data/ diff --git a/src/api_data/mod.rs b/src/api_data/mod.rs index 3fbba4a..61821da 100644 --- a/src/api_data/mod.rs +++ b/src/api_data/mod.rs @@ -55,4 +55,5 @@ pub mod general_settings_api; pub mod language_settings_api; pub mod security_settings_api; pub mod account_image_settings_api; -pub mod res_create_custom_emoji; \ No newline at end of file +pub mod res_create_custom_emoji; +pub mod res_get_ws_token; \ No newline at end of file diff --git a/src/api_data/res_get_ws_token.rs b/src/api_data/res_get_ws_token.rs new file mode 100644 index 0000000..484c1fe --- /dev/null +++ b/src/api_data/res_get_ws_token.rs @@ -0,0 +1,15 @@ +//! # Get WebSocket token result +//! +//! @author Pierre Hubert +use serde::Serialize; + +#[derive(Serialize)] +pub struct ResGetWsToken { + token: String, +} + +impl ResGetWsToken { + pub fn new(token: String) -> Self { + ResGetWsToken { token } + } +} \ No newline at end of file diff --git a/src/constants.rs b/src/constants.rs index 7c26228..5bac31a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -57,6 +57,12 @@ pub mod database_tables_names { pub const NOTIFICATIONS_TABLE: &str = "comunic_notifications"; } +/// WebSocket access token lifetime, in seconds +pub const WS_ACCESS_TOKEN_LIFETIME: u64 = 10; + +/// WebSocket access token length +pub const WS_ACCESS_TOKEN_LENGTH: usize = 10; + /// Lifetime of limit counter (1 hour) pub const LIMIT_COUNTER_LIFETIME: u64 = 60 * 60; diff --git a/src/controllers/mod.rs b/src/controllers/mod.rs index 168302d..eb3d47d 100644 --- a/src/controllers/mod.rs +++ b/src/controllers/mod.rs @@ -2,6 +2,7 @@ pub mod routes; pub mod server; pub mod server_controller; +pub mod user_web_socket_controller; pub mod account_controller; pub mod user_controller; pub mod settings_controller; diff --git a/src/controllers/routes.rs b/src/controllers/routes.rs index 9e617fb..1acfdff 100644 --- a/src/controllers/routes.rs +++ b/src/controllers/routes.rs @@ -1,6 +1,6 @@ use std::error::Error; -use crate::controllers::{account_controller, calls_controller, comments_controller, conversations_controller, friends_controller, groups_controller, likes_controller, movies_controller, notifications_controller, posts_controller, search_controller, server_controller, settings_controller, surveys_controller, user_controller, virtual_directory_controller, web_app_controller}; +use crate::controllers::{account_controller, calls_controller, comments_controller, conversations_controller, friends_controller, groups_controller, likes_controller, movies_controller, notifications_controller, posts_controller, search_controller, server_controller, settings_controller, surveys_controller, user_controller, user_web_socket_controller, virtual_directory_controller, web_app_controller}; use crate::controllers::routes::Method::{GET, POST}; use crate::data::http_request_handler::HttpRequestHandler; @@ -128,6 +128,9 @@ pub fn get_routes() -> Vec { // Server meta routes Route::get_without_login("/", Box::new(server_controller::main_index)), + // Main user WebSocket + Route::post("/ws/token", Box::new(user_web_socket_controller::get_token)), + // Account controller Route::limited_post_without_login("/account/create", Box::new(account_controller::create), LimitPolicy::SUCCESS(10)), Route::limited_post_without_login("/account/login", Box::new(account_controller::login_user), LimitPolicy::FAILURE(10)), diff --git a/src/controllers/user_web_socket_controller.rs b/src/controllers/user_web_socket_controller.rs new file mode 100644 index 0000000..37193a3 --- /dev/null +++ b/src/controllers/user_web_socket_controller.rs @@ -0,0 +1,92 @@ +//! # User Web Socket controller +//! +//! Handles the WebSocket offered to the users + +use crate::api_data::res_get_ws_token::ResGetWsToken; +use crate::constants::WS_ACCESS_TOKEN_LENGTH; +use crate::data::base_request_handler::BaseRequestHandler; +use crate::data::error::ResultBoxError; +use crate::data::http_request_handler::HttpRequestHandler; +use crate::utils::crypt_utils::rand_str; +use crate::utils::date_utils::time; + +/// WebSocket access tokens list +mod ws_tokens_list { + use std::sync::Arc; + use std::sync::Mutex; + + use crate::constants::WS_ACCESS_TOKEN_LIFETIME; + use crate::data::user::UserID; + use crate::utils::date_utils::time; + + #[derive(Debug)] + pub struct WsToken { + pub time: u64, + pub client_id: u32, + pub user_id: UserID, + pub token: String, + pub incognito: bool, + } + + lazy_static! { + static ref WS_TOKENS: Arc>> = { + Arc::new(Mutex::new(Vec::new())) + }; + } + + /// Get the list of WebSocket tokens + fn get_list() -> Arc>> { + (*WS_TOKENS).clone() + } + + /// Remove old entries from the list + pub fn clean_list() { + let list = get_list(); + let mut list = list.lock().unwrap(); + + while let Some(first) = list.first() { + if first.time < time() - WS_ACCESS_TOKEN_LIFETIME { + list.remove(0); + } else { + break; + } + } + } + + /// Add a new token to the list + pub fn add_token(t: WsToken) { + get_list().lock().unwrap().push(t) + } + + /// Remove a specific access token from the list & return it + pub fn take_access_token(t: String) -> Option { + let list = get_list(); + let mut list = list.lock().unwrap(); + for i in 0..list.len() { + if list[i].token == t { + return Some(list.remove(i)); + } + } + + None + } +} + +/// Get a WebSocket access token +pub fn get_token(r: &mut HttpRequestHandler) -> ResultBoxError { + ws_tokens_list::clean_list(); + + let access_token = rand_str(WS_ACCESS_TOKEN_LENGTH); + + let token = ws_tokens_list::WsToken { + user_id: r.user_id()?, + client_id: r.api_client().id, + time: time(), + token: access_token.to_string(), + incognito: r.post_bool_opt("incognito", false), + }; + + ws_tokens_list::add_token(token); + + r.set_response(ResGetWsToken::new(access_token)) +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index 9f16414..840cc69 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,10 @@ +//! # Comunic Server Library +//! +//! This library contains all the logic of the Comunic Server. + +#[macro_use] +extern crate lazy_static; + pub mod data; pub mod helpers; pub mod controllers;