diff --git a/src/models/errors.rs b/src/models/errors.rs index bfbcd96..688f113 100644 --- a/src/models/errors.rs +++ b/src/models/errors.rs @@ -130,6 +130,20 @@ impl From for ErrorResponse { } } +impl From for ErrorResponse { + fn from(e: models::RecordListParseError) -> Self { + models::ErrorResponse::new( + Status::BadRequest, + "Record list contains records that could not be parsed into DNS records".into() + ).with_details( + json!({ + "zone_name": e.zone.to_utf8(), + "records": e.bad_records + }) + ) + } +} + impl From for Outcome { fn from(e: ErrorResponse) -> Self { diff --git a/src/models/mod.rs b/src/models/mod.rs index 0b387b9..32b6a4e 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -15,5 +15,5 @@ pub use errors::{UserError, ErrorResponse, make_500}; pub use name::{AbsoluteName, SerdeName}; pub use user::{LocalUser, UserInfo, Role, UserZone, User, CreateUserRequest}; pub use rdata::RData; -pub use record::Record; +pub use record::{Record, RecordList, ParseRecordList, RecordListParseError}; pub use zone::{Zone, AddZoneMemberRequest, CreateZoneRequest}; \ No newline at end of file diff --git a/src/models/name.rs b/src/models/name.rs index 0856f11..11438e9 100644 --- a/src/models/name.rs +++ b/src/models/name.rs @@ -69,4 +69,10 @@ impl Deref for AbsoluteName { fn deref(&self) -> &Self::Target { &self.0.0 } +} + +impl AbsoluteName { + pub fn into_inner(self) -> Name { + self.0.0 + } } \ No newline at end of file diff --git a/src/models/rdata.rs b/src/models/rdata.rs index 64c61be..775bce8 100644 --- a/src/models/rdata.rs +++ b/src/models/rdata.rs @@ -247,7 +247,7 @@ impl TryFrom for dns::RData { // TODO: Error out for DNSSEC? Prefer downstream checks? RData::DNSSEC(_) => todo!(), // TODO: Disallow unknown? (could be used to bypass unsopported types?) Prefer downstream checks? - RData::Unknown { code, data } => todo!(), + RData::Unknown { code: _code, data: _data } => todo!(), }) } } diff --git a/src/models/record.rs b/src/models/record.rs index 3c463cd..091a47d 100644 --- a/src/models/record.rs +++ b/src/models/record.rs @@ -40,4 +40,41 @@ impl TryFrom for dns::Record { trust_dns_record.set_dns_class(record.dns_class.into()); Ok(trust_dns_record) } +} + + +pub type RecordList = Vec; + +pub struct RecordListParseError { + pub bad_records: Vec, + pub zone: dns::Name, +} + +pub trait ParseRecordList { + fn try_into_dns_type(self, zone: dns::Name) -> Result, RecordListParseError>; +} + +impl ParseRecordList for RecordList { + fn try_into_dns_type(self, zone: dns::Name) -> Result, RecordListParseError> { + // TODO: What about relative names (also in cnames and stuff) + let mut bad_records = Vec::new(); + let mut records: Vec = Vec::new(); + + for record in self.into_iter() { + let this_record = record.clone(); + if let Ok(record) = record.try_into() { + records.push(record); + } else { + bad_records.push(this_record.clone()); + } + } + + if !bad_records.is_empty() { + return Err(RecordListParseError { + zone, + bad_records, + }); + } + return Ok(records) + } } \ No newline at end of file diff --git a/src/routes/zones.rs b/src/routes/zones.rs index 91032dd..ca91a21 100644 --- a/src/routes/zones.rs +++ b/src/routes/zones.rs @@ -1,14 +1,13 @@ -use std::convert::TryInto; -use serde_json::json; use rocket::Response; use rocket::http::Status; use rocket_contrib::json::Json; use crate::DbConn; -use crate::models; use crate::dns; +use crate::models; use crate::dns::{RecordApi, ZoneApi}; +use crate::models::{ParseRecordList}; #[get("/zones//records")] @@ -58,33 +57,14 @@ pub async fn create_zone_records( } }).await?; - // TODO: What about relative names (also in cnames and stuff) - let mut bad_records = Vec::new(); - let mut records: Vec = Vec::new(); - - for record in new_records.into_inner().into_iter() { - let this_record = record.clone(); - if let Ok(record) = record.try_into() { - records.push(record); - } else { - bad_records.push(this_record.clone()); - } - } - - if !bad_records.is_empty() { - return models::ErrorResponse::new( - Status::BadRequest, - "Record list contains records that could not been parsed into DNS records".into() - ).with_details( - json!({ - "zone_name": zone.to_utf8(), - "records": bad_records - }) - ).err(); - } let mut dns_api = dns::DnsApiClient::new(client); - dns_api.add_records(zone.clone(), dns::DNSClass::IN, records).await?; + + dns_api.add_records( + zone.clone(), + models::DNSClass::IN.into(), + new_records.into_inner().try_into_dns_type(zone.into_inner())? + ).await?; return Ok(Json(())); }