nomilo/src/routes/zones.rs

103 lines
2.9 KiB
Rust
Raw Normal View History

2021-05-02 13:56:42 +00:00
use rocket::Response;
2021-04-02 20:09:51 +00:00
use rocket::http::Status;
use rocket_contrib::json::Json;
use trust_dns_client::client::ClientHandle;
2021-04-05 22:56:15 +00:00
use trust_dns_client::op::ResponseCode;
2021-04-05 21:21:40 +00:00
use trust_dns_client::rr::{DNSClass, RecordType};
2021-04-02 20:09:51 +00:00
2021-04-05 22:56:15 +00:00
use crate::{DbConn, models::dns};
use crate::models::errors::{ErrorResponse, make_500};
2021-05-02 13:56:42 +00:00
use crate::models::users::{LocalUser, UserInfo, Zone, AddZoneMemberRequest};
2021-04-02 20:09:51 +00:00
#[get("/zones/<zone>/records")]
pub async fn get_zone_records(
2021-04-05 21:21:40 +00:00
mut client: dns::DnsClient,
2021-04-05 22:56:15 +00:00
conn: DbConn,
2021-04-02 21:12:29 +00:00
user_info: Result<UserInfo, ErrorResponse>,
2021-04-05 21:21:40 +00:00
zone: dns::AbsoluteName
2021-04-02 21:12:29 +00:00
) -> Result<Json<Vec<dns::Record>>, ErrorResponse> {
2021-04-02 20:09:51 +00:00
2021-04-05 22:56:15 +00:00
let user_info = user_info?;
if !user_info.is_admin() {
let zone_name = zone.clone().to_string();
conn.run(move |c| {
2021-05-02 13:56:42 +00:00
user_info.get_zone(c, &zone_name)
2021-04-05 22:56:15 +00:00
}).await?;
}
let response = {
let query = client.query(zone.clone(), DNSClass::IN, RecordType::AXFR);
query.await.map_err(make_500)?
};
2021-04-02 20:09:51 +00:00
2021-05-02 13:56:42 +00:00
// TODO: Better error handling (ex. not authorized should be 500)
2021-04-02 20:09:51 +00:00
if response.response_code() != ResponseCode::NoError {
2021-05-02 13:56:42 +00:00
println!("Querrying of zone {} failed with code {}", *zone, response.response_code());
2021-04-02 20:09:51 +00:00
return ErrorResponse::new(
Status::NotFound,
2021-05-02 13:56:42 +00:00
format!("Zone {} could not be found", *zone)
2021-04-02 20:09:51 +00:00
).err()
}
let answers = response.answers();
let mut records: Vec<_> = answers.to_vec().into_iter()
2021-04-05 01:05:39 +00:00
.map(dns::Record::from)
.filter(|record| !matches!(record.rdata, dns::RData::NULL { .. } | dns::RData::DNSSEC(_)))
.collect();
2021-04-02 20:09:51 +00:00
// AXFR response ends with SOA, we remove it so it is not doubled in the response.
records.pop();
Ok(Json(records))
}
2021-05-02 13:56:42 +00:00
// TODO: the post version of that
#[get("/zones")]
pub async fn get_zones(
conn: DbConn,
user_info: Result<UserInfo, ErrorResponse>,
) -> Result<Json<Vec<Zone>>, 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/<zone>/members", data = "<zone_member_request>")]
pub async fn add_member_to_zone<'r>(
conn: DbConn,
zone: dns::AbsoluteName,
user_info: Result<UserInfo, ErrorResponse>,
zone_member_request: Json<AddZoneMemberRequest>
) -> Result<Response<'r>, 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()
}