diff --git a/src/lib/bs.rs b/src/lib/bs.rs index 7625808..9e351a5 100644 --- a/src/lib/bs.rs +++ b/src/lib/bs.rs @@ -21,6 +21,7 @@ extern crate serde_derive; #[macro_use] extern crate serde_json; +extern crate tempdir; pub mod config; pub mod from_file; @@ -33,5 +34,6 @@ pub mod proxy_utils; pub mod replacer; pub mod rewrites; pub mod setup; +pub mod ssl; pub mod with_body; pub mod without_body; diff --git a/src/lib/config.rs b/src/lib/config.rs index 7a9a448..b5c1758 100644 --- a/src/lib/config.rs +++ b/src/lib/config.rs @@ -36,6 +36,11 @@ pub enum ProgramStartError { ConfigCliError(ConfigError), InvalidArgs(Error), FromFile(FromFileError), + BindHttp(std::io::Error), + BindHttps(std::io::Error), + SslFailed, + SslTempDir, + SslTempDirClose, } impl std::fmt::Display for ProgramStartError { @@ -58,6 +63,16 @@ impl std::fmt::Display for ProgramStartError { ProgramStartError::ConfigFileRead => write!(f, "config file content could not be read"), ProgramStartError::FromFile(e) => write!(f, "{}", e), ProgramStartError::InvalidArgs(e) => write!(f, "{}", e), + ProgramStartError::SslFailed => write!(f, "could not create self-signed ssl certs"), + ProgramStartError::SslTempDir => write!( + f, + "could not create the temp dir to hold self-signed ssl certs" + ), + ProgramStartError::SslTempDirClose => write!(f, "could not clean up the temp dir"), + ProgramStartError::BindHttp(e) => write!(f, "could not bind over http, reason: {}", e), + ProgramStartError::BindHttps(e) => { + write!(f, "could not bind over https, reason: {}", e) + } } } } diff --git a/src/lib/ssl.rs b/src/lib/ssl.rs new file mode 100644 index 0000000..b3ef4bb --- /dev/null +++ b/src/lib/ssl.rs @@ -0,0 +1,84 @@ +use config::ProgramStartError; +use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod}; +use std::fs::File; +use std::io::{Error, Write}; +use std::path::PathBuf; +use tempdir::TempDir; + +const TMP_DIR_NAME: &'static str = "config-gen"; + +const TMP_KEY: &'static [u8] = include_bytes!("../key.pem"); +const TMP_KEY_NAME: &'static str = "key.pem"; + +const TMP_CERT: &'static [u8] = include_bytes!("../cert.pem"); +const TMP_CERT_NAME: &'static str = "cert.pem"; + +/// +/// Create an SslAcceptorBuilder by using self-signed +/// certificates that exist inside this binary +/// +/// This is acceptable since this is a development only +/// tool and nothing this runs should be anywhere near anything +/// that's shared, or in production. +/// +pub fn builder() -> Result { + let (key_path, cert_path, tmp_dir) = ssl_paths().map_err(|_e| ProgramStartError::SslTempDir)?; + + let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()) + .map_err(|_e| ProgramStartError::SslFailed)?; + + builder + .set_private_key_file(key_path, SslFiletype::PEM) + .map_err(|_e| ProgramStartError::SslFailed)?; + + builder + .set_certificate_chain_file(cert_path) + .map_err(|_e| ProgramStartError::SslFailed)?; + + tmp_dir + .close() + .map_err(|_e| ProgramStartError::SslTempDirClose)?; + + Ok(builder) +} + +#[test] +fn test_ssl_builder() { + builder().unwrap(); +} + +/// +/// Takes the self-signed bundled key & cert +/// and places them in a temporary directory so that they +/// can be used by openSSL +/// +/// # Examples +/// +/// ``` +/// use bs::ssl::*; +/// let (key_path, cert_path, tmp_dir) = ssl_paths().unwrap(); +/// println!("key={:?}, cert={:?}", key_path, cert_path); +/// tmp_dir.close().unwrap(); +/// ``` +/// +pub fn ssl_paths() -> Result<(PathBuf, PathBuf, TempDir), Error> { + let tmp_dir = TempDir::new(TMP_DIR_NAME)?; + let key_path = tmp_dir.path().join(TMP_KEY_NAME); + let cert_path = tmp_dir.path().join(TMP_CERT_NAME); + + let mut key_file = File::create(&key_path)?; + key_file.write_all(TMP_KEY)?; + key_file.sync_all()?; + + let mut cert_file = File::create(&cert_path)?; + cert_file.write_all(TMP_CERT)?; + cert_file.sync_all()?; + + Ok((key_path, cert_path, tmp_dir)) +} + +#[test] +fn test_ssl_paths() { + let (_file_key, _file_cert, tmp_dir) = ssl_paths().unwrap(); + assert_eq!(tmp_dir.path().exists(), true); +} diff --git a/src/main.rs b/src/main.rs index 6ace1a2..496841b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,25 +11,20 @@ extern crate mime; extern crate openssl; extern crate regex; extern crate serde_yaml; -extern crate url; extern crate tempdir; +extern crate url; use actix_web::{server, App}; -use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; use bs::config::{ProgramConfig, ProgramStartError}; use bs::from_file::FromFile; use bs::options::{ProgramOptions, ProxyScheme}; use bs::setup::{apply_presets, state_and_presets}; -use openssl::ssl::SslAcceptorBuilder; -use std::ffi::CString; -use std::env; -use tempdir::TempDir; -use std::fs::File; +use bs::ssl; fn main() { match ProgramOptions::from_vec(&mut std::env::args_os()).and_then(run_with_opts) { - Ok(opts) => println!("Running!"), + Ok(..) => { /* Running! */ } Err(e) => { eprintln!("{}", e); std::process::exit(1); @@ -92,50 +87,25 @@ fn run_with_opts(opts: ProgramOptions) -> Result<(), ProgramStartError> { // target URL's scheme // let s = match server_opts.scheme { - ProxyScheme::Http => s.bind(&local_addr), - ProxyScheme::Https => s.bind_ssl(&local_addr, get_ssl_builder()), + ProxyScheme::Http => s.bind(&local_addr).map_err(ProgramStartError::BindHttp)?, + ProxyScheme::Https => { + let builder = ssl::builder()?; + s.bind_ssl(&local_addr, builder) + .map_err(ProgramStartError::BindHttps)? + } }; - s.expect("Couldn't start the application") - .shutdown_timeout(0) - .start(); + // + // Start the server + // + s.shutdown_timeout(0).start(); + // + // Output the proxy URL only + // println!("{}://{}", server_opts.scheme, local_addr); let _ = sys.run(); Ok(()) } - -/// -/// SSL builder -/// -/// Todo: allow key/cert options -/// -fn get_ssl_builder() -> SslAcceptorBuilder { - - use std::fs::File; - use std::io::{self, Write}; - - let tmp_dir = TempDir::new("example").unwrap(); - let file_key = tmp_dir.path().join("key.pem"); - let file_cert = tmp_dir.path().join("cert.pem"); - - let mut tmp_file = File::create(&file_key).unwrap(); - tmp_file.write_all(include_bytes!("key.pem")).unwrap(); - tmp_file.sync_all().unwrap(); - - let mut tmp_file2 = File::create(&file_cert).unwrap(); - tmp_file2.write_all(include_bytes!("cert.pem")).unwrap(); - tmp_file2.sync_all().unwrap(); - - let mut builder = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); - builder - .set_private_key_file(file_key, SslFiletype::PEM) - .unwrap(); - builder.set_certificate_chain_file(file_cert).unwrap(); - - tmp_dir.close().unwrap(); - - builder -}