Skip to content

Commit 5f96b0b

Browse files
committed
fix(gateway): normalize ZT domain CRUD keys
1 parent 9c2f9fc commit 5f96b0b

1 file changed

Lines changed: 27 additions & 21 deletions

File tree

dstack/gateway/src/admin_service.rs

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -468,8 +468,9 @@ impl AdminRpc for AdminRpcHandler {
468468
let kv_store = self.state.kv_store();
469469
let cert_resolver = &self.state.cert_resolver;
470470

471+
let domain = normalize_zt_domain(&request.domain)?;
471472
let config = kv_store
472-
.get_zt_domain_config(&request.domain)
473+
.get_zt_domain_config(&domain)
473474
.context("ZT-Domain config not found")?;
474475

475476
Ok(zt_domain_to_proto(config, kv_store, cert_resolver))
@@ -479,13 +480,14 @@ impl AdminRpc for AdminRpcHandler {
479480
let kv_store = self.state.kv_store();
480481
let cert_resolver = &self.state.cert_resolver;
481482

482-
// Check if domain already exists
483-
if kv_store.get_zt_domain_config(&request.domain).is_some() {
484-
bail!("ZT-Domain config already exists: {}", request.domain);
485-
}
486-
487483
let config = proto_to_zt_domain_config(&request, kv_store)?;
488484

485+
// Uniqueness is checked after normalization so wildcard, case, and a
486+
// trailing root dot cannot silently overwrite the same DNS name.
487+
if kv_store.get_zt_domain_config(&config.domain).is_some() {
488+
bail!("ZT-Domain config already exists: {}", config.domain);
489+
}
490+
489491
kv_store.save_zt_domain_config(&config)?;
490492
info!("Added ZT-Domain config: {}", config.domain);
491493

@@ -496,13 +498,13 @@ impl AdminRpc for AdminRpcHandler {
496498
let kv_store = self.state.kv_store();
497499
let cert_resolver = &self.state.cert_resolver;
498500

499-
// Check if config exists
501+
let config = proto_to_zt_domain_config(&request, kv_store)?;
502+
503+
// Check the normalized key rather than the caller's presentation.
500504
kv_store
501-
.get_zt_domain_config(&request.domain)
505+
.get_zt_domain_config(&config.domain)
502506
.context("ZT-Domain config not found")?;
503507

504-
let config = proto_to_zt_domain_config(&request, kv_store)?;
505-
506508
kv_store.save_zt_domain_config(&config)?;
507509
info!("Updated ZT-Domain config: {}", config.domain);
508510

@@ -512,14 +514,14 @@ impl AdminRpc for AdminRpcHandler {
512514
async fn delete_zt_domain(self, request: DeleteZtDomainRequest) -> Result<()> {
513515
let kv_store = self.state.kv_store();
514516

515-
// Check if config exists
517+
let domain = normalize_zt_domain(&request.domain)?;
516518
kv_store
517-
.get_zt_domain_config(&request.domain)
519+
.get_zt_domain_config(&domain)
518520
.context("ZT-Domain config not found")?;
519521

520522
// Delete config (cert data, acme, attestations are kept for historical purposes)
521-
kv_store.delete_zt_domain_config(&request.domain)?;
522-
info!("Deleted ZT-Domain config: {}", request.domain);
523+
kv_store.delete_zt_domain_config(&domain)?;
524+
info!("Deleted ZT-Domain config: {domain}");
523525
Ok(())
524526
}
525527

@@ -792,6 +794,16 @@ fn redact_token(token: &str) -> String {
792794
}
793795
}
794796

797+
fn normalize_zt_domain(domain: &str) -> Result<String> {
798+
let domain = domain.trim().trim_end_matches('.');
799+
let domain = domain
800+
.strip_prefix("*.")
801+
.unwrap_or(domain)
802+
.to_ascii_lowercase();
803+
validate_zt_domain(&domain)?;
804+
Ok(domain)
805+
}
806+
795807
fn validate_zt_domain(domain: &str) -> Result<()> {
796808
if domain.is_empty() || domain.len() > 253 || !domain.is_ascii() {
797809
bail!("domain must be a non-empty ASCII DNS name of at most 253 bytes");
@@ -830,13 +842,7 @@ fn proto_to_zt_domain_config(
830842
.context("specified dns credential not found")?;
831843
}
832844

833-
// Strip wildcard prefix if user entered it
834-
let domain = proto
835-
.domain
836-
.strip_prefix("*.")
837-
.unwrap_or(&proto.domain)
838-
.to_string();
839-
validate_zt_domain(&domain)?;
845+
let domain = normalize_zt_domain(&proto.domain)?;
840846
if proto.port == 0 {
841847
bail!("port must be between 1 and 65535");
842848
}

0 commit comments

Comments
 (0)