Fix up init, implement sync (maybe)
This commit is contained in:
parent
f3394acaf1
commit
6e88ab967f
@ -22,9 +22,6 @@ pub enum NewDNSCheckerError {
|
|||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum CheckDomainError {
|
pub enum CheckDomainError {
|
||||||
#[error("invalid domain name")]
|
|
||||||
InvalidDomainName,
|
|
||||||
|
|
||||||
#[error("target CNAME not set")]
|
#[error("target CNAME not set")]
|
||||||
TargetCNAMENotSet,
|
TargetCNAMENotSet,
|
||||||
|
|
||||||
@ -99,7 +96,7 @@ impl Checker for DNSChecker {
|
|||||||
|
|
||||||
// check that the TXT record with the challenge token is correctly installed on the domain
|
// 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)))?
|
.map_err(|e| CheckDomainError::Unexpected(Box::from(e)))?
|
||||||
.append_domain(domain)
|
.append_domain(domain)
|
||||||
.map_err(|e| CheckDomainError::Unexpected(Box::from(e)))?;
|
.map_err(|e| CheckDomainError::Unexpected(Box::from(e)))?;
|
||||||
|
@ -67,9 +67,6 @@ pub enum SyncWithConfigError {
|
|||||||
#[error("invalid branch name")]
|
#[error("invalid branch name")]
|
||||||
InvalidBranchName,
|
InvalidBranchName,
|
||||||
|
|
||||||
#[error("invalid domain name")]
|
|
||||||
InvalidDomainName,
|
|
||||||
|
|
||||||
#[error("already in progress")]
|
#[error("already in progress")]
|
||||||
AlreadyInProgress,
|
AlreadyInProgress,
|
||||||
|
|
||||||
@ -97,7 +94,6 @@ impl From<origin::store::SyncError> for SyncWithConfigError {
|
|||||||
impl From<checker::CheckDomainError> for SyncWithConfigError {
|
impl From<checker::CheckDomainError> for SyncWithConfigError {
|
||||||
fn from(e: checker::CheckDomainError) -> SyncWithConfigError {
|
fn from(e: checker::CheckDomainError) -> SyncWithConfigError {
|
||||||
match e {
|
match e {
|
||||||
checker::CheckDomainError::InvalidDomainName => SyncWithConfigError::InvalidDomainName,
|
|
||||||
checker::CheckDomainError::TargetCNAMENotSet => SyncWithConfigError::TargetCNAMENotSet,
|
checker::CheckDomainError::TargetCNAMENotSet => SyncWithConfigError::TargetCNAMENotSet,
|
||||||
checker::CheckDomainError::ChallengeTokenNotSet => {
|
checker::CheckDomainError::ChallengeTokenNotSet => {
|
||||||
SyncWithConfigError::ChallengeTokenNotSet
|
SyncWithConfigError::ChallengeTokenNotSet
|
||||||
|
@ -147,15 +147,15 @@ where
|
|||||||
config: Option<domain::config::Config>,
|
config: Option<domain::config::Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
let domain_get = warp::get()
|
let domain = warp::get()
|
||||||
.and(with_renderer.clone())
|
.and(with_renderer.clone())
|
||||||
.and(warp::path!("domain.html"))
|
.and(warp::path!("domain.html"))
|
||||||
.and(warp::query::<DomainGetNewRequest>())
|
.and(warp::query::<DomainGetNewRequest>())
|
||||||
.and(warp::query::<util::ConfigFromURL>())
|
.and(warp::query::<util::FlatConfig>())
|
||||||
.map(
|
.map(
|
||||||
|renderer: Renderer<'_, DM>,
|
|renderer: Renderer<'_, DM>,
|
||||||
req: DomainGetNewRequest,
|
req: DomainGetNewRequest,
|
||||||
domain_config: util::ConfigFromURL| {
|
domain_config: util::FlatConfig| {
|
||||||
match renderer.domain_manager.get_config(&req.domain) {
|
match renderer.domain_manager.get_config(&req.domain) {
|
||||||
Ok(_config) => renderer.render_error_page(500, "TODO not yet implemented"),
|
Ok(_config) => renderer.render_error_page(500, "TODO not yet implemented"),
|
||||||
Err(domain::manager::GetConfigError::NotFound) => {
|
Err(domain::manager::GetConfigError::NotFound) => {
|
||||||
@ -170,7 +170,7 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderer.render_page(
|
renderer.render_page(
|
||||||
"/domain_get_new.html",
|
"/domain.html",
|
||||||
&DomainGetNewResponse {
|
&DomainGetNewResponse {
|
||||||
domain: req.domain,
|
domain: req.domain,
|
||||||
config: domain_config,
|
config: domain_config,
|
||||||
@ -187,30 +187,28 @@ where
|
|||||||
);
|
);
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct DomainPostRequest {
|
struct DomainInitRequest {
|
||||||
_init: bool,
|
|
||||||
domain: domain::Name,
|
domain: domain::Name,
|
||||||
passphrase: String,
|
passphrase: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
let domain_post = warp::post()
|
let domain_init = warp::get()
|
||||||
.and(with_renderer.clone())
|
.and(with_renderer.clone())
|
||||||
.and(warp::path!("domain.html"))
|
.and(warp::path!("domain_init.html"))
|
||||||
.and(warp::query::<DomainPostRequest>())
|
.and(warp::query::<DomainInitRequest>())
|
||||||
.and(warp::query::<util::ConfigFromURL>())
|
.and(warp::query::<util::FlatConfig>())
|
||||||
.map(
|
.map(
|
||||||
|renderer: Renderer<'_, DM>,
|
|renderer: Renderer<'_, DM>,
|
||||||
req: DomainPostRequest,
|
req: DomainInitRequest,
|
||||||
domain_config: util::ConfigFromURL| {
|
domain_config: util::FlatConfig| {
|
||||||
if req.passphrase != renderer.passphrase.as_str() {
|
if req.passphrase != renderer.passphrase.as_str() {
|
||||||
return renderer.render_error_page(401, "Incorrect passphrase");
|
return renderer.render_error_page(401, "Incorrect passphrase");
|
||||||
}
|
}
|
||||||
|
|
||||||
//if req.init {
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct Response {
|
struct Response {
|
||||||
domain: domain::Name,
|
domain: domain::Name,
|
||||||
config: domain::config::Config,
|
flat_config: util::FlatConfig,
|
||||||
target_cname: domain::Name,
|
target_cname: domain::Name,
|
||||||
challenge_token: String,
|
challenge_token: String,
|
||||||
}
|
}
|
||||||
@ -239,15 +237,74 @@ where
|
|||||||
let target_cname = (*renderer.target_cname).clone();
|
let target_cname = (*renderer.target_cname).clone();
|
||||||
|
|
||||||
return renderer.render_page(
|
return renderer.render_page(
|
||||||
"/domain_post_init.html",
|
"/domain_init.html",
|
||||||
&Response {
|
&Response {
|
||||||
domain: req.domain,
|
domain: req.domain,
|
||||||
config: config,
|
flat_config: config.into(),
|
||||||
target_cname: target_cname,
|
target_cname: target_cname,
|
||||||
challenge_token: config_hash,
|
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::<DomainSyncRequest>())
|
||||||
|
.and(warp::query::<util::FlatConfig>())
|
||||||
|
.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<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
Ok(static_dir
|
||||||
.or(index)
|
.or(index)
|
||||||
.or(domain_get)
|
.or(domain)
|
||||||
.or(domain_post)
|
.or(domain_init)
|
||||||
|
.or(domain_sync)
|
||||||
.or(not_found))
|
.or(not_found))
|
||||||
}
|
}
|
||||||
|
@ -10,8 +10,7 @@ automatically updated too!</p>
|
|||||||
<p><em>In the future Cosmux will support more backends than just git
|
<p><em>In the future Cosmux will support more backends than just git
|
||||||
repos.</em></p>
|
repos.</em></p>
|
||||||
|
|
||||||
<form method="POST" action="/domain.html">
|
<form method="GET" action="/domain_init.html">
|
||||||
<input name="init" type="hidden" value="true" />
|
|
||||||
<input name="domain" type="hidden" value="{{ data.domain }}" />
|
<input name="domain" type="hidden" value="{{ data.domain }}" />
|
||||||
<input name="config_origin_descr_kind" type="hidden" value="git" />
|
<input name="config_origin_descr_kind" type="hidden" value="git" />
|
||||||
|
|
26
src/service/http_tpl/domain_init.html
Normal file
26
src/service/http_tpl/domain_init.html
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
<h2>Configure DNS</h2>
|
||||||
|
|
||||||
|
<p>Next you will need to configure your DNS server to point to Cosmux. There are
|
||||||
|
two entries you will need to add:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
A <code>CNAME {{ data.domain }}</code> entry with the value
|
||||||
|
<code>{{ data.target_cname }}</code>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
A <code>TXT _domiply_challenge.{{ data.domain }}</code> entry with the value
|
||||||
|
<code>{{ data.challenge_token }}</code>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>Once complete, you can hit the following button to check your configuration
|
||||||
|
and set up your domain.</p>
|
||||||
|
|
||||||
|
<form method="GET" action="/domain_sync.html">
|
||||||
|
<input name="domain" type="hidden" value="{{ data.domain }}" />
|
||||||
|
{{ #each data.flat_config }}
|
||||||
|
<input name="{{ @key }}" type="hidden" value="{{ this }}" />
|
||||||
|
{{ /each }}
|
||||||
|
<input type="submit" value="Next" />
|
||||||
|
</form>
|
13
src/service/http_tpl/domain_sync.html
Normal file
13
src/service/http_tpl/domain_sync.html
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{{#if data.error_msg}}
|
||||||
|
|
||||||
|
<p>Your domain is not yet set up.</p>
|
||||||
|
<p>{{ data.error_msg }}</p>
|
||||||
|
|
||||||
|
{{ else }}
|
||||||
|
|
||||||
|
<p>Congratulations! Your domain has been successfully configured. You can visit
|
||||||
|
it at:</p>
|
||||||
|
|
||||||
|
<p><a href="http://{{ data.domain }}">http://{{ data.domain }}</a></p>
|
||||||
|
|
||||||
|
{{/if}}
|
@ -1,20 +1,20 @@
|
|||||||
use std::convert::TryFrom;
|
use std::convert::{From, TryFrom};
|
||||||
|
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{domain, origin};
|
use crate::{domain, origin};
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
pub struct ConfigFromURL {
|
pub struct FlatConfig {
|
||||||
config_origin_descr_kind: Option<String>,
|
config_origin_descr_kind: Option<String>,
|
||||||
config_origin_descr_git_url: Option<String>,
|
config_origin_descr_git_url: Option<String>,
|
||||||
config_origin_descr_git_branch_name: Option<String>,
|
config_origin_descr_git_branch_name: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<ConfigFromURL> for Option<domain::config::Config> {
|
impl TryFrom<FlatConfig> for Option<domain::config::Config> {
|
||||||
type Error = String;
|
type Error = String;
|
||||||
|
|
||||||
fn try_from(v: ConfigFromURL) -> Result<Self, Self::Error> {
|
fn try_from(v: FlatConfig) -> Result<Self, Self::Error> {
|
||||||
match v
|
match v
|
||||||
.config_origin_descr_kind
|
.config_origin_descr_kind
|
||||||
.unwrap_or("".to_string())
|
.unwrap_or("".to_string())
|
||||||
@ -35,3 +35,15 @@ impl TryFrom<ConfigFromURL> for Option<domain::config::Config> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<domain::config::Config> 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),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user