From 6e88ab967fa6952a12c12524ac6a25c46ccf4661 Mon Sep 17 00:00:00 2001
From: Brian Picciano
Date: Sat, 13 May 2023 16:34:51 +0200
Subject: [PATCH] Fix up init, implement sync (maybe)
---
src/domain/checker.rs | 5 +-
src/domain/manager.rs | 4 -
src/service.rs | 96 +++++++++++++++----
.../{domain_get_new.html => domain.html} | 3 +-
src/service/http_tpl/domain_init.html | 26 +++++
src/service/http_tpl/domain_sync.html | 13 +++
src/service/util.rs | 24 +++--
7 files changed, 136 insertions(+), 35 deletions(-)
rename src/service/http_tpl/{domain_get_new.html => domain.html} (93%)
create mode 100644 src/service/http_tpl/domain_init.html
create mode 100644 src/service/http_tpl/domain_sync.html
diff --git a/src/domain/checker.rs b/src/domain/checker.rs
index 46a0802..d89559f 100644
--- a/src/domain/checker.rs
+++ b/src/domain/checker.rs
@@ -22,9 +22,6 @@ pub enum NewDNSCheckerError {
#[derive(thiserror::Error, Debug)]
pub enum CheckDomainError {
- #[error("invalid domain name")]
- InvalidDomainName,
-
#[error("target CNAME not set")]
TargetCNAMENotSet,
@@ -99,7 +96,7 @@ impl Checker for DNSChecker {
// check that the TXT record with the challenge token is correctly installed on the domain
{
- let domain = Name::from_str("_gateway")
+ let domain = Name::from_str("_domiply_challenge")
.map_err(|e| CheckDomainError::Unexpected(Box::from(e)))?
.append_domain(domain)
.map_err(|e| CheckDomainError::Unexpected(Box::from(e)))?;
diff --git a/src/domain/manager.rs b/src/domain/manager.rs
index 81f78e3..f636b95 100644
--- a/src/domain/manager.rs
+++ b/src/domain/manager.rs
@@ -67,9 +67,6 @@ pub enum SyncWithConfigError {
#[error("invalid branch name")]
InvalidBranchName,
- #[error("invalid domain name")]
- InvalidDomainName,
-
#[error("already in progress")]
AlreadyInProgress,
@@ -97,7 +94,6 @@ impl From for SyncWithConfigError {
impl From for SyncWithConfigError {
fn from(e: checker::CheckDomainError) -> SyncWithConfigError {
match e {
- checker::CheckDomainError::InvalidDomainName => SyncWithConfigError::InvalidDomainName,
checker::CheckDomainError::TargetCNAMENotSet => SyncWithConfigError::TargetCNAMENotSet,
checker::CheckDomainError::ChallengeTokenNotSet => {
SyncWithConfigError::ChallengeTokenNotSet
diff --git a/src/service.rs b/src/service.rs
index 5eae619..f5c8ed1 100644
--- a/src/service.rs
+++ b/src/service.rs
@@ -147,15 +147,15 @@ where
config: Option,
}
- let domain_get = warp::get()
+ let domain = warp::get()
.and(with_renderer.clone())
.and(warp::path!("domain.html"))
.and(warp::query::())
- .and(warp::query::())
+ .and(warp::query::())
.map(
|renderer: Renderer<'_, DM>,
req: DomainGetNewRequest,
- domain_config: util::ConfigFromURL| {
+ domain_config: util::FlatConfig| {
match renderer.domain_manager.get_config(&req.domain) {
Ok(_config) => renderer.render_error_page(500, "TODO not yet implemented"),
Err(domain::manager::GetConfigError::NotFound) => {
@@ -170,7 +170,7 @@ where
};
renderer.render_page(
- "/domain_get_new.html",
+ "/domain.html",
&DomainGetNewResponse {
domain: req.domain,
config: domain_config,
@@ -187,30 +187,28 @@ where
);
#[derive(Deserialize)]
- struct DomainPostRequest {
- _init: bool,
+ struct DomainInitRequest {
domain: domain::Name,
passphrase: String,
}
- let domain_post = warp::post()
+ let domain_init = warp::get()
.and(with_renderer.clone())
- .and(warp::path!("domain.html"))
- .and(warp::query::())
- .and(warp::query::())
+ .and(warp::path!("domain_init.html"))
+ .and(warp::query::())
+ .and(warp::query::())
.map(
|renderer: Renderer<'_, DM>,
- req: DomainPostRequest,
- domain_config: util::ConfigFromURL| {
+ req: DomainInitRequest,
+ domain_config: util::FlatConfig| {
if req.passphrase != renderer.passphrase.as_str() {
return renderer.render_error_page(401, "Incorrect passphrase");
}
- //if req.init {
#[derive(Serialize)]
struct Response {
domain: domain::Name,
- config: domain::config::Config,
+ flat_config: util::FlatConfig,
target_cname: domain::Name,
challenge_token: String,
}
@@ -239,15 +237,74 @@ where
let target_cname = (*renderer.target_cname).clone();
return renderer.render_page(
- "/domain_post_init.html",
+ "/domain_init.html",
&Response {
domain: req.domain,
- config: config,
+ flat_config: config.into(),
target_cname: target_cname,
challenge_token: config_hash,
},
);
- //}
+ },
+ );
+
+ #[derive(Deserialize)]
+ struct DomainSyncRequest {
+ domain: domain::Name,
+ }
+
+ let domain_sync = warp::get()
+ .and(with_renderer.clone())
+ .and(warp::path!("domain_sync.html"))
+ .and(warp::query::())
+ .and(warp::query::())
+ .map(
+ |renderer: Renderer<'_, DM>,
+ req: DomainSyncRequest,
+ domain_config: util::FlatConfig| {
+ let config: domain::config::Config = match domain_config.try_into() {
+ Ok(Some(config)) => config,
+ Ok(None) => {
+ return renderer.render_error_page(400, "domain config is required")
+ }
+ Err(e) => {
+ return renderer
+ .render_error_page(400, format!("invalid domain config: {e}").as_str())
+ }
+ };
+
+ let sync_result = renderer
+ .domain_manager
+ .sync_with_config(&req.domain, &config);
+
+ #[derive(Serialize)]
+ struct Response {
+ domain: domain::Name,
+ flat_config: util::FlatConfig,
+ error_msg: Option,
+ }
+
+ let mut response = Response {
+ domain: req.domain,
+ flat_config: config.into(),
+ error_msg: None,
+ };
+
+ response.error_msg = match sync_result
+ {
+ Ok(_) => None,
+ Err(domain::manager::SyncWithConfigError::InvalidURL) => Some("Fetching the git repository failed, please double check that you input the correct URL.".to_string()),
+ Err(domain::manager::SyncWithConfigError::InvalidBranchName) => Some("The git repository does not have a branch of the given name, please double check that you input the correct name.".to_string()),
+ Err(domain::manager::SyncWithConfigError::AlreadyInProgress) => Some("The configuration of your domain is still in progress, please refresh in a few minutes.".to_string()),
+ Err(domain::manager::SyncWithConfigError::TargetCNAMENotSet) => Some("The CNAME record is not set correctly on the domain. Please double check that you put the correct value on the record. If the value is correct, then most likely the updated records have not yet propagated. In this case you can refresh in a few minutes to try again.".to_string()),
+ Err(domain::manager::SyncWithConfigError::ChallengeTokenNotSet) => Some("The TXT record is not set correctly on the domain. Please double check that you put the correct value on the record. If the value is correct, then most likely the updated records have not yet propagated. In this case you can refresh in a few minutes to try again.".to_string()),
+ Err(domain::manager::SyncWithConfigError::Unexpected(e)) => Some(format!("An unexpected error occurred: {e}")),
+ };
+
+ return renderer.render_page(
+ "/domain_sync.html",
+ &response,
+ )
},
);
@@ -257,7 +314,8 @@ where
Ok(static_dir
.or(index)
- .or(domain_get)
- .or(domain_post)
+ .or(domain)
+ .or(domain_init)
+ .or(domain_sync)
.or(not_found))
}
diff --git a/src/service/http_tpl/domain_get_new.html b/src/service/http_tpl/domain.html
similarity index 93%
rename from src/service/http_tpl/domain_get_new.html
rename to src/service/http_tpl/domain.html
index 12a8a32..b15af4d 100644
--- a/src/service/http_tpl/domain_get_new.html
+++ b/src/service/http_tpl/domain.html
@@ -10,8 +10,7 @@ automatically updated too!
In the future Cosmux will support more backends than just git
repos.
-
diff --git a/src/service/http_tpl/domain_sync.html b/src/service/http_tpl/domain_sync.html
new file mode 100644
index 0000000..2d9aef1
--- /dev/null
+++ b/src/service/http_tpl/domain_sync.html
@@ -0,0 +1,13 @@
+{{#if data.error_msg}}
+
+Your domain is not yet set up.
+{{ data.error_msg }}
+
+{{ else }}
+
+Congratulations! Your domain has been successfully configured. You can visit
+it at:
+
+http://{{ data.domain }}
+
+{{/if}}
diff --git a/src/service/util.rs b/src/service/util.rs
index a93ea25..ebb9b90 100644
--- a/src/service/util.rs
+++ b/src/service/util.rs
@@ -1,20 +1,20 @@
-use std::convert::TryFrom;
+use std::convert::{From, TryFrom};
-use serde::Deserialize;
+use serde::{Deserialize, Serialize};
use crate::{domain, origin};
-#[derive(Deserialize)]
-pub struct ConfigFromURL {
+#[derive(Serialize, Deserialize)]
+pub struct FlatConfig {
config_origin_descr_kind: Option,
config_origin_descr_git_url: Option,
config_origin_descr_git_branch_name: Option,
}
-impl TryFrom for Option {
+impl TryFrom for Option {
type Error = String;
- fn try_from(v: ConfigFromURL) -> Result {
+ fn try_from(v: FlatConfig) -> Result {
match v
.config_origin_descr_kind
.unwrap_or("".to_string())
@@ -35,3 +35,15 @@ impl TryFrom for Option {
}
}
}
+
+impl From for FlatConfig {
+ fn from(v: domain::config::Config) -> Self {
+ match v.origin_descr {
+ origin::Descr::Git { url, branch_name } => FlatConfig {
+ config_origin_descr_kind: Some("git".to_string()),
+ config_origin_descr_git_url: Some(url),
+ config_origin_descr_git_branch_name: Some(branch_name),
+ },
+ }
+ }
+}