got basic system for passing configs back and forth with URL working

This commit is contained in:
Brian Picciano 2023-05-12 18:17:23 +02:00
parent 9e724d3903
commit 130581d61e
5 changed files with 139 additions and 15 deletions

View File

@ -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

View File

@ -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 {

View File

@ -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<DM>,
target_cname: sync::Arc<domain::Name>,
passphrase: sync::Arc<String>,
handlebars: Handlebars<'a>,
query_args: HashMap<String, String>,
}
@ -71,6 +75,8 @@ where
pub fn new<DM>(
manager: DM,
target_cname: domain::Name,
passphrase: String,
) -> Result<
impl warp::Filter<Extract = impl warp::Reply, Error = warp::Rejection> + Clone + 'static,
Box<dyn Error>,
@ -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::<HashMap<String, String>>())
.map(move |query_args: HashMap<String, String>| 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<domain::config::Config>,
}
let domain_get = warp::get()
.and(with_render_ctx.clone())
.and(warp::path("domain.html"))
.and(warp::path!("domain.html"))
.and(warp::query::<DomainGetNewRequest>())
.and(warp::query::<util::ConfigFromURL>())
.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::<DomainPostRequest>())
.and(warp::query::<util::ConfigFromURL>())
.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::Config> =
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))
}

View File

@ -10,19 +10,25 @@ automatically updated too!</p>
<p><em>In the future Cosmux will support more backends than just git
repos.</em></p>
<form method="POST" action="/domain.html">
<input name="init" type="hidden" value="true" />
<input name="domain" type="hidden" value="{{ data.domain }}" />
<input name="config_origin_descr_kind" type="hidden" value="git" />
<label>
Passphrase (required during closed-beta):
<input name="passphrase" placeholder="shhhh" required />
</label>
<fieldset>
<legend>Git Repository</legend>
<p>
<label>
URL (HTTPS only):
<input name="git_url"
<input name="config_origin_descr_git_url"
type="text"
placeholder="https://example.com/some_repo.git"
value="{{ data.config.origin_descr.Git.url }}"
required />
</label>
</p>
@ -30,12 +36,15 @@ automatically updated too!</p>
<p>
<label>
Branch name:
<input name="git_branch_name"
<input name="config_origin_descr_git_branch_name"
type="text"
placeholder="main / master / etc..."
value="{{ data.config.origin_descr.Git.branch_name }}"
required />
</label>
</p>
</fieldset>
<input type="submit" value="Next" />
</form>

37
src/service/util.rs Normal file
View File

@ -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<String>,
config_origin_descr_git_url: Option<String>,
config_origin_descr_git_branch_name: Option<String>,
}
impl TryFrom<ConfigFromURL> for Option<domain::config::Config> {
type Error = String;
fn try_from(v: ConfigFromURL) -> Result<Self, Self::Error> {
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()),
}
}
}