From 1de4b2eb2d5130504c4a20ee42a2f05829e9f19b Mon Sep 17 00:00:00 2001 From: Yauhen Pahrabniak Date: Thu, 14 Dec 2023 14:59:06 +0100 Subject: [PATCH 1/4] Added authentication and registration --- Cargo.lock | 49 +++++ common/Cargo.toml | 1 + .../migrations/2023-02-01-210714_init/up.sql | 6 + common/src/db/mod.rs | 73 ++++++- common/src/db/schema_auto.rs | 9 + lumen/src/main.rs | 206 ++++++++++++------ 6 files changed, 272 insertions(+), 72 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index afa4e16..1861779 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -138,6 +138,19 @@ dependencies = [ "tokio", ] +[[package]] +name = "bcrypt" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d1c9c15093eb224f0baa400f38fcd713fc1391a6f1c389d886beef146d60a3" +dependencies = [ + "base64 0.21.2", + "blowfish", + "getrandom", + "subtle", + "zeroize", +] + [[package]] name = "binascii" version = "0.1.4" @@ -165,6 +178,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "byteorder" version = "1.4.3" @@ -192,6 +215,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "4.3.22" @@ -230,6 +263,7 @@ name = "common" version = "0.2.0" dependencies = [ "anyhow", + "bcrypt", "binascii", "diesel", "diesel-async", @@ -724,6 +758,15 @@ dependencies = [ "hashbrown 0.14.0", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -1942,3 +1985,9 @@ checksum = "83817bbecf72c73bad717ee86820ebf286203d2e04c3951f3cd538869c897364" dependencies = [ "memchr", ] + +[[package]] +name = "zeroize" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" diff --git a/common/Cargo.toml b/common/Cargo.toml index 12f372e..379d679 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -22,6 +22,7 @@ diesel = {version = "2.1", optional = true, default-features = false, features = diesel-async = {version = "0.3", optional = true, features = ["postgres", "bb8"]} anyhow = "1.0" prometheus-client = "0.21.2" +bcrypt = "0.15.0" [features] default = ["web", "db"] diff --git a/common/migrations/2023-02-01-210714_init/up.sql b/common/migrations/2023-02-01-210714_init/up.sql index c545f5a..e89f6de 100644 --- a/common/migrations/2023-02-01-210714_init/up.sql +++ b/common/migrations/2023-02-01-210714_init/up.sql @@ -37,3 +37,9 @@ CREATE TABLE IF NOT EXISTS funcs ( CREATE UNIQUE INDEX IF NOT EXISTS funcs_db ON funcs(chksum, db_id); CREATE INDEX IF NOT EXISTS funcs_ranking ON funcs(chksum,rank); CREATE INDEX IF NOT EXISTS func_chksum ON funcs(chksum); + +CREATE TABLE IF NOT EXISTS auth_users ( + id SERIAL PRIMARY KEY, + username VARCHAR(32) NOT NULL UNIQUE, + password_hash VARCHAR(128) NOT NULL +); diff --git a/common/src/db/mod.rs b/common/src/db/mod.rs index 8f83bbc..8899be1 100644 --- a/common/src/db/mod.rs +++ b/common/src/db/mod.rs @@ -3,11 +3,12 @@ use postgres_native_tls::MakeTlsConnector; use serde::Serialize; use tokio_postgres::{tls::MakeTlsConnect, Socket, NoTls}; use std::{collections::HashMap}; +use bcrypt::{hash, verify, DEFAULT_COST}; use crate::async_drop::{AsyncDropper, AsyncDropGuard}; mod schema_auto; pub mod schema; -use diesel::{upsert::excluded, ExpressionMethods, QueryDsl, NullableExpressionMethods, sql_types::{Array, Binary, VarChar, Integer}, query_builder::{QueryFragment, Query}}; +use diesel::{upsert::excluded, ExpressionMethods, QueryDsl, NullableExpressionMethods, sql_types::{Array, Binary, VarChar, Integer}, query_builder::{QueryFragment, Query}, result::Error::NotFound}; use diesel_async::RunQueryDsl; pub type DynConfig = dyn crate::config::HasConfig + Send + Sync; @@ -337,6 +338,76 @@ impl Database { Ok(results) } + pub async fn register_user(&self, username: &str, password: &str) -> Result<(), anyhow::Error> { + let conn = &mut self.diesel.get().await?; + + // Hash the password + let hashed_password = hash(password, DEFAULT_COST)?; + + // Insert new user + diesel::insert_into(schema::auth_users::table) + .values(( + schema::auth_users::username.eq(username), + schema::auth_users::password_hash.eq(hashed_password), + )) + .execute(conn) + .await?; + + Ok(()) + } + + pub async fn change_user_password(&self, username: &str, new_password: &str) -> Result<(), anyhow::Error> { + let conn = &mut self.diesel.get().await?; + + // Hash the new password + let hashed_password = hash(new_password, DEFAULT_COST)?; + + // Update the user's password + diesel::update(schema::auth_users::table.filter(schema::auth_users::username.eq(username))) + .set(schema::auth_users::password_hash.eq(hashed_password)) + .execute(conn) + .await?; + + Ok(()) + } + + pub async fn remove_user(&self, username: &str) -> Result<(), anyhow::Error> { + let conn = &mut self.diesel.get().await?; + + // Execute the delete query + diesel::delete(schema::auth_users::table.filter(schema::auth_users::username.eq(username))) + .execute(conn) + .await?; + + Ok(()) + } + + pub async fn auth_user(&self, login: &str, password: &str) -> Result { + let conn = &mut self.diesel.get().await?; + + match schema::auth_users::table + .select((schema::auth_users::username, schema::auth_users::password_hash)) + .filter(schema::auth_users::username.eq(login)) + .first::<(String, String)>(conn) + .await { + Ok((_, password_hash)) => { + // If user is found, verify the password + match verify(password, &password_hash) { + Ok(valid) => Ok(valid), + Err(e) => Err(anyhow::Error::new(e)), + } + }, + Err(diesel::result::Error::NotFound) => { + // If user is not found, return false + Ok(false) + }, + Err(e) => { + // For all other errors, return the error + Err(anyhow::Error::new(e)) + } + } + } + pub async fn get_files_with_func(&self, func: &[u8]) -> Result>, anyhow::Error> { let conn = &mut self.diesel.get().await?; diff --git a/common/src/db/schema_auto.rs b/common/src/db/schema_auto.rs index 3700def..ccd69b2 100644 --- a/common/src/db/schema_auto.rs +++ b/common/src/db/schema_auto.rs @@ -1,5 +1,13 @@ // @generated automatically by Diesel CLI. +diesel::table! { + auth_users (id) { + id -> Int4, + username -> Varchar, + password_hash -> Varchar, + } +} + diesel::table! { dbs (id) { id -> Int4, @@ -46,6 +54,7 @@ diesel::joinable!(dbs -> users (user_id)); diesel::joinable!(funcs -> dbs (db_id)); diesel::allow_tables_to_appear_in_same_query!( + auth_users, dbs, files, funcs, diff --git a/lumen/src/main.rs b/lumen/src/main.rs index adc649e..637b141 100644 --- a/lumen/src/main.rs +++ b/lumen/src/main.rs @@ -200,11 +200,14 @@ async fn handle_client(state: &SharedState, m }).inc(); if let Some(ref creds) = creds { - if creds.username != "guest" { + + let auth_state = state.db.auth_user(creds.username, creds.password).await; + + if !auth_state.is_ok() || !auth_state.unwrap() { // Only allow "guest" to connect for now. rpc::RpcMessage::Fail(rpc::RpcFail { code: 1, - message: &format!("{server_name}: invalid username or password. Try logging in with `guest` instead."), + message: &format!("{server_name}: invalid username or password."), }).async_write(&mut stream).await?; return Ok(()); } @@ -329,6 +332,33 @@ fn main() { .default_value("config.toml") .help("Configuration file path") ) + .subcommand( + clap::Command::new("add_user") + .about("Adds a new user") + .arg(Arg::new("username") + .help("The username for the new user") + .required(true)) + .arg(Arg::new("password") + .help("The password for the new user") + .required(true)) + ) + .subcommand( + clap::Command::new("change_user_pass") + .about("Changes a user's password") + .arg(Arg::new("username") + .help("The username of the user") + .required(true)) + .arg(Arg::new("new_password") + .help("The new password for the user") + .required(true)) + ) + .subcommand( + clap::Command::new("remove_user") + .about("Removes user") + .arg(Arg::new("username") + .help("The username of the user") + .required(true)) + ) .get_matches(); let config = { @@ -347,7 +377,7 @@ fn main() { exit(1); }, }; - + let db = rt.block_on(async { match Database::open(&config.database).await { Ok(v) => v, @@ -367,80 +397,114 @@ fn main() { metrics: common::metrics::Metrics::default(), }); - let tls_acceptor; + let subcommand_future = async { + match matches.subcommand() { + Some(("add_user", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); + let password = sub_m.get_one::("password").unwrap(); - if state.config.lumina.use_tls.unwrap_or_default() { - let cert_path = &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert; - let mut crt = match std::fs::read(cert_path) { - Ok(v) => v, - Err(err) => { - error!("failed to read certificate file: {}", err); - exit(1); - } - }; - let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default(); - let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) { - Ok(v) => v, - Err(err) => { - error!("failed to parse tls certificate: {}", err); - exit(1); - } - }; - let _ = pkcs_passwd; - crt.iter_mut().for_each(|v| *v = 0); - let _ = crt; - let mut accpt = native_tls::TlsAcceptor::builder(id); - accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3)); - let accpt = match accpt.build() { - Ok(v) => v, - Err(err) => { - error!("failed to build tls acceptor: {}", err); - exit(1); + state.db.register_user(username, password).await; }, - }; - let accpt = tokio_native_tls::TlsAcceptor::from(accpt); - tls_acceptor = Some(accpt); - } else { - tls_acceptor = None; - } + Some(("change_user_pass", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); + let new_password = sub_m.get_one::("new_password").unwrap(); - let web_handle = if let Some(ref webcfg) = state.config.api_server { - let bind_addr = webcfg.bind_addr; - let state = state.clone(); - info!("starting http api server on {:?}", &bind_addr); - Some(rt.spawn(async move { - web::start_webserver(bind_addr, state).await; - })) - } else { - None - }; - - let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>(); + state.db.change_user_password(username, new_password).await; + }, + Some(("remove_user", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); - let async_server = async move { - let server = match TcpListener::bind(state.config.lumina.bind_addr).await { - Ok(v) => v, - Err(err) => { - error!("failed to bind server port: {}", err); - exit(1); + state.db.remove_user(username).await; }, - }; + _ => { + let tls_acceptor; + if state.config.lumina.use_tls.unwrap_or_default() { + let cert_path = &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert; + let mut crt = match std::fs::read(cert_path) { + Ok(v) => v, + Err(err) => { + error!("failed to read certificate file: {}", err); + exit(1); + } + }; + let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default(); + let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) { + Ok(v) => v, + Err(err) => { + error!("failed to parse tls certificate: {}", err); + exit(1); + } + }; + let _ = pkcs_passwd; + crt.iter_mut().for_each(|v| *v = 0); + let _ = crt; + let mut accpt = native_tls::TlsAcceptor::builder(id); + accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3)); + let accpt = match accpt.build() { + Ok(v) => v, + Err(err) => { + error!("failed to build tls acceptor: {}", err); + exit(1); + }, + }; + let accpt = tokio_native_tls::TlsAcceptor::from(accpt); + tls_acceptor = Some(accpt); + } else { + tls_acceptor = None; + } - info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some()); - - serve(server, tls_acceptor, state, exit_signal_rx).await; - }; + let web_handle = if let Some(ref webcfg) = state.config.api_server { + let bind_addr = webcfg.bind_addr; + let state = state.clone(); + info!("starting http api server on {:?}", &bind_addr); + Some(rt.spawn(async move { + web::start_webserver(bind_addr, state).await; + })) + } else { + None + }; + + let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>(); + + let async_server = async move { + let server = match TcpListener::bind(state.config.lumina.bind_addr).await { + Ok(v) => v, + Err(err) => { + error!("failed to bind server port: {}", err); + exit(1); + }, + }; + + info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some()); + + serve(server, tls_acceptor, state, exit_signal_rx).await; + }; - rt.block_on(async { - let server_handle = tokio::task::spawn(async_server); - tokio::signal::ctrl_c().await.unwrap(); - debug!("CTRL-C; exiting..."); - if let Some(handle) = web_handle { - handle.abort(); + rt.block_on(async { + let server_handle = tokio::task::spawn(async_server); + tokio::signal::ctrl_c().await.unwrap(); + debug!("CTRL-C; exiting..."); + if let Some(handle) = web_handle { + handle.abort(); + } + exit_signal_tx.send(()).unwrap(); + server_handle.await.unwrap(); + }); + drop(rt); + info!("Goodbye."); + } } - exit_signal_tx.send(()).unwrap(); - server_handle.await.unwrap(); - }); - drop(rt); - info!("Goodbye."); + }; + + let rt = match tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() { + Ok(v) => v, + Err(err) => { + error!("failed to create tokio runtime: {}", err); + exit(1); + }, + }; + + rt.block_on(subcommand_future); } From 6994b2756a79846ad3cf126a6266f8c414031366 Mon Sep 17 00:00:00 2001 From: Yauhen Pahrabniak Date: Thu, 14 Dec 2023 15:12:49 +0100 Subject: [PATCH 2/4] Fatal error fix --- lumen/src/main.rs | 184 +++++++++++++++++++++------------------------- 1 file changed, 85 insertions(+), 99 deletions(-) diff --git a/lumen/src/main.rs b/lumen/src/main.rs index 637b141..39ba8b5 100644 --- a/lumen/src/main.rs +++ b/lumen/src/main.rs @@ -397,114 +397,100 @@ fn main() { metrics: common::metrics::Metrics::default(), }); - let subcommand_future = async { - match matches.subcommand() { - Some(("add_user", sub_m)) => { - let username = sub_m.get_one::("username").unwrap(); - let password = sub_m.get_one::("password").unwrap(); + match matches.subcommand() { + Some(("add_user", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); + let password = sub_m.get_one::("password").unwrap(); - state.db.register_user(username, password).await; - }, - Some(("change_user_pass", sub_m)) => { - let username = sub_m.get_one::("username").unwrap(); - let new_password = sub_m.get_one::("new_password").unwrap(); - - state.db.change_user_password(username, new_password).await; - }, - Some(("remove_user", sub_m)) => { - let username = sub_m.get_one::("username").unwrap(); + state.db.register_user(username, password); + }, + Some(("change_user_pass", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); + let new_password = sub_m.get_one::("new_password").unwrap(); - state.db.remove_user(username).await; - }, - _ => { - let tls_acceptor; - if state.config.lumina.use_tls.unwrap_or_default() { - let cert_path = &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert; - let mut crt = match std::fs::read(cert_path) { - Ok(v) => v, - Err(err) => { - error!("failed to read certificate file: {}", err); - exit(1); - } - }; - let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default(); - let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) { - Ok(v) => v, - Err(err) => { - error!("failed to parse tls certificate: {}", err); - exit(1); - } - }; - let _ = pkcs_passwd; - crt.iter_mut().for_each(|v| *v = 0); - let _ = crt; - let mut accpt = native_tls::TlsAcceptor::builder(id); - accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3)); - let accpt = match accpt.build() { - Ok(v) => v, - Err(err) => { - error!("failed to build tls acceptor: {}", err); - exit(1); - }, - }; - let accpt = tokio_native_tls::TlsAcceptor::from(accpt); - tls_acceptor = Some(accpt); - } else { - tls_acceptor = None; - } + state.db.change_user_password(username, new_password); + }, + Some(("remove_user", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); - let web_handle = if let Some(ref webcfg) = state.config.api_server { - let bind_addr = webcfg.bind_addr; - let state = state.clone(); - info!("starting http api server on {:?}", &bind_addr); - Some(rt.spawn(async move { - web::start_webserver(bind_addr, state).await; - })) - } else { - None + state.db.remove_user(username); + }, + _ => { + let tls_acceptor; + if state.config.lumina.use_tls.unwrap_or_default() { + let cert_path = &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert; + let mut crt = match std::fs::read(cert_path) { + Ok(v) => v, + Err(err) => { + error!("failed to read certificate file: {}", err); + exit(1); + } }; + let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default(); + let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) { + Ok(v) => v, + Err(err) => { + error!("failed to parse tls certificate: {}", err); + exit(1); + } + }; + let _ = pkcs_passwd; + crt.iter_mut().for_each(|v| *v = 0); + let _ = crt; + let mut accpt = native_tls::TlsAcceptor::builder(id); + accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3)); + let accpt = match accpt.build() { + Ok(v) => v, + Err(err) => { + error!("failed to build tls acceptor: {}", err); + exit(1); + }, + }; + let accpt = tokio_native_tls::TlsAcceptor::from(accpt); + tls_acceptor = Some(accpt); + } else { + tls_acceptor = None; + } - let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>(); - - let async_server = async move { - let server = match TcpListener::bind(state.config.lumina.bind_addr).await { - Ok(v) => v, - Err(err) => { - error!("failed to bind server port: {}", err); - exit(1); - }, - }; + let web_handle = if let Some(ref webcfg) = state.config.api_server { + let bind_addr = webcfg.bind_addr; + let state = state.clone(); + info!("starting http api server on {:?}", &bind_addr); + Some(rt.spawn(async move { + web::start_webserver(bind_addr, state).await; + })) + } else { + None + }; - info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some()); + let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>(); - serve(server, tls_acceptor, state, exit_signal_rx).await; + let async_server = async move { + let server = match TcpListener::bind(state.config.lumina.bind_addr).await { + Ok(v) => v, + Err(err) => { + error!("failed to bind server port: {}", err); + exit(1); + }, }; - rt.block_on(async { - let server_handle = tokio::task::spawn(async_server); - tokio::signal::ctrl_c().await.unwrap(); - debug!("CTRL-C; exiting..."); - if let Some(handle) = web_handle { - handle.abort(); - } - exit_signal_tx.send(()).unwrap(); - server_handle.await.unwrap(); - }); - drop(rt); - info!("Goodbye."); - } - } - }; + info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some()); - let rt = match tokio::runtime::Builder::new_multi_thread() - .enable_all() - .build() { - Ok(v) => v, - Err(err) => { - error!("failed to create tokio runtime: {}", err); - exit(1); - }, - }; + serve(server, tls_acceptor, state, exit_signal_rx).await; + }; - rt.block_on(subcommand_future); + rt.block_on(async { + let server_handle = tokio::task::spawn(async_server); + tokio::signal::ctrl_c().await.unwrap(); + debug!("CTRL-C; exiting..."); + if let Some(handle) = web_handle { + handle.abort(); + } + exit_signal_tx.send(()).unwrap(); + server_handle.await.unwrap(); + }); + drop(rt); + info!("Goodbye."); + } + } } From 89d5062f381d3039d58c37f84e1b56b9ee0de921 Mon Sep 17 00:00:00 2001 From: Yauhen Pahrabniak Date: Thu, 14 Dec 2023 15:23:36 +0100 Subject: [PATCH 3/4] Fixes --- lumen/src/main.rs | 188 +++++++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 85 deletions(-) diff --git a/lumen/src/main.rs b/lumen/src/main.rs index 39ba8b5..b0a3931 100644 --- a/lumen/src/main.rs +++ b/lumen/src/main.rs @@ -397,100 +397,118 @@ fn main() { metrics: common::metrics::Metrics::default(), }); - match matches.subcommand() { - Some(("add_user", sub_m)) => { - let username = sub_m.get_one::("username").unwrap(); - let password = sub_m.get_one::("password").unwrap(); + let subcommand_future = async { + match matches.subcommand() { + Some(("add_user", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); + let password = sub_m.get_one::("password").unwrap(); + + match state.db.register_user(username, password).await { + Ok(_) => println!("User added successfully"), + Err(e) => eprintln!("Error adding user: {}", e), + } + exit(0); + }, + Some(("change_user_pass", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); + let new_password = sub_m.get_one::("new_password").unwrap(); - state.db.register_user(username, password); - }, - Some(("change_user_pass", sub_m)) => { - let username = sub_m.get_one::("username").unwrap(); - let new_password = sub_m.get_one::("new_password").unwrap(); + match state.db.change_user_password(username, new_password).await { + Ok(_) => println!("User password changed successfully"), + Err(e) => eprintln!("Error changing user password: {}", e), + } + exit(0); + }, + Some(("remove_user", sub_m)) => { + let username = sub_m.get_one::("username").unwrap(); - state.db.change_user_password(username, new_password); - }, - Some(("remove_user", sub_m)) => { - let username = sub_m.get_one::("username").unwrap(); + match state.db.remove_user(username).await { + Ok(_) => println!("User removed successfully"), + Err(e) => eprintln!("Error removing user: {}", e), + } + exit(0); + }, + _ => { + + } + } + }; - state.db.remove_user(username); - }, - _ => { - let tls_acceptor; - if state.config.lumina.use_tls.unwrap_or_default() { - let cert_path = &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert; - let mut crt = match std::fs::read(cert_path) { - Ok(v) => v, - Err(err) => { - error!("failed to read certificate file: {}", err); - exit(1); - } - }; - let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default(); - let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) { - Ok(v) => v, - Err(err) => { - error!("failed to parse tls certificate: {}", err); - exit(1); - } - }; - let _ = pkcs_passwd; - crt.iter_mut().for_each(|v| *v = 0); - let _ = crt; - let mut accpt = native_tls::TlsAcceptor::builder(id); - accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3)); - let accpt = match accpt.build() { - Ok(v) => v, - Err(err) => { - error!("failed to build tls acceptor: {}", err); - exit(1); - }, - }; - let accpt = tokio_native_tls::TlsAcceptor::from(accpt); - tls_acceptor = Some(accpt); - } else { - tls_acceptor = None; + rt.block_on(subcommand_future); + + let tls_acceptor; + if state.config.lumina.use_tls.unwrap_or_default() { + let cert_path = &state.config.lumina.tls.as_ref().expect("tls section is missing").server_cert; + let mut crt = match std::fs::read(cert_path) { + Ok(v) => v, + Err(err) => { + error!("failed to read certificate file: {}", err); + exit(1); + } + }; + let pkcs_passwd = std::env::var("PKCSPASSWD").unwrap_or_default(); + let id = match Identity::from_pkcs12(&crt, &pkcs_passwd) { + Ok(v) => v, + Err(err) => { + error!("failed to parse tls certificate: {}", err); + exit(1); } + }; + let _ = pkcs_passwd; + crt.iter_mut().for_each(|v| *v = 0); + let _ = crt; + let mut accpt = native_tls::TlsAcceptor::builder(id); + accpt.min_protocol_version(Some(native_tls::Protocol::Sslv3)); + let accpt = match accpt.build() { + Ok(v) => v, + Err(err) => { + error!("failed to build tls acceptor: {}", err); + exit(1); + }, + }; + let accpt = tokio_native_tls::TlsAcceptor::from(accpt); + tls_acceptor = Some(accpt); + } else { + tls_acceptor = None; + } - let web_handle = if let Some(ref webcfg) = state.config.api_server { - let bind_addr = webcfg.bind_addr; - let state = state.clone(); - info!("starting http api server on {:?}", &bind_addr); - Some(rt.spawn(async move { - web::start_webserver(bind_addr, state).await; - })) - } else { - None - }; + let web_handle = if let Some(ref webcfg) = state.config.api_server { + let bind_addr = webcfg.bind_addr; + let state = state.clone(); + info!("starting http api server on {:?}", &bind_addr); + Some(rt.spawn(async move { + web::start_webserver(bind_addr, state).await; + })) + } else { + None + }; - let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>(); + let (exit_signal_tx, exit_signal_rx) = tokio::sync::oneshot::channel::<()>(); - let async_server = async move { - let server = match TcpListener::bind(state.config.lumina.bind_addr).await { - Ok(v) => v, - Err(err) => { - error!("failed to bind server port: {}", err); - exit(1); - }, - }; + let async_server = async move { + let server = match TcpListener::bind(state.config.lumina.bind_addr).await { + Ok(v) => v, + Err(err) => { + error!("failed to bind server port: {}", err); + exit(1); + }, + }; - info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some()); + info!("listening on {:?} secure={}", server.local_addr().unwrap(), tls_acceptor.is_some()); - serve(server, tls_acceptor, state, exit_signal_rx).await; - }; + serve(server, tls_acceptor, state, exit_signal_rx).await; + }; - rt.block_on(async { - let server_handle = tokio::task::spawn(async_server); - tokio::signal::ctrl_c().await.unwrap(); - debug!("CTRL-C; exiting..."); - if let Some(handle) = web_handle { - handle.abort(); - } - exit_signal_tx.send(()).unwrap(); - server_handle.await.unwrap(); - }); - drop(rt); - info!("Goodbye."); + rt.block_on(async { + let server_handle = tokio::task::spawn(async_server); + tokio::signal::ctrl_c().await.unwrap(); + debug!("CTRL-C; exiting..."); + if let Some(handle) = web_handle { + handle.abort(); } - } + exit_signal_tx.send(()).unwrap(); + server_handle.await.unwrap(); + }); + drop(rt); + info!("Goodbye."); } From aa08defd465878e92a7b1fa0935e21f915420fd8 Mon Sep 17 00:00:00 2001 From: Yauhen Pahrabniak Date: Thu, 14 Dec 2023 15:25:47 +0100 Subject: [PATCH 4/4] Don't pass without username and password --- lumen/src/main.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lumen/src/main.rs b/lumen/src/main.rs index b0a3931..03b68d0 100644 --- a/lumen/src/main.rs +++ b/lumen/src/main.rs @@ -212,6 +212,13 @@ async fn handle_client(state: &SharedState, m return Ok(()); } } + else { + rpc::RpcMessage::Fail(rpc::RpcFail { + code: 1, + message: &format!("{server_name}: username and password should be specified."), + }).async_write(&mut stream).await?; + return Ok(()); + } let resp = match hello.protocol_version { 0..=4 => rpc::RpcMessage::Ok(()),