added code for creating new owner accounts, and for dealing with some commandline arguments
This commit is contained in:
parent
34ac3709f7
commit
99ccb14bf2
@ -1,6 +1,8 @@
|
|||||||
extern crate chrono;
|
extern crate chrono;
|
||||||
|
extern crate clap;
|
||||||
extern crate dotenv;
|
extern crate dotenv;
|
||||||
extern crate getrandom;
|
extern crate getrandom;
|
||||||
|
extern crate bcrypt;
|
||||||
extern crate base64;
|
extern crate base64;
|
||||||
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
@ -16,7 +18,11 @@ use hyper::{
|
|||||||
service::{make_service_fn, service_fn}
|
service::{make_service_fn, service_fn}
|
||||||
};
|
};
|
||||||
use mysql_async::Pool;
|
use mysql_async::Pool;
|
||||||
|
use mysql_async::prelude::Queryable;
|
||||||
|
|
||||||
use dotenv::dotenv;
|
use dotenv::dotenv;
|
||||||
|
use clap::{Arg, App};
|
||||||
|
use chrono::Utc;
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
use auth::AuthReason;
|
use auth::AuthReason;
|
||||||
@ -24,12 +30,19 @@ use auth::AuthReason;
|
|||||||
mod routes;
|
mod routes;
|
||||||
mod invites;
|
mod invites;
|
||||||
mod channels;
|
mod channels;
|
||||||
|
|
||||||
mod members;
|
mod members;
|
||||||
|
use members::Member;
|
||||||
|
|
||||||
mod messages;
|
mod messages;
|
||||||
mod http_params;
|
mod http_params;
|
||||||
mod perms;
|
mod perms;
|
||||||
mod db_types;
|
mod db_types;
|
||||||
|
|
||||||
|
const NO_ERR: u16 = 0;
|
||||||
|
const CONFIG_ERR: u16 = 1;
|
||||||
|
const SHUTDOWN_ERR: u16 = 2;
|
||||||
|
|
||||||
async fn route_dispatcher(pool: &Pool, resp: &mut Response<Body>, meth: &Method, path: &str, params: serde_json::Value) {
|
async fn route_dispatcher(pool: &Pool, resp: &mut Response<Body>, meth: &Method, path: &str, params: serde_json::Value) {
|
||||||
// At some point we should have some way of hiding this obnoxious complexity
|
// At some point we should have some way of hiding this obnoxious complexity
|
||||||
use routes::resolve_dynamic_route;
|
use routes::resolve_dynamic_route;
|
||||||
@ -109,11 +122,82 @@ async fn shutdown_signal() {
|
|||||||
.await
|
.await
|
||||||
.expect("Failed to capture ctrl-c signal");
|
.expect("Failed to capture ctrl-c signal");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn start_server(ecode: u16) -> u16 {
|
||||||
|
println!("Servering on localhost:8888");
|
||||||
|
let addr = SocketAddr::from(([127,0,0,1], 8888));
|
||||||
|
let service = make_service_fn(|_conn| async {
|
||||||
|
Ok::<_, Infallible>(service_fn(main_responder))
|
||||||
|
});
|
||||||
|
let server = Server::bind(&addr).serve(service);
|
||||||
|
let graceful_shutdown = server.with_graceful_shutdown(shutdown_signal());
|
||||||
|
|
||||||
|
if let Err(e) = graceful_shutdown.await {
|
||||||
|
eprintln!("Server shutdown error: {}", e);
|
||||||
|
return ecode | SHUTDOWN_ERR;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return ecode
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// we're only marking this as async because
|
||||||
|
fn parse_options(eflags: u16) -> (u16, Option<Member>) {
|
||||||
|
use std::env::set_var;
|
||||||
|
let mut potential_owner: Option<Member> = None;
|
||||||
|
|
||||||
|
let args = App::new("Freechat Server")
|
||||||
|
.version("0.1")
|
||||||
|
.author("shockrah")
|
||||||
|
.about("Decentralized chat system")
|
||||||
|
.arg(Arg::with_name("db-url")
|
||||||
|
.short("d")
|
||||||
|
.long("db-url")
|
||||||
|
.value_name("DATABASE URL")
|
||||||
|
.help("Sets the DATABASE URL via an environment variable")
|
||||||
|
.takes_value(true))
|
||||||
|
.arg(Arg::with_name("create-owner")
|
||||||
|
.short("c")
|
||||||
|
.long("create-owner")
|
||||||
|
.value_name("Owner")
|
||||||
|
.help("Creates an account with full permissions in the SQL database."))
|
||||||
|
.arg(Arg::with_name("server")
|
||||||
|
.short("s")
|
||||||
|
.long("server")
|
||||||
|
.help("Starts the API server"))
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
if let Some(db_url) = args.value_of("db-url") {
|
||||||
|
set_var("DATABASE_URL", db_url);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(name) = args.value_of("create-owner") {
|
||||||
|
use getrandom::getrandom;
|
||||||
|
|
||||||
|
let mut raw: Vec<u8> = vec![0;64];
|
||||||
|
getrandom(&mut raw).unwrap();
|
||||||
|
let raw_key = base64::encode_config(raw, base64::URL_SAFE);
|
||||||
|
// this we can store in our db as a full string on its own
|
||||||
|
let secret = bcrypt::hash(raw_key, auth::BCRYPT_COST).unwrap();
|
||||||
|
|
||||||
|
potential_owner = Some(Member {
|
||||||
|
// id field is rather meaninglyless since the db takes care of this for us
|
||||||
|
id: 0,
|
||||||
|
secret: secret.to_string(),
|
||||||
|
name: name.to_string(),
|
||||||
|
joindate: Utc::now().timestamp(),
|
||||||
|
status: 0,
|
||||||
|
permissions: std::u64::MAX
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return (eflags, potential_owner);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> Result<(), u16>{
|
async fn main() -> Result<(), u16>{
|
||||||
const NO_ERR: u16 = 0;
|
|
||||||
const CONFIG_ERR: u16 = 1;
|
|
||||||
const SHUTDOWN_ERR: u16 = 2;
|
|
||||||
|
|
||||||
let mut main_ret: u16 = 0;
|
let mut main_ret: u16 = 0;
|
||||||
// setting up environment variables
|
// setting up environment variables
|
||||||
@ -124,21 +208,30 @@ async fn main() -> Result<(), u16>{
|
|||||||
main_ret |= CONFIG_ERR;
|
main_ret |= CONFIG_ERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if main_ret == NO_ERR {
|
let (opt_res, potential_owner) = parse_options(main_ret);
|
||||||
println!("Servering on localhost:8888");
|
main_ret = opt_res; // pull out the return value from the option parsing stage
|
||||||
let addr = SocketAddr::from(([127,0,0,1], 8888));
|
// create a new owner account if we need to
|
||||||
let service = make_service_fn(|_conn| async {
|
if let Some(owner) = potential_owner {
|
||||||
Ok::<_, Infallible>(service_fn(main_responder))
|
let p = Pool::new(&env::var("DATABASE_URL").unwrap());
|
||||||
});
|
// TODO: move this logic over to members.rs
|
||||||
let server = Server::bind(&addr).serve(service);
|
if let Ok(conn) = p.get_conn().await {
|
||||||
let graceful_shutdown = server.with_graceful_shutdown(shutdown_signal());
|
let db_res = conn.prep_exec(
|
||||||
|
"INSERT INTO members (secret, name, joindate, status, permissions)
|
||||||
if let Err(e) = graceful_shutdown.await {
|
VALUES(:secret, :name, :joindate, :status, :permissions)",
|
||||||
main_ret |= SHUTDOWN_ERR;
|
mysql_async::params!{
|
||||||
eprintln!("Server shutdown error: {}", e);
|
"secret" => owner.secret,
|
||||||
|
"name" => owner.name,
|
||||||
|
"joindate" => owner.joindate,
|
||||||
|
"status" => owner.status,
|
||||||
|
"permissions" => owner.permissions
|
||||||
|
}).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if main_ret == NO_ERR {
|
||||||
|
main_ret = start_server(main_ret).await;
|
||||||
|
}
|
||||||
|
|
||||||
if main_ret != 0 {
|
if main_ret != 0 {
|
||||||
// dumb as heck loggin method here
|
// dumb as heck loggin method here
|
||||||
if main_ret & CONFIG_ERR != 0 {println!("ERROR: Config was not setup properly => Missing {{DATABASE_URL}}");}
|
if main_ret & CONFIG_ERR != 0 {println!("ERROR: Config was not setup properly => Missing {{DATABASE_URL}}");}
|
||||||
|
Loading…
Reference in New Issue
Block a user