Skip to content

Commit 9143384

Browse files
authored
client-api: Resolve organization names via the tld, not the dns table (#4266)
As specified in the proposal.
1 parent 253095a commit 9143384

4 files changed

Lines changed: 47 additions & 11 deletions

File tree

crates/client-api/src/lib.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -263,8 +263,9 @@ pub trait ControlStateReadAccess {
263263
async fn get_energy_balance(&self, identity: &Identity) -> anyhow::Result<Option<EnergyBalance>>;
264264

265265
// DNS
266-
async fn lookup_identity(&self, domain: &str) -> anyhow::Result<Option<Identity>>;
266+
async fn lookup_database_identity(&self, domain: &str) -> anyhow::Result<Option<Identity>>;
267267
async fn reverse_lookup(&self, database_identity: &Identity) -> anyhow::Result<Vec<DomainName>>;
268+
async fn lookup_namespace_owner(&self, name: &str) -> anyhow::Result<Option<Identity>>;
268269
}
269270

270271
/// Write operations on the SpacetimeDB control plane.
@@ -355,22 +356,26 @@ impl<T: ControlStateReadAccess + Send + Sync + Sync + ?Sized> ControlStateReadAc
355356
(**self).get_replicas().await
356357
}
357358

359+
async fn get_leader_replica_by_database(&self, database_id: u64) -> Option<Replica> {
360+
(**self).get_leader_replica_by_database(database_id).await
361+
}
362+
358363
// Energy
359364
async fn get_energy_balance(&self, identity: &Identity) -> anyhow::Result<Option<EnergyBalance>> {
360365
(**self).get_energy_balance(identity).await
361366
}
362367

363368
// DNS
364-
async fn lookup_identity(&self, domain: &str) -> anyhow::Result<Option<Identity>> {
365-
(**self).lookup_identity(domain).await
369+
async fn lookup_database_identity(&self, domain: &str) -> anyhow::Result<Option<Identity>> {
370+
(**self).lookup_database_identity(domain).await
366371
}
367372

368373
async fn reverse_lookup(&self, database_identity: &Identity) -> anyhow::Result<Vec<DomainName>> {
369374
(**self).reverse_lookup(database_identity).await
370375
}
371376

372-
async fn get_leader_replica_by_database(&self, database_id: u64) -> Option<Replica> {
373-
(**self).get_leader_replica_by_database(database_id).await
377+
async fn lookup_namespace_owner(&self, name: &str) -> anyhow::Result<Option<Identity>> {
378+
(**self).lookup_namespace_owner(name).await
374379
}
375380
}
376381

crates/client-api/src/routes/database.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -715,7 +715,7 @@ pub async fn publish<S: NodeDelegate + ControlStateDelegate + Authorization>(
715715
};
716716
let maybe_org_identity = match organization.as_ref() {
717717
None => None,
718-
Some(org) => org.resolve(&ctx).await.map(Some)?,
718+
Some(org) => org.resolve_namespace_owner(&ctx).await.map(Some)?,
719719
};
720720

721721
// Check that the replication factor looks somewhat sane.
@@ -1093,7 +1093,7 @@ pub async fn set_names<S: ControlStateDelegate + Authorization>(
10931093
})?;
10941094

10951095
for name in &validated_names {
1096-
if ctx.lookup_identity(name.as_str()).await.unwrap().is_some() {
1096+
if ctx.lookup_database_identity(name.as_str()).await.unwrap().is_some() {
10971097
return Ok((
10981098
StatusCode::BAD_REQUEST,
10991099
axum::Json(name::SetDomainsResult::OtherError(format!(

crates/client-api/src/util.rs

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ impl NameOrIdentity {
100100
) -> anyhow::Result<Result<Identity, &DatabaseName>> {
101101
Ok(match self {
102102
Self::Identity(identity) => Ok(Identity::from(*identity)),
103-
Self::Name(name) => ctx.lookup_identity(name.as_ref()).await?.ok_or(name),
103+
Self::Name(name) => ctx.lookup_database_identity(name.as_ref()).await?.ok_or(name),
104104
})
105105
}
106106

@@ -111,7 +111,31 @@ impl NameOrIdentity {
111111
self.try_resolve(ctx)
112112
.await
113113
.map_err(log_and_500)?
114-
.map_err(|name| (StatusCode::NOT_FOUND, format!("Could not resolve database `{name}`")).into())
114+
.map_err(|name| (StatusCode::NOT_FOUND, format!("`{name}` not found")).into())
115+
}
116+
117+
/// If `self` is a [`NameOrIdentity::Name`], looks up the name in the
118+
/// namespace registry (also known as "top level domain") and returns the
119+
/// owner identity if found.
120+
///
121+
/// If the name is not found, returns a 404 (Not Found) error response.
122+
///
123+
/// If `self` is a [`NameOrIdentity::Identity`], returns the identity.
124+
//
125+
// NOTE: Namespace (TLD) owner identities are also used as organization
126+
// identities.
127+
pub async fn resolve_namespace_owner(
128+
&self,
129+
ctx: &(impl ControlStateReadAccess + ?Sized),
130+
) -> axum::response::Result<Identity> {
131+
match self {
132+
Self::Identity(identity) => Ok(Identity::from(*identity)),
133+
Self::Name(name) => ctx
134+
.lookup_namespace_owner(name.as_ref())
135+
.await
136+
.map_err(log_and_500)?
137+
.ok_or_else(|| (StatusCode::NOT_FOUND, format!("`{name}` not found")).into()),
138+
}
115139
}
116140
}
117141

crates/standalone/src/lib.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ use spacetimedb::worker_metrics::WORKER_METRICS;
2323
use spacetimedb_client_api::auth::{self, LOCALHOST};
2424
use spacetimedb_client_api::routes::subscribe::{HasWebSocketOptions, WebSocketOptions};
2525
use spacetimedb_client_api::{ControlStateReadAccess, DatabaseResetDef, Host, NodeDelegate};
26-
use spacetimedb_client_api_messages::name::{DomainName, InsertDomainResult, RegisterTldResult, SetDomainsResult, Tld};
26+
use spacetimedb_client_api_messages::name::{
27+
DatabaseName, DomainName, InsertDomainResult, RegisterTldResult, SetDomainsResult, Tld,
28+
};
2729
use spacetimedb_datastore::db_metrics::data_size::DATA_SIZE_METRICS;
2830
use spacetimedb_datastore::db_metrics::DB_METRICS;
2931
use spacetimedb_datastore::traits::Program;
@@ -240,13 +242,18 @@ impl spacetimedb_client_api::ControlStateReadAccess for StandaloneEnv {
240242
}
241243

242244
// DNS
243-
async fn lookup_identity(&self, domain: &str) -> anyhow::Result<Option<Identity>> {
245+
async fn lookup_database_identity(&self, domain: &str) -> anyhow::Result<Option<Identity>> {
244246
Ok(self.control_db.spacetime_dns(domain)?)
245247
}
246248

247249
async fn reverse_lookup(&self, database_identity: &Identity) -> anyhow::Result<Vec<DomainName>> {
248250
Ok(self.control_db.spacetime_reverse_dns(database_identity)?)
249251
}
252+
253+
async fn lookup_namespace_owner(&self, name: &str) -> anyhow::Result<Option<Identity>> {
254+
let name: DatabaseName = name.parse()?;
255+
Ok(self.control_db.spacetime_lookup_tld(Tld::from(name))?)
256+
}
250257
}
251258

252259
#[async_trait]

0 commit comments

Comments
 (0)