diff --git a/appmgr/Cargo.lock b/appmgr/Cargo.lock index 96c5a3190..1822c501e 100644 --- a/appmgr/Cargo.lock +++ b/appmgr/Cargo.lock @@ -35,7 +35,7 @@ dependencies = [ [[package]] name = "appmgr" -version = "0.2.8" +version = "0.2.9" dependencies = [ "argonautica", "async-trait", diff --git a/appmgr/Cargo.toml b/appmgr/Cargo.toml index b5a1af76c..75c84a3ba 100644 --- a/appmgr/Cargo.toml +++ b/appmgr/Cargo.toml @@ -2,7 +2,7 @@ authors = ["Aiden McClelland "] edition = "2018" name = "appmgr" -version = "0.2.8" +version = "0.2.9" [lib] name = "appmgrlib" diff --git a/appmgr/src/nginx.conf.template b/appmgr/src/nginx.conf.template new file mode 100644 index 000000000..d1866cedb --- /dev/null +++ b/appmgr/src/nginx.conf.template @@ -0,0 +1,15 @@ +server {{ + listen 443 ssl; + server_name {app_id}.{hostname}.local; + ssl_certificate /etc/nginx/ssl/{hostname}-local.crt.pem; + ssl_certificate_key /etc/nginx/ssl/{hostname}-local.key.pem; + location / {{ + proxy_pass http://{app_ip}:80/; + proxy_set_header Host $host; + }} +}} +server {{ + listen 80; + server_name {hostname}.local; + return 301 https://$host$request_uri; +}} \ No newline at end of file diff --git a/appmgr/src/tor.rs b/appmgr/src/tor.rs index 8db0dd37d..5454e8a09 100644 --- a/appmgr/src/tor.rs +++ b/appmgr/src/tor.rs @@ -19,6 +19,8 @@ pub struct PortMapping { pub const ETC_TOR_RC: &'static str = "/etc/tor/torrc"; pub const HIDDEN_SERVICE_DIR_ROOT: &'static str = "/var/lib/tor"; +pub const ETC_HOSTNAME: &'static str = "/etc/hostname"; +pub const ETC_NGINX_SERVICES_CONF: &'static str = "/etc/nginx/sites-available/start9-services.conf"; #[derive(Debug, Clone, Copy, serde::Deserialize, serde::Serialize)] #[serde(rename_all = "lowercase")] @@ -176,6 +178,34 @@ pub async fn write_services(hidden_services: &ServicesMap) -> Result<(), Error> } f.write_all(b"\n").await?; } + write_lan_services(hidden_services).await?; // I know this doesn't belong here + Ok(()) +} + +pub async fn write_lan_services(hidden_services: &ServicesMap) -> Result<(), Error> { + let hostname = tokio::fs::read_to_string(ETC_HOSTNAME).await?; + let mut f = tokio::fs::File::create(ETC_NGINX_SERVICES_CONF).await?; + for (name, service) in &hidden_services.map { + if service + .ports + .iter() + .filter(|p| p.internal == 80) + .next() + .is_none() + { + continue; + } + f.write_all( + format!( + include_str!("nginx.conf.template"), + hostname = hostname, + app_id = name, + app_ip = service.ip, + ) + .as_bytes(), + ) + .await?; + } Ok(()) } @@ -302,6 +332,19 @@ pub async fn set_svc( .or_else(|| { svc_exit.signal().map(|a| 128 + a) }) .unwrap_or(0) ); + log::info!("Reloading Nginx."); + let svc_exit = std::process::Command::new("service") + .args(&["nginx", "reload"]) + .status()?; + crate::ensure_code!( + svc_exit.success(), + crate::error::GENERAL_ERROR, + "Failed to Reload Nginx: {}", + svc_exit + .code() + .or_else(|| { svc_exit.signal().map(|a| 128 + a) }) + .unwrap_or(0) + ); Ok(( ip, if is_listening { @@ -344,6 +387,19 @@ pub async fn rm_svc(name: &str) -> Result<(), Error> { "Failed to Reload Tor: {}", svc_exit.code().unwrap_or(0) ); + log::info!("Reloading Nginx."); + let svc_exit = std::process::Command::new("service") + .args(&["nginx", "reload"]) + .status()?; + crate::ensure_code!( + svc_exit.success(), + crate::error::GENERAL_ERROR, + "Failed to Reload Nginx: {}", + svc_exit + .code() + .or_else(|| { svc_exit.signal().map(|a| 128 + a) }) + .unwrap_or(0) + ); Ok(()) } diff --git a/appmgr/src/version/mod.rs b/appmgr/src/version/mod.rs index 7d5687ec5..e278d53e0 100644 --- a/appmgr/src/version/mod.rs +++ b/appmgr/src/version/mod.rs @@ -24,8 +24,9 @@ mod v0_2_5; mod v0_2_6; mod v0_2_7; mod v0_2_8; +mod v0_2_9; -pub use v0_2_8::Version as Current; +pub use v0_2_9::Version as Current; #[derive(serde::Serialize, serde::Deserialize)] #[serde(untagged)] @@ -46,6 +47,7 @@ enum Version { V0_2_6(Wrapper), V0_2_7(Wrapper), V0_2_8(Wrapper), + V0_2_9(Wrapper), Other(emver::Version), } @@ -156,6 +158,7 @@ pub async fn init() -> Result<(), failure::Error> { Version::V0_2_6(v) => v.0.migrate_to(&Current::new()).await?, Version::V0_2_7(v) => v.0.migrate_to(&Current::new()).await?, Version::V0_2_8(v) => v.0.migrate_to(&Current::new()).await?, + Version::V0_2_9(v) => v.0.migrate_to(&Current::new()).await?, Version::Other(_) => (), // TODO find some way to automate this? } @@ -172,7 +175,8 @@ pub async fn self_update(requirement: emver::VersionRange) -> Result<(), Error> .collect(); let url = format!("{}/appmgr?spec={}", &*crate::SYS_REGISTRY_URL, req_str); log::info!("Fetching new version from {}", url); - let response = reqwest::get(&url).compat() + let response = reqwest::get(&url) + .compat() .await .with_code(crate::error::NETWORK_ERROR)? .error_for_status() @@ -244,6 +248,7 @@ pub async fn self_update(requirement: emver::VersionRange) -> Result<(), Error> Version::V0_2_6(v) => Current::new().migrate_to(&v.0).await?, Version::V0_2_7(v) => Current::new().migrate_to(&v.0).await?, Version::V0_2_8(v) => Current::new().migrate_to(&v.0).await?, + Version::V0_2_9(v) => Current::new().migrate_to(&v.0).await?, Version::Other(_) => (), // TODO find some way to automate this? }; diff --git a/appmgr/src/version/v0_2_9.rs b/appmgr/src/version/v0_2_9.rs new file mode 100644 index 000000000..4d95f3495 --- /dev/null +++ b/appmgr/src/version/v0_2_9.rs @@ -0,0 +1,58 @@ +use std::os::unix::process::ExitStatusExt; + +use super::*; + +const V0_2_9: emver::Version = emver::Version::new(0, 2, 9, 0); + +pub struct Version; +#[async_trait] +impl VersionT for Version { + type Previous = v0_2_8::Version; + fn new() -> Self { + Version + } + fn semver(&self) -> &'static emver::Version { + &V0_2_9 + } + async fn up(&self) -> Result<(), Error> { + crate::tor::write_lan_services( + &crate::tor::services_map(&PersistencePath::from_ref(crate::SERVICES_YAML)).await?, + ) + .await?; + tokio::fs::os::unix::symlink( + crate::tor::ETC_NGINX_SERVICES_CONF, + "/etc/nginx/sites-enabled/start9-services.conf", + ) + .await?; + let svc_exit = std::process::Command::new("service") + .args(&["nginx", "reload"]) + .status()?; + crate::ensure_code!( + svc_exit.success(), + crate::error::GENERAL_ERROR, + "Failed to Reload Nginx: {}", + svc_exit + .code() + .or_else(|| { svc_exit.signal().map(|a| 128 + a) }) + .unwrap_or(0) + ); + Ok(()) + } + async fn down(&self) -> Result<(), Error> { + tokio::fs::remove_file("/etc/nginx/sites-enabled/start9-services.conf").await?; + tokio::fs::remove_file(crate::tor::ETC_NGINX_SERVICES_CONF).await?; + let svc_exit = std::process::Command::new("service") + .args(&["nginx", "reload"]) + .status()?; + crate::ensure_code!( + svc_exit.success(), + crate::error::GENERAL_ERROR, + "Failed to Reload Nginx: {}", + svc_exit + .code() + .or_else(|| { svc_exit.signal().map(|a| 128 + a) }) + .unwrap_or(0) + ); + Ok(()) + } +}