Serve certain endpoints on localhost
This commit is contained in:
parent
e9bacc93b2
commit
d99a5e3df6
|
@ -20,13 +20,6 @@ enum AuthorizationLevel {
|
|||
Moderator,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct RoomInfo {
|
||||
id: String,
|
||||
name: String,
|
||||
image_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct GenericStringResponse {
|
||||
pub status_code: u16,
|
||||
|
@ -35,14 +28,14 @@ pub struct GenericStringResponse {
|
|||
|
||||
// Rooms
|
||||
|
||||
// Currently not exposed
|
||||
pub async fn create_room(id: &str, name: &str) -> Result<Response, Rejection> {
|
||||
// Not publicly exposed.
|
||||
pub async fn create_room(room: models::Room) -> Result<Response, Rejection> {
|
||||
// Get a connection
|
||||
let pool = &storage::MAIN_POOL;
|
||||
let conn = pool.get().map_err(|_| Error::DatabaseFailedInternally)?;
|
||||
// Insert the room
|
||||
let stmt = format!("REPLACE INTO {} (id, name) VALUES (?1, ?2)", storage::MAIN_TABLE);
|
||||
match conn.execute(&stmt, params![id, name]) {
|
||||
match conn.execute(&stmt, params![&room.id, &room.name]) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("Couldn't create room due to error: {}.", e);
|
||||
|
@ -50,20 +43,20 @@ pub async fn create_room(id: &str, name: &str) -> Result<Response, Rejection> {
|
|||
}
|
||||
}
|
||||
// Set up the database
|
||||
storage::create_database_if_needed(id);
|
||||
storage::create_database_if_needed(&room.id);
|
||||
// Return
|
||||
let json = models::StatusCode { status_code: StatusCode::OK.as_u16() };
|
||||
return Ok(warp::reply::json(&json).into_response());
|
||||
}
|
||||
|
||||
// Currently not exposed
|
||||
pub async fn delete_room(id: &str) -> Result<Response, Rejection> {
|
||||
// Not publicly exposed.
|
||||
pub async fn delete_room(id: String) -> Result<Response, Rejection> {
|
||||
// Get a connection
|
||||
let pool = &storage::MAIN_POOL;
|
||||
let conn = pool.get().map_err(|_| Error::DatabaseFailedInternally)?;
|
||||
// Insert the room
|
||||
let stmt = format!("DELETE FROM {} WHERE id = (?1)", storage::MAIN_TABLE);
|
||||
match conn.execute(&stmt, params![id]) {
|
||||
match conn.execute(&stmt, params![&id]) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("Couldn't delete room due to error: {}.", e);
|
||||
|
@ -83,7 +76,7 @@ pub async fn get_room(room_id: &str) -> Result<Response, Rejection> {
|
|||
let raw_query =
|
||||
format!("SELECT id, name, image_id FROM {} where id = (?1)", storage::MAIN_TABLE);
|
||||
let room = match conn.query_row(&raw_query, params![room_id], |row| {
|
||||
Ok(RoomInfo { id: row.get(0)?, name: row.get(1)?, image_id: row.get(2).ok() })
|
||||
Ok(models::Room { id: row.get(0)?, name: row.get(1)?, image_id: row.get(2).ok() })
|
||||
}) {
|
||||
Ok(info) => info,
|
||||
Err(_) => return Err(warp::reject::custom(Error::NoSuchRoom)),
|
||||
|
@ -92,7 +85,7 @@ pub async fn get_room(room_id: &str) -> Result<Response, Rejection> {
|
|||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Response {
|
||||
status_code: u16,
|
||||
room: RoomInfo,
|
||||
room: models::Room,
|
||||
}
|
||||
let response = Response { status_code: StatusCode::OK.as_u16(), room };
|
||||
return Ok(warp::reply::json(&response).into_response());
|
||||
|
@ -106,7 +99,7 @@ pub async fn get_all_rooms() -> Result<Response, Rejection> {
|
|||
let raw_query = format!("SELECT id, name, image_id FROM {}", storage::MAIN_TABLE);
|
||||
let mut query = conn.prepare(&raw_query).map_err(|_| Error::DatabaseFailedInternally)?;
|
||||
let rows = match query.query_map(params![], |row| {
|
||||
Ok(RoomInfo { id: row.get(0)?, name: row.get(1)?, image_id: row.get(2).ok() })
|
||||
Ok(models::Room { id: row.get(0)?, name: row.get(1)?, image_id: row.get(2).ok() })
|
||||
}) {
|
||||
Ok(rows) => rows,
|
||||
Err(e) => {
|
||||
|
@ -114,12 +107,12 @@ pub async fn get_all_rooms() -> Result<Response, Rejection> {
|
|||
return Err(warp::reject::custom(Error::DatabaseFailedInternally));
|
||||
}
|
||||
};
|
||||
let rooms: Vec<RoomInfo> = rows.filter_map(|result| result.ok()).collect();
|
||||
let rooms: Vec<models::Room> = rows.filter_map(|result| result.ok()).collect();
|
||||
// Return
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct Response {
|
||||
status_code: u16,
|
||||
rooms: Vec<RoomInfo>,
|
||||
rooms: Vec<models::Room>,
|
||||
}
|
||||
let response = Response { status_code: StatusCode::OK.as_u16(), rooms };
|
||||
return Ok(warp::reply::json(&response).into_response());
|
||||
|
@ -603,13 +596,14 @@ pub async fn get_deleted_messages(
|
|||
|
||||
// Currently not exposed
|
||||
pub async fn make_public_key_moderator(
|
||||
public_key: &str, pool: &storage::DatabaseConnectionPool,
|
||||
body: models::AddModeratorRequestBody,
|
||||
) -> Result<Response, Rejection> {
|
||||
// Get a database connection
|
||||
let pool = storage::pool_by_room_id(&body.room_id);
|
||||
let conn = pool.get().map_err(|_| Error::DatabaseFailedInternally)?;
|
||||
// Insert the moderator
|
||||
let stmt = format!("INSERT INTO {} (public_key) VALUES (?1)", storage::MODERATORS_TABLE);
|
||||
match conn.execute(&stmt, params![public_key]) {
|
||||
match conn.execute(&stmt, params![&body.public_key]) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
println!("Couldn't make public key moderator due to error: {}.", e);
|
||||
|
|
62
src/main.rs
62
src/main.rs
|
@ -11,6 +11,7 @@ mod errors;
|
|||
mod handlers;
|
||||
mod models;
|
||||
mod onion_requests;
|
||||
mod options;
|
||||
mod routes;
|
||||
mod rpc;
|
||||
mod storage;
|
||||
|
@ -18,46 +19,12 @@ mod storage;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
// The default is * not * to run in TLS mode. This is because normally the server communicates through
|
||||
// onion requests, eliminating the need for TLS.
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(name = "Session Open Group Server")]
|
||||
struct Opt {
|
||||
/// Run in TLS mode.
|
||||
#[structopt(long)]
|
||||
tls: bool,
|
||||
|
||||
/// Path to TLS certificate.
|
||||
#[structopt(long = "tls-certificate", default_value = "tls_certificate.pem")]
|
||||
tls_certificate: String,
|
||||
|
||||
/// Path to TLS private key.
|
||||
#[structopt(long = "tls-private-key", default_value = "tls_private_key.pem")]
|
||||
tls_private_key: String,
|
||||
|
||||
/// Path to X25519 public key.
|
||||
#[structopt(long = "x25519-public-key", default_value = "x25519_public_key.pem")]
|
||||
x25519_public_key: String,
|
||||
|
||||
/// Path to X25519 private key.
|
||||
#[structopt(long = "x25519-private-key", default_value = "x25519_private_key.pem")]
|
||||
x25519_private_key: String,
|
||||
|
||||
/// Port to bind to.
|
||||
#[structopt(short = "P", long = "port", default_value = "80")]
|
||||
port: u16,
|
||||
|
||||
/// IP to bind to.
|
||||
#[structopt(short = "H", long = "host", default_value = "0.0.0.0")]
|
||||
host: Ipv4Addr,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
// Parse arguments
|
||||
let opt = Opt::from_args();
|
||||
let opt = options::Opt::from_args();
|
||||
let addr = SocketAddr::new(IpAddr::V4(opt.host), opt.port);
|
||||
let localhost = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 80);
|
||||
*crypto::PRIVATE_KEY_PATH.lock().unwrap() = opt.x25519_private_key;
|
||||
*crypto::PUBLIC_KEY_PATH.lock().unwrap() = opt.x25519_public_key;
|
||||
// Print the server public key
|
||||
|
@ -75,30 +42,36 @@ async fn main() {
|
|||
let prune_tokens_future = storage::prune_tokens_periodically();
|
||||
let prune_files_future = storage::prune_files_periodically();
|
||||
// Serve routes
|
||||
let routes = routes::root().or(routes::lsrpc());
|
||||
let public_routes = routes::root().or(routes::lsrpc());
|
||||
let private_routes =
|
||||
routes::create_room().or(routes::delete_room()).or(routes::add_moderator());
|
||||
if opt.tls {
|
||||
println!("Running on {} with TLS.", addr);
|
||||
let serve_routes_future = warp::serve(routes)
|
||||
let serve_public_routes_future = warp::serve(public_routes)
|
||||
.tls()
|
||||
.cert_path(opt.tls_certificate)
|
||||
.key_path(opt.tls_private_key)
|
||||
.run(addr);
|
||||
let serve_private_routes_future = warp::serve(private_routes).run(localhost);
|
||||
// Keep futures alive
|
||||
join!(
|
||||
prune_pending_tokens_future,
|
||||
prune_tokens_future,
|
||||
prune_files_future,
|
||||
serve_routes_future
|
||||
serve_public_routes_future,
|
||||
serve_private_routes_future
|
||||
);
|
||||
} else {
|
||||
println!("Running on {}.", addr);
|
||||
let serve_routes_future = warp::serve(routes).run(addr);
|
||||
let serve_public_routes_future = warp::serve(public_routes).run(addr);
|
||||
let serve_private_routes_future = warp::serve(private_routes).run(localhost);
|
||||
// Keep futures alive
|
||||
join!(
|
||||
prune_pending_tokens_future,
|
||||
prune_tokens_future,
|
||||
prune_files_future,
|
||||
serve_routes_future
|
||||
serve_public_routes_future,
|
||||
serve_private_routes_future
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -106,8 +79,9 @@ async fn main() {
|
|||
async fn create_default_rooms() {
|
||||
let info: Vec<(&str, &str)> = vec![("main", "Main")];
|
||||
for info in info {
|
||||
let id = info.0;
|
||||
let name = info.1;
|
||||
handlers::create_room(id, name).await.unwrap();
|
||||
let id = info.0.to_string();
|
||||
let name = info.1.to_string();
|
||||
let room = models::Room { id, name, image_id: None };
|
||||
handlers::create_room(room).await.unwrap();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,19 @@ impl Message {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Room {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub image_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct AddModeratorRequestBody {
|
||||
pub public_key: String,
|
||||
pub room_id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
pub struct Challenge {
|
||||
pub ciphertext: String,
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
use std::net::Ipv4Addr;
|
||||
|
||||
use structopt::StructOpt;
|
||||
|
||||
// The default is * not * to run in TLS mode. This is because normally the server communicates through
|
||||
// onion requests, eliminating the need for TLS.
|
||||
|
||||
#[derive(StructOpt)]
|
||||
#[structopt(name = "Session Open Group Server")]
|
||||
pub struct Opt {
|
||||
/// Path to X25519 public key.
|
||||
#[structopt(long = "x25519-public-key", default_value = "x25519_public_key.pem")]
|
||||
pub x25519_public_key: String,
|
||||
|
||||
/// Path to X25519 private key.
|
||||
#[structopt(long = "x25519-private-key", default_value = "x25519_private_key.pem")]
|
||||
pub x25519_private_key: String,
|
||||
|
||||
/// Port to bind to.
|
||||
#[structopt(short = "P", long = "port", default_value = "80")]
|
||||
pub port: u16,
|
||||
|
||||
/// IP to bind to.
|
||||
#[structopt(short = "H", long = "host", default_value = "0.0.0.0")]
|
||||
pub host: Ipv4Addr,
|
||||
|
||||
/// Run in TLS mode.
|
||||
#[structopt(long)]
|
||||
pub tls: bool,
|
||||
|
||||
/// Path to TLS certificate.
|
||||
#[structopt(long = "tls-certificate", default_value = "tls_certificate.pem")]
|
||||
pub tls_certificate: String,
|
||||
|
||||
/// Path to TLS private key.
|
||||
#[structopt(long = "tls-private-key", default_value = "tls_private_key.pem")]
|
||||
pub tls_private_key: String,
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use warp::{reply::Reply, reply::Response, Filter, Rejection};
|
||||
|
||||
use super::errors;
|
||||
use super::handlers;
|
||||
use super::onion_requests;
|
||||
|
||||
/// GET /
|
||||
|
@ -23,6 +24,33 @@ pub fn lsrpc() -> impl Filter<Extract = impl warp::Reply, Error = Rejection> + C
|
|||
.recover(into_response);
|
||||
}
|
||||
|
||||
/// POST /rooms
|
||||
///
|
||||
/// Not publicly exposed.
|
||||
pub fn create_room() -> impl Filter<Extract = impl warp::Reply, Error = Rejection> + Clone {
|
||||
return warp::post()
|
||||
.and(warp::path("rooms"))
|
||||
.and(warp::body::json())
|
||||
.and_then(handlers::create_room);
|
||||
}
|
||||
|
||||
/// DELETE /rooms/:id
|
||||
///
|
||||
/// Not publicly exposed.
|
||||
pub fn delete_room() -> impl Filter<Extract = impl warp::Reply, Error = Rejection> + Clone {
|
||||
return warp::delete().and(warp::path!("rooms" / String)).and_then(handlers::delete_room);
|
||||
}
|
||||
|
||||
/// POST /moderators
|
||||
///
|
||||
/// Not publicly exposed.
|
||||
pub fn add_moderator() -> impl Filter<Extract = impl warp::Reply, Error = Rejection> + Clone {
|
||||
return warp::post()
|
||||
.and(warp::path("moderators"))
|
||||
.and(warp::body::json())
|
||||
.and_then(handlers::make_public_key_moderator);
|
||||
}
|
||||
|
||||
pub async fn root_html() -> Result<Response, Rejection> {
|
||||
let body = r#"
|
||||
<html>
|
||||
|
|
|
@ -8,6 +8,7 @@ use super::handlers;
|
|||
use super::models;
|
||||
use super::storage;
|
||||
|
||||
#[allow(dead_code)]
|
||||
enum Mode {
|
||||
FileServer,
|
||||
OpenGroupServer,
|
||||
|
|
|
@ -8,6 +8,7 @@ use warp::http::StatusCode;
|
|||
|
||||
use super::crypto;
|
||||
use super::handlers;
|
||||
use super::models;
|
||||
use super::storage;
|
||||
|
||||
macro_rules! aw {
|
||||
|
@ -26,7 +27,12 @@ fn set_up_test_room() {
|
|||
perform_main_setup();
|
||||
let test_room_id = "test_room";
|
||||
let test_room_name = "Test Room";
|
||||
aw!(handlers::create_room(&test_room_id, &test_room_name)).unwrap();
|
||||
let test_room = models::Room {
|
||||
id: test_room_id.to_string(),
|
||||
name: test_room_name.to_string(),
|
||||
image_id: None,
|
||||
};
|
||||
aw!(handlers::create_room(test_room)).unwrap();
|
||||
let raw_path = format!("rooms/{}.db", test_room_id);
|
||||
let path = Path::new(&raw_path);
|
||||
fs::read(path).unwrap(); // Fail if this doesn't exist
|
||||
|
|
Loading…
Reference in New Issue