session-open-group-server/src/rpc.rs

158 lines
6.7 KiB
Rust
Raw Normal View History

2021-03-17 05:55:04 +01:00
use std::collections::HashMap;
2021-03-12 08:55:37 +01:00
use serde::{Serialize, Deserialize};
2021-03-12 05:46:06 +01:00
use warp::{Rejection, reply::Response};
2021-03-12 05:11:12 +01:00
2021-03-12 06:40:24 +01:00
use super::errors::Error;
2021-03-12 05:11:12 +01:00
use super::handlers;
use super::storage;
2021-03-12 08:55:37 +01:00
#[derive(Deserialize, Serialize, Debug)]
pub struct RpcCall {
pub endpoint: String,
pub body: String,
2021-03-17 05:55:04 +01:00
pub method: String,
pub headers: String
2021-03-12 08:55:37 +01:00
}
2021-03-12 05:11:12 +01:00
#[derive(Debug, Deserialize)]
pub struct QueryOptions {
pub limit: Option<u16>,
pub from_server_id: Option<i64>
}
2021-03-12 08:55:37 +01:00
pub async fn handle_rpc_call(rpc_call: RpcCall, pool: &storage::DatabaseConnectionPool) -> Result<Response, Rejection> {
2021-03-12 05:11:12 +01:00
// Check that the endpoint is a valid URI
let uri = match rpc_call.endpoint.parse::<http::Uri>() {
Ok(uri) => uri,
Err(e) => {
2021-03-12 08:55:37 +01:00
println!("Couldn't parse URI from: {} due to error: {}.", rpc_call.endpoint, e);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
};
2021-03-17 23:35:51 +01:00
// Get the auth token if possible
let auth_token = get_auth_token(&rpc_call);
2021-03-12 05:11:12 +01:00
// Switch on the HTTP method
match rpc_call.method.as_ref() {
2021-03-17 23:35:51 +01:00
"GET" => return handle_get_request(rpc_call, uri, auth_token, pool).await,
"POST" => return handle_post_request(rpc_call, uri, auth_token, pool).await,
"DELETE" => return handle_delete_request(rpc_call, uri, auth_token, pool).await,
2021-03-12 05:11:12 +01:00
_ => {
2021-03-12 08:55:37 +01:00
println!("Ignoring RPC call with invalid or unused HTTP method: {}.", rpc_call.method);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
}
}
2021-03-17 23:35:51 +01:00
async fn handle_get_request(rpc_call: RpcCall, uri: http::Uri, auth_token: Option<String>, pool: &storage::DatabaseConnectionPool) -> Result<Response, Rejection> {
2021-03-12 05:11:12 +01:00
// Parse query options if needed
let mut query_options = QueryOptions { limit : None, from_server_id : None };
if let Some(query) = uri.query() {
query_options = match serde_json::from_str(&query) {
Ok(query_options) => query_options,
Err(e) => {
2021-03-12 08:55:37 +01:00
println!("Couldn't parse query options from: {} due to error: {}.", query, e);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
};
}
// Switch on the path
match uri.path() {
"/messages" => return handlers::get_messages(query_options, pool).await,
"/deleted_messages" => return handlers::get_deleted_messages(query_options, pool).await,
"/moderators" => return handlers::get_moderators(pool).await,
"/block_list" => return handlers::get_banned_public_keys(pool).await,
"/member_count" => return handlers::get_member_count(pool).await,
2021-03-17 01:51:11 +01:00
"/challenge" => {
2021-03-17 01:58:59 +01:00
#[derive(Debug, Deserialize)]
pub struct QueryOptions {
pub public_key: String
2021-03-17 01:51:11 +01:00
}
2021-03-17 01:58:59 +01:00
let query_options: QueryOptions;
if let Some(query) = uri.query() {
query_options = match serde_json::from_str(&query) {
Ok(query_options) => query_options,
Err(e) => {
println!("Couldn't parse query options from: {} due to error: {}.", query, e);
return Err(warp::reject::custom(Error::InvalidRpcCall));
}
};
} else {
println!("Missing query options.");
return Err(warp::reject::custom(Error::InvalidRpcCall));
}
return handlers::get_challenge(&query_options.public_key, pool).await;
2021-03-17 01:51:11 +01:00
},
2021-03-12 05:11:12 +01:00
_ => {
2021-03-12 08:55:37 +01:00
println!("Ignoring RPC call with invalid or unused endpoint: {}.", rpc_call.endpoint);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
}
}
2021-03-17 23:35:51 +01:00
async fn handle_post_request(rpc_call: RpcCall, uri: http::Uri, auth_token: Option<String>, pool: &storage::DatabaseConnectionPool) -> Result<Response, Rejection> {
2021-03-12 05:11:12 +01:00
match uri.path() {
"/messages" => {
let message = match serde_json::from_str(&rpc_call.body) {
2021-03-17 01:51:11 +01:00
Ok(message) => message,
2021-03-12 05:11:12 +01:00
Err(e) => {
2021-03-12 08:55:37 +01:00
println!("Couldn't parse message from: {} due to error: {}.", rpc_call.body, e);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
};
2021-03-17 23:35:51 +01:00
return handlers::insert_message(message, auth_token, pool).await;
2021-03-12 05:11:12 +01:00
},
2021-03-12 05:32:41 +01:00
"/block_list" => {
let public_key = rpc_call.body;
2021-03-17 23:35:51 +01:00
return handlers::ban(&public_key, auth_token, pool).await;
2021-03-12 05:32:41 +01:00
},
2021-03-12 05:11:12 +01:00
_ => {
2021-03-12 08:55:37 +01:00
println!("Ignoring RPC call with invalid or unused endpoint: {}.", rpc_call.endpoint);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
}
}
2021-03-17 23:35:51 +01:00
async fn handle_delete_request(rpc_call: RpcCall, uri: http::Uri, auth_token: Option<String>, pool: &storage::DatabaseConnectionPool) -> Result<Response, Rejection> {
2021-03-12 05:11:12 +01:00
// DELETE /messages/:server_id
if uri.path().starts_with("/messages") {
let components: Vec<&str> = uri.path()[1..].split("/").collect(); // Drop the leading slash and split on subsequent slashes
if components.len() != 2 {
2021-03-12 08:55:37 +01:00
println!("Invalid endpoint: {}.", rpc_call.endpoint);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
let server_id: i64 = match components[1].parse() {
Ok(server_id) => server_id,
2021-03-12 05:46:06 +01:00
Err(_) => {
2021-03-12 08:55:37 +01:00
println!("Invalid endpoint: {}.", rpc_call.endpoint);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
};
2021-03-17 23:35:51 +01:00
return handlers::delete_message(server_id, auth_token, pool).await;
2021-03-12 05:11:12 +01:00
}
// DELETE /block_list/:public_key
if uri.path().starts_with("/block_list") {
let components: Vec<&str> = uri.path()[1..].split("/").collect(); // Drop the leading slash and split on subsequent slashes
if components.len() != 2 {
2021-03-12 08:55:37 +01:00
println!("Invalid endpoint: {}.", rpc_call.endpoint);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
let public_key = components[1].to_string();
2021-03-17 23:35:51 +01:00
return handlers::unban(&public_key, auth_token, pool).await;
2021-03-12 05:11:12 +01:00
}
// Unrecognized endpoint
2021-03-12 08:55:37 +01:00
println!("Ignoring RPC call with invalid or unused endpoint: {}.", rpc_call.endpoint);
return Err(warp::reject::custom(Error::InvalidRpcCall));
2021-03-12 05:11:12 +01:00
}
2021-03-17 05:55:04 +01:00
// Utilities
2021-03-17 23:35:51 +01:00
fn get_auth_token(rpc_call: &RpcCall) -> Option<String> {
2021-03-17 05:55:04 +01:00
if rpc_call.headers.is_empty() { return None; }
let headers: HashMap<String, String> = match serde_json::from_str(&rpc_call.headers) {
Ok(headers) => headers,
2021-03-17 23:35:51 +01:00
Err(_) => return None
2021-03-17 05:55:04 +01:00
};
let header = headers.get("Authorization");
if header == None { return None; }
return header.unwrap().strip_prefix("Bearer").map(|s| s.to_string()).or(None);
}