diff options
author | Galen Guyer <galen@galenguyer.com> | 2022-08-31 16:59:43 -0400 |
---|---|---|
committer | Galen Guyer <galen@galenguyer.com> | 2022-08-31 17:03:14 -0400 |
commit | ee62cd357fdb0cfc9116aec7e28162ad684a8599 (patch) | |
tree | f8ceacfa8223e7bbdb94461877f5d07377311fac | |
parent | bcb51966f3446f671558e615cb3dfbe700bc3e23 (diff) |
Validate record before creating or updating
-rw-r--r-- | Cargo.lock | 3 | ||||
-rw-r--r-- | Cargo.toml | 3 | ||||
-rw-r--r-- | src/db/metrics.rs | 5 | ||||
-rw-r--r-- | src/db/mod.rs | 3 | ||||
-rw-r--r-- | src/db/models.rs | 2 | ||||
-rw-r--r-- | src/db/strings.rs | 1 | ||||
-rw-r--r-- | src/features.rs | 4 | ||||
-rw-r--r-- | src/routes/v1/metrics.rs | 14 | ||||
-rw-r--r-- | src/routes/v1/mod.rs | 2 | ||||
-rw-r--r-- | src/routes/v1/records.rs | 28 | ||||
-rw-r--r-- | src/routes/v1/zones.rs | 12 |
11 files changed, 53 insertions, 24 deletions
@@ -545,7 +545,7 @@ dependencies = [ [[package]] name = "hdt-api" -version = "0.1.5" +version = "0.2.0" dependencies = [ "addr", "anyhow", @@ -569,6 +569,7 @@ dependencies = [ "tower", "tower-http", "tracing-subscriber", + "trust-dns-proto", "uuid", "whois-rust", "whoisthere", @@ -1,6 +1,6 @@ [package] name = "hdt-api" -version = "0.1.5" +version = "0.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html @@ -28,6 +28,7 @@ totp-rs = "2.0.0" tower = "0.4.12" tower-http = { version = "0.3.3", features = ["cors", "trace"] } tracing-subscriber = "0.3.11" +trust-dns-proto = "0.21.2" # uuid v1.0.0 is out, but it breaks sqlx... we just have to wait for sqlx to release v0.6 uuid = { version = "0.8.2", features = ["serde", "v4"] } whois-rust = "1.5.0" diff --git a/src/db/metrics.rs b/src/db/metrics.rs index 7557d47..f3ccb77 100644 --- a/src/db/metrics.rs +++ b/src/db/metrics.rs @@ -2,10 +2,7 @@ use crate::db::models::Metrics; use crate::db::strings; use sqlx::{Pool, Postgres}; - -pub async fn get_metrics( - pool: &Pool<Postgres>, -) -> Result<Metrics, sqlx::Error> { +pub async fn get_metrics(pool: &Pool<Postgres>) -> Result<Metrics, sqlx::Error> { let mut transaction = pool.begin().await?; let metrics = sqlx::query_as::<_, Metrics>(&strings::GET_METRICS) .fetch_one(&mut transaction) diff --git a/src/db/mod.rs b/src/db/mod.rs index f06dd3b..6af9b2d 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,8 +1,7 @@ +pub mod metrics; pub mod records; pub mod users; pub mod zones; -pub mod metrics; pub mod models; mod strings; - diff --git a/src/db/models.rs b/src/db/models.rs index 0d82018..64b9290 100644 --- a/src/db/models.rs +++ b/src/db/models.rs @@ -49,4 +49,4 @@ pub struct Metrics { pub p99: f64, pub avg: f64, pub count: i64, -}
\ No newline at end of file +} diff --git a/src/db/strings.rs b/src/db/strings.rs index dc6e44d..b8812e5 100644 --- a/src/db/strings.rs +++ b/src/db/strings.rs @@ -44,7 +44,6 @@ lazy_static! { WHERE api_keys.token_hash = $1 AND api_keys.expires_at > (now() AT TIME ZONE 'UTC'); "; - pub(crate) static ref GET_METRICS: &'static str = r#" SELECT percentile_cont(0.50) WITHIN GROUP (ORDER BY queries.duration_us) AS p50, diff --git a/src/features.rs b/src/features.rs index 378bc46..8f8ff27 100644 --- a/src/features.rs +++ b/src/features.rs @@ -6,6 +6,6 @@ lazy_static! { env::var("SIGNUPS_ENABLED").unwrap_or_else(|_| String::from("false")) == "true"; pub static ref TOTP_ENABLED: bool = env::var("TOTP_ENABLED").unwrap_or_else(|_| String::from("false")) == "true"; - pub static ref METRICS_ENABLED: bool = - env::var("METRICS_URL").is_ok() && env::var("METRICS_ENABLED").unwrap_or_else(|_| String::from("false")) == "true"; + pub static ref METRICS_ENABLED: bool = env::var("METRICS_URL").is_ok() + && env::var("METRICS_ENABLED").unwrap_or_else(|_| String::from("false")) == "true"; } diff --git a/src/routes/v1/metrics.rs b/src/routes/v1/metrics.rs index 38485d0..074bfa0 100644 --- a/src/routes/v1/metrics.rs +++ b/src/routes/v1/metrics.rs @@ -1,5 +1,5 @@ +use crate::extractors::Json; use crate::{db, features}; -use crate::extractors::{Json}; use axum::http::StatusCode; use axum::response::IntoResponse; use axum::Extension; @@ -11,12 +11,18 @@ pub async fn get_metrics( Extension(metrics_pool): Extension<Option<Arc<Pool<Postgres>>>>, ) -> impl IntoResponse { if !*features::METRICS_ENABLED { - return (StatusCode::NOT_FOUND, Json(json!({"error": "Metrics not enabled"}))); + return ( + StatusCode::NOT_FOUND, + Json(json!({"error": "Metrics not enabled"})), + ); } - let metrics = db::metrics::get_metrics(&metrics_pool.as_ref().unwrap()).await; + let metrics = db::metrics::get_metrics(&metrics_pool.unwrap()).await; match metrics { Ok(metrics) => (StatusCode::OK, Json(json!(metrics))), - Err(err) => (StatusCode::INTERNAL_SERVER_ERROR, Json(json!({"error": err.to_string()}))), + Err(err) => ( + StatusCode::INTERNAL_SERVER_ERROR, + Json(json!({"error": err.to_string()})), + ), } } diff --git a/src/routes/v1/mod.rs b/src/routes/v1/mod.rs index df0880d..b1d2e44 100644 --- a/src/routes/v1/mod.rs +++ b/src/routes/v1/mod.rs @@ -1,7 +1,7 @@ pub mod features; +pub mod metrics; pub mod records; pub mod users; pub mod zones; -pub mod metrics; mod requests; diff --git a/src/routes/v1/records.rs b/src/routes/v1/records.rs index fd72663..3c424c9 100644 --- a/src/routes/v1/records.rs +++ b/src/routes/v1/records.rs @@ -7,7 +7,10 @@ use axum::response::IntoResponse; use axum::Extension; use serde_json::json; use sqlx::{Pool, Postgres}; +use std::net::{Ipv4Addr, Ipv6Addr}; +use std::str::FromStr; use std::sync::Arc; +use trust_dns_proto::rr::RecordType; use uuid::Uuid; pub async fn get_records( @@ -68,6 +71,10 @@ pub async fn create_record( ); } + if let Err(e) = validate_record(&data.record_type, &data.content) { + return (StatusCode::BAD_REQUEST, Json(json!({ "error": e }))); + } + let record = db::records::create_record( &pool, &zone.id, @@ -120,6 +127,10 @@ pub async fn update_record( ); } + if let Err(e) = validate_record(&data.record_type, &data.content) { + return (StatusCode::BAD_REQUEST, Json(json!({ "error": e }))); + } + let record = db::records::update_record( &pool, &zone_id, @@ -182,3 +193,20 @@ pub async fn delete_record( })), ) } + +fn validate_record(rtype: &str, content: &str) -> Result<(), String> { + match RecordType::from_str(rtype) { + Ok(rtype) => match rtype { + RecordType::A => content + .parse::<Ipv4Addr>() + .map(|_| ()) + .map_err(|_| String::from("Invalid IPv4 address")), + RecordType::AAAA => content + .parse::<Ipv6Addr>() + .map(|_| ()) + .map_err(|_| String::from("Invalid IPv6 address")), + _ => Err(String::from("Unknown record type")), + }, + _ => Err(String::from("Unknown record type")), + } +} diff --git a/src/routes/v1/zones.rs b/src/routes/v1/zones.rs index ddbeb19..0281948 100644 --- a/src/routes/v1/zones.rs +++ b/src/routes/v1/zones.rs @@ -46,7 +46,7 @@ pub async fn get_root_domain( Extension(pool): Extension<Arc<Pool<Postgres>>>, ) -> impl IntoResponse { let zones = db::zones::get_zones(&pool, user.sub).await; - let domain = match query.domain.ends_with(".") { + let domain = match query.domain.ends_with('.') { true => query.domain, false => format!("{}.", query.domain), }; @@ -89,7 +89,7 @@ pub async fn create_zone( ); } - let lookup = match WhoIsLookupOptions::from_string(&*zone_id.trim_end_matches('.')) { + let lookup = match WhoIsLookupOptions::from_string(zone_id.trim_end_matches('.')) { Ok(lookup) => lookup, Err(e) => { return ( @@ -102,9 +102,7 @@ pub async fn create_zone( } }; let whois_res = match whois_client.lookup(lookup) { - Ok(res) => { - res - } + Ok(res) => res, Err(e) => { return ( StatusCode::BAD_REQUEST, @@ -116,7 +114,7 @@ pub async fn create_zone( } }; - let whois_info = whoisthere::parse_info(&*zone_id.trim_end_matches('.'), &whois_res); + let whois_info = whoisthere::parse_info(zone_id.trim_end_matches('.'), &whois_res); if !whois_info.is_registered || whois_info.is_under_grace_period { return ( StatusCode::BAD_REQUEST, @@ -124,7 +122,7 @@ pub async fn create_zone( "error": "Invalid domain", "message": "Domain is not registered or expired" })), - ) + ); } let zone = db::zones::create_zone(&pool, &zone_id, user.sub).await; |