From 130581d61e10bcf4a9e7c1716a6558e397dc6041 Mon Sep 17 00:00:00 2001 From: Brian Picciano Date: Fri, 12 May 2023 18:17:23 +0200 Subject: [PATCH] got basic system for passing configs back and forth with URL working --- .env.dev | 1 + src/main.rs | 12 +++- src/service.rs | 89 +++++++++++++++++++++--- src/service/http_tpl/domain_get_new.html | 15 +++- src/service/util.rs | 37 ++++++++++ 5 files changed, 139 insertions(+), 15 deletions(-) create mode 100644 src/service/util.rs diff --git a/.env.dev b/.env.dev index 6b342b6..bd57d5a 100644 --- a/.env.dev +++ b/.env.dev @@ -1,3 +1,4 @@ +export GATEWAY_PASSPHRASE=foobar export GATEWAY_ORIGIN_STORE_GIT_DIR_PATH=/tmp/gateway_dev_env/origin/git export GATEWAY_DOMAIN_CHECKER_TARGET_CNAME=gateway.example.com export GATEWAY_DOMAIN_CONFIG_STORE_DIR_PATH=/tmp/gateway_dev_env/domain/config diff --git a/src/main.rs b/src/main.rs index 8bdec32..2faa18e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,6 +15,9 @@ struct Cli { #[arg(long, default_value_t = SocketAddr::from_str("127.0.0.1:3030").unwrap(), env = "GATEWAY_HTTP_LISTEN_ADDR")] http_listen_addr: SocketAddr, + #[arg(long, required = true, env = "GATEWAY_PASSPHRASE")] + passphrase: String, + #[arg(long, required = true, env = "GATEWAY_ORIGIN_STORE_GIT_DIR_PATH")] origin_store_git_dir_path: path::PathBuf, @@ -59,7 +62,7 @@ async fn main() { .expect("git origin store initialized"); let domain_checker = gateway::domain::checker::new( - config.domain_checker_target_cname, + config.domain_checker_target_cname.clone(), &config.domain_checker_resolver_addr, ) .expect("domain checker initialized"); @@ -69,7 +72,12 @@ async fn main() { let manager = gateway::domain::manager::new(origin_store, domain_config_store, domain_checker); - let service = gateway::service::new(manager).expect("service initialized"); + let service = gateway::service::new( + manager, + config.domain_checker_target_cname, + config.passphrase, + ) + .expect("service initialized"); let (addr, server) = warp::serve(service).bind_with_graceful_shutdown(config.http_listen_addr, async { diff --git a/src/service.rs b/src/service.rs index d62057c..d9e97e9 100644 --- a/src/service.rs +++ b/src/service.rs @@ -7,6 +7,7 @@ use warp::Filter; use crate::domain; pub mod http_tpl; +mod util; /* * POST /domain/config (domain, config, secret, init?) -> token? @@ -21,6 +22,9 @@ where DM: domain::manager::Manager, { domain_manager: sync::Arc, + target_cname: sync::Arc, + passphrase: sync::Arc, + handlebars: Handlebars<'a>, query_args: HashMap, } @@ -71,6 +75,8 @@ where pub fn new( manager: DM, + target_cname: domain::Name, + passphrase: String, ) -> Result< impl warp::Filter + Clone + 'static, Box, @@ -79,12 +85,16 @@ where DM: domain::manager::Manager + 'static, { let manager = sync::Arc::new(manager); + let target_cname = sync::Arc::new(target_cname); + let passphrase = sync::Arc::new(passphrase); let hbs = sync::Arc::new(self::http_tpl::get()?); let with_render_ctx = warp::any() .and(warp::query::>()) .map(move |query_args: HashMap| RenderContext { domain_manager: manager.clone(), + target_cname: target_cname.clone(), + passphrase: passphrase.clone(), handlebars: hbs.clone(), query_args, }); @@ -111,28 +121,87 @@ where domain: domain::Name, } + #[derive(Serialize)] + struct DomainGetNewResponse { + domain: domain::Name, + config: Option, + } + let domain_get = warp::get() .and(with_render_ctx.clone()) - .and(warp::path("domain.html")) + .and(warp::path!("domain.html")) .and(warp::query::()) + .and(warp::query::()) .map( - move |render_ctx: RenderContext<'_, DM>, req: DomainGetNewRequest| { - #[derive(Serialize)] - struct DomainGetNewResponse { - domain: domain::Name, - } - + |render_ctx: RenderContext<'_, DM>, + req: DomainGetNewRequest, + domain_config: util::ConfigFromURL| { match render_ctx.domain_manager.get_config(&req.domain) { Ok(_config) => panic!("TODO"), Err(domain::manager::GetConfigError::NotFound) => render_page( render_ctx, String::from("/domain_get_new.html"), - DomainGetNewResponse { domain: req.domain }, + DomainGetNewResponse { + domain: req.domain, + config: domain_config.try_into().expect("TODO"), + }, ), - Err(_) => panic!("TODO"), + Err(domain::manager::GetConfigError::Unexpected(e)) => { + panic!("{}", e) // TODO + } } }, ); - Ok(static_dir.or(index).or(domain_get)) + #[derive(Deserialize)] + struct DomainPostRequest { + _init: bool, + domain: domain::Name, + passphrase: String, + } + + let domain_post = warp::post() + .and(with_render_ctx.clone()) + .and(warp::path!("domain.html")) + .and(warp::query::()) + .and(warp::query::()) + .map( + |render_ctx: RenderContext<'_, DM>, + req: DomainPostRequest, + domain_config: util::ConfigFromURL| { + if req.passphrase != render_ctx.passphrase.as_str() { + panic!("TODO") + } + + //if req.init { + #[derive(Serialize)] + struct Response { + domain: domain::Name, + config: domain::config::Config, + target_cname: domain::Name, + challenge_token: String, + } + + let config: Option = + domain_config.try_into().expect("TODO"); + let config = config.expect("TODO"); + + let config_hash = config.hash().expect("TODO"); + let target_cname = (*render_ctx.target_cname).clone(); + + return render_page( + render_ctx, + String::from("/domain_post_init.html"), + Response { + domain: req.domain, + config: config, + target_cname: target_cname, + challenge_token: config_hash, + }, + ); + //} + }, + ); + + Ok(static_dir.or(index).or(domain_get).or(domain_post)) } diff --git a/src/service/http_tpl/domain_get_new.html b/src/service/http_tpl/domain_get_new.html index 024676e..12a8a32 100644 --- a/src/service/http_tpl/domain_get_new.html +++ b/src/service/http_tpl/domain_get_new.html @@ -10,19 +10,25 @@ automatically updated too!

In the future Cosmux will support more backends than just git repos.

-
+ + +
Git Repository

@@ -30,12 +36,15 @@ automatically updated too!

+ +
diff --git a/src/service/util.rs b/src/service/util.rs new file mode 100644 index 0000000..a93ea25 --- /dev/null +++ b/src/service/util.rs @@ -0,0 +1,37 @@ +use std::convert::TryFrom; + +use serde::Deserialize; + +use crate::{domain, origin}; + +#[derive(Deserialize)] +pub struct ConfigFromURL { + config_origin_descr_kind: Option, + config_origin_descr_git_url: Option, + config_origin_descr_git_branch_name: Option, +} + +impl TryFrom for Option { + type Error = String; + + fn try_from(v: ConfigFromURL) -> Result { + match v + .config_origin_descr_kind + .unwrap_or("".to_string()) + .as_str() + { + "" => Ok(None), + "git" => Ok(Some(domain::config::Config { + origin_descr: origin::Descr::Git { + url: v + .config_origin_descr_git_url + .ok_or("config_origin_descr_git_url missing")?, + branch_name: v + .config_origin_descr_git_branch_name + .ok_or("config_origin_descr_git_branch_name missing")?, + }, + })), + _ => Err("invalid config_origin_descr_kind".to_string()), + } + } +}