use rocket::Response; use rocket::http::Status; use rocket_contrib::json::Json; use trust_dns_client::client::ClientHandle; use trust_dns_client::op::ResponseCode; use trust_dns_client::rr::{DNSClass, RecordType}; use crate::{DbConn, models::dns}; use crate::models::errors::{ErrorResponse, make_500}; use crate::models::users::{LocalUser, UserInfo, Zone, AddZoneMemberRequest}; #[get("/zones//records")] pub async fn get_zone_records( mut client: dns::DnsClient, conn: DbConn, user_info: Result, zone: dns::AbsoluteName ) -> Result>, ErrorResponse> { let user_info = user_info?; if !user_info.is_admin() { let zone_name = zone.clone().to_string(); conn.run(move |c| { user_info.get_zone(c, &zone_name) }).await?; } let response = { let query = client.query(zone.clone(), DNSClass::IN, RecordType::AXFR); query.await.map_err(make_500)? }; // TODO: Better error handling (ex. not authorized should be 500) if response.response_code() != ResponseCode::NoError { println!("Querrying of zone {} failed with code {}", *zone, response.response_code()); return ErrorResponse::new( Status::NotFound, format!("Zone {} could not be found", *zone) ).err() } let answers = response.answers(); let mut records: Vec<_> = answers.to_vec().into_iter() .map(dns::Record::from) .filter(|record| !matches!(record.rdata, dns::RData::NULL { .. } | dns::RData::DNSSEC(_))) .collect(); // AXFR response ends with SOA, we remove it so it is not doubled in the response. records.pop(); Ok(Json(records)) } // TODO: the post version of that #[get("/zones")] pub async fn get_zones( conn: DbConn, user_info: Result, ) -> Result>, ErrorResponse> { let user_info = user_info?; let zones = conn.run(move |c| { if user_info.is_admin() { Zone::get_all(c) } else { user_info.get_zones(c) } }).await?; Ok(Json(zones)) } #[post("/zones//members", data = "")] pub async fn add_member_to_zone<'r>( conn: DbConn, zone: dns::AbsoluteName, user_info: Result, zone_member_request: Json ) -> Result, ErrorResponse> { let user_info = user_info?; let zone_name = zone.to_utf8(); conn.run(move |c| { let zone = if user_info.is_admin() { Zone::get_by_name(c, &zone_name) } else { user_info.get_zone(c, &zone_name) }?; let new_member = LocalUser::get_user_by_uuid(c, &zone_member_request.id)?; zone.add_member(&c, &new_member) }).await?; Response::build() .status(Status::Created) // TODO: change this? .ok() }