diff --git a/.gitignore b/.gitignore index 8e38330..0e0ff75 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ /target -/config.json \ No newline at end of file +/config.json +/localhost-key.pem +/localhost.pem \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index cbfd0b7..2e73fbd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -358,6 +358,17 @@ dependencies = [ "syn", ] +[[package]] +name = "actix-web-middleware-redirect-https" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ce1464786203c29120f6d1e4dcdc9c3975506e70b89c3a56c5389f265256dc6" +dependencies = [ + "actix-service", + "actix-web", + "futures", +] + [[package]] name = "actix_derive" version = "0.5.0" @@ -1202,6 +1213,7 @@ dependencies = [ "actix-ratelimit", "actix-web", "actix-web-actors", + "actix-web-middleware-redirect-https", "base64", "clap", "env_logger", @@ -2060,6 +2072,18 @@ dependencies = [ "autocfg", "num_cpus", "pin-project-lite 0.2.4", + "tokio-macros", +] + +[[package]] +name = "tokio-macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1edff19..0f574cd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ description = "Chat app for lupt(लुप्त) users!" authors = ["Piyush Raj "] edition = "2018" license = "GPL 3.0" -license-file = "LICENSE" readme = "README.md" repository = "https://github.com/PiyushXCoder/lupt" homepage = "luptchat.in" @@ -21,6 +20,7 @@ actix-web-actors = "3" actix-broker = "0.3.1" actix-files = "0.5.0" actix-ratelimit = "0.3.1" +actix-web-middleware-redirect-https = "3.0.1" env_logger = "0.8.3" openssl = "0.10.28" @@ -30,7 +30,7 @@ lazy_static = "1.4.0" serde = "1.0.123" serde_json = "1.0.62" rand = "0.8.3" -tokio = { version = "1.5.0", features = ['rt', 'rt-multi-thread']} +tokio = { version = "1.5.0", features = ['rt', 'rt-multi-thread', 'macros']} sha1 = "0.6.0" base64 = "0.13.0" diff --git a/src/config.rs b/src/config.rs index fb8eb23..b584431 100644 --- a/src/config.rs +++ b/src/config.rs @@ -21,6 +21,8 @@ use serde::{Deserialize, Serialize}; pub struct Config { pub static_path: String, pub bind_address: String, + pub port: String, + pub port_x: String, pub config: ConfigFile } @@ -39,13 +41,6 @@ impl Config { .version(env!("CARGO_PKG_VERSION")) .author(env!("CARGO_PKG_AUTHORS")) .about(env!("CARGO_PKG_DESCRIPTION")) - .arg(Arg::with_name("static_path") - .short("s") - .long("static_path") - .value_name("DIR") - .help("Path of directory with index.html") - .required(true) - .takes_value(true)) .arg(Arg::with_name("bind_address") .short("a") .long("bind_address") @@ -53,6 +48,27 @@ impl Config { .help("Address to bind for server") .required(true) .takes_value(true)) + .arg(Arg::with_name("port") + .short("p") + .long("port") + .value_name("PORT") + .help("Port to bind for server") + .required(true) + .takes_value(true)) + .arg(Arg::with_name("port_x") + .short("x") + .long("port_x") + .value_name("PORT") + .help("Port to bind for http if ssl is enabled to redirect to https") + .required(false) + .takes_value(true)) + .arg(Arg::with_name("static_path") + .short("s") + .long("static_path") + .value_name("DIR") + .help("Path of directory with index.html") + .required(true) + .takes_value(true)) .arg(Arg::with_name("config") .short("c") .long("config") @@ -80,6 +96,8 @@ Config file must have following fields Config { static_path: matches.value_of("static_path").unwrap().to_owned(), bind_address: matches.value_of("bind_address").unwrap().to_owned(), + port: matches.value_of("port").unwrap().to_owned(), + port_x: matches.value_of("port_x").unwrap_or("").to_owned(), config } } diff --git a/src/main.rs b/src/main.rs index 2af1bbe..8f50a85 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,7 +54,6 @@ lazy_static! { async fn main() -> std::io::Result<()> { std::env::set_var("RUST_LOG", "actix_web=info"); env_logger::init(); - let store = MemoryStore::new(); let config = config::Config::new(); *SALT.write().unwrap() = config.config.salt; @@ -63,11 +62,33 @@ async fn main() -> std::io::Result<()> { let ssl_builder = generate_ssl_builder(config.config.ssl_key, config.config.ssl_cert); let logger_pattern = config.config.logger_pattern; let static_path = config.static_path; + + let mut redirect = None; + let port_x = config.port_x.clone(); + let port = config.port.clone(); + if ssl_builder.is_some() { + redirect = Some(HttpServer::new(move || { + App::new() + .wrap( + RateLimiter::new( + MemoryStoreActor::from(MemoryStore::new().clone()).start()) + .with_interval(std::time::Duration::from_secs(60)) + .with_max_requests(100) + ) + .wrap(actix_web_middleware_redirect_https::RedirectHTTPS::with_replacements(&[(port_x.clone(), port.clone())])) + .route("/", web::get().to(|| HttpResponse::Ok() + .content_type("text/plain") + .body("Always HTTPS on non-default ports!"))) + }) + .bind(format!("{}:{}", config.bind_address, config.port_x))? + .run()); + } + let server = HttpServer::new(move || { App::new() .wrap( RateLimiter::new( - MemoryStoreActor::from(store.clone()).start()) + MemoryStoreActor::from(MemoryStore::new().clone()).start()) .with_interval(std::time::Duration::from_secs(60)) .with_max_requests(200) ) @@ -79,10 +100,16 @@ async fn main() -> std::io::Result<()> { }); match ssl_builder { - Some(b) => server.bind_openssl(config.bind_address, b), - None => server.bind(config.bind_address) - }?.run() - .await + Some(b) => { + let srv = server.bind_openssl(format!("{}:{}", config.bind_address, config.port), b)?.run(); + tokio::try_join!(redirect.unwrap(), srv)?; + }, + None => { + server.bind(format!("{}:{}", config.bind_address, config.port))?.run().await?; + } + } + + Ok(()) } async fn ws_index(req: HttpRequest, stream: web::Payload) -> Result {