Commit ebe15520 authored by Gaël Berthaud-Müller's avatar Gaël Berthaud-Müller
Browse files

use enum for role and fix dns client for async

parent 67e12239
...@@ -795,6 +795,7 @@ dependencies = [ ...@@ -795,6 +795,7 @@ dependencies = [
"rocket_contrib", "rocket_contrib",
"serde", "serde",
"serde_json", "serde_json",
"tokio",
"toml", "toml",
"trust-dns-client", "trust-dns-client",
"trust-dns-proto", "trust-dns-proto",
......
...@@ -22,3 +22,4 @@ djangohashers = { version = "1.4.0", features = ["with_argon2"], default-feature ...@@ -22,3 +22,4 @@ djangohashers = { version = "1.4.0", features = ["with_argon2"], default-feature
jsonwebtoken = "7.2.0" jsonwebtoken = "7.2.0"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
humantime = "2.1.0" humantime = "2.1.0"
tokio = "1"
...@@ -3,3 +3,4 @@ ...@@ -3,3 +3,4 @@
[print_schema] [print_schema]
file = "src/schema.rs" file = "src/schema.rs"
import_types = ["diesel::sql_types::*", "crate::models::users::*"]
...@@ -8,5 +8,5 @@ CREATE TABLE localuser ( ...@@ -8,5 +8,5 @@ CREATE TABLE localuser (
CREATE TABLE user ( CREATE TABLE user (
id VARCHAR NOT NULL PRIMARY KEY, id VARCHAR NOT NULL PRIMARY KEY,
role VARCHAR NOT NULL role TEXT CHECK(role IN ('admin', 'zoneadmin')) NOT NULL -- note: migrate to postgres so enum are actually a thing
); );
...@@ -4,8 +4,15 @@ ...@@ -4,8 +4,15 @@
#[macro_use] extern crate rocket_contrib; #[macro_use] extern crate rocket_contrib;
#[macro_use] extern crate diesel; #[macro_use] extern crate diesel;
use trust_dns_client::client::SyncClient; use trust_dns_client::client::AsyncClient;
use trust_dns_client::tcp::TcpClientConnection; use trust_dns_client::tcp::TcpClientStream;
use trust_dns_proto::xfer::dns_multiplexer::DnsMultiplexer;
use trust_dns_proto::iocompat::AsyncIoTokioAsStd;
use trust_dns_client::rr::dnssec::Signer;
use tokio::net::TcpStream as TokioTcpStream;
use tokio::task;
use std::sync::{Arc, Mutex};
mod models; mod models;
mod config; mod config;
...@@ -19,19 +26,22 @@ use routes::zones::*; ...@@ -19,19 +26,22 @@ use routes::zones::*;
#[database("db")] #[database("db")]
pub struct DbConn(diesel::SqliteConnection); pub struct DbConn(diesel::SqliteConnection);
type DnsClient = SyncClient<TcpClientConnection>; type DnsClient = Arc<Mutex<AsyncClient>>;
#[launch] #[launch]
fn rocket() -> rocket::Rocket { async fn rocket() -> rocket::Rocket {
let app_config = config::load("config.toml".into()); let app_config = config::load("config.toml".into());
println!("{:#?}", app_config); println!("{:#?}", app_config);
let conn = TcpClientConnection::new(app_config.dns.server).unwrap(); let (stream, handle) = TcpClientStream::<AsyncIoTokioAsStd<TokioTcpStream>>::new(app_config.dns.server);
let client = SyncClient::new(conn); let multiplexer = DnsMultiplexer::<_, Signer>::new(stream, handle, None);
let client = AsyncClient::connect(multiplexer);
let (client, bg) = client.await.expect("connection failed");
task::spawn(bg);
rocket::ignite() rocket::ignite()
.manage(client) .manage(Arc::new(Mutex::new(client)))
.manage(app_config) .manage(app_config)
.attach(DbConn::fairing()) .attach(DbConn::fairing())
.mount("/api/v1", routes![get_zone_records, create_auth_token, create_user]) .mount("/api/v1", routes![get_zone_records, create_auth_token, create_user])
......
...@@ -27,10 +27,11 @@ const BEARER: &'static str = "Bearer "; ...@@ -27,10 +27,11 @@ const BEARER: &'static str = "Bearer ";
const AUTH_HEADER: &'static str = "Authentication"; const AUTH_HEADER: &'static str = "Authentication";
#[derive(Debug, DbEnum, Deserialize)] #[derive(Debug, DbEnum, Deserialize, Clone)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "kebab-case")]
pub enum Role { pub enum Role {
Admin, Admin,
#[db_rename = "zoneadmin"]
ZoneAdmin, ZoneAdmin,
} }
...@@ -40,7 +41,7 @@ pub enum Role { ...@@ -40,7 +41,7 @@ pub enum Role {
#[table_name = "user"] #[table_name = "user"]
pub struct User { pub struct User {
pub id: String, pub id: String,
pub role: String, pub role: Role,
} }
#[derive(Debug, Queryable, Identifiable, Insertable)] #[derive(Debug, Queryable, Identifiable, Insertable)]
...@@ -89,7 +90,7 @@ pub struct AuthTokenRequest { ...@@ -89,7 +90,7 @@ pub struct AuthTokenRequest {
#[derive(Debug)] #[derive(Debug)]
pub struct UserInfo { pub struct UserInfo {
pub id: String, pub id: String,
pub role: String, pub role: Role,
pub username: String, pub username: String,
} }
...@@ -176,7 +177,7 @@ impl LocalUser { ...@@ -176,7 +177,7 @@ impl LocalUser {
let new_user = User { let new_user = User {
id: new_user_id.clone(), id: new_user_id.clone(),
// TODO: Use role from request // TODO: Use role from request
role: "zoneadmin".into(), role: Role::ZoneAdmin,
}; };
let new_localuser = LocalUser { let new_localuser = LocalUser {
......
...@@ -3,28 +3,31 @@ use rocket::http::Status; ...@@ -3,28 +3,31 @@ use rocket::http::Status;
use rocket_contrib::json::Json; use rocket_contrib::json::Json;
use trust_dns_client::client::{Client}; use trust_dns_client::client::ClientHandle;
use trust_dns_client::op::{DnsResponse, ResponseCode}; use trust_dns_client::op::{DnsResponse, ResponseCode};
use trust_dns_client::rr::{DNSClass, Name, RecordType}; use trust_dns_client::rr::{DNSClass, Name, RecordType};
use crate::models::dns; use crate::models::dns;
use crate::models::errors::ErrorResponse; use crate::models::errors::{ErrorResponse, make_500};
use crate::models::users::UserInfo; use crate::models::users::UserInfo;
use crate::DnsClient; use crate::DnsClient;
#[get("/zones/<zone>/records")] #[get("/zones/<zone>/records")]
pub fn get_zone_records( pub async fn get_zone_records(
client: State<DnsClient>, client: State<'_, DnsClient>,
user_info: Result<UserInfo, ErrorResponse>, user_info: Result<UserInfo, ErrorResponse>,
zone: String zone: String
) -> Result<Json<Vec<dns::Record>>, ErrorResponse> { ) -> Result<Json<Vec<dns::Record>>, ErrorResponse> {
user_info?; println!("{:#?}", user_info?);
// TODO: Implement FromParam for Name // TODO: Implement FromParam for Name
let name = Name::from_utf8(&zone).unwrap(); let name = Name::from_utf8(&zone).unwrap();
let response: DnsResponse = client.query(&name, DNSClass::IN, RecordType::AXFR).unwrap(); let response: DnsResponse = {
let query = client.lock().unwrap().query(name.clone(), DNSClass::IN, RecordType::AXFR);
query.await.map_err(make_500)?
};
if response.response_code() != ResponseCode::NoError { if response.response_code() != ResponseCode::NoError {
return ErrorResponse::new( return ErrorResponse::new(
......
table! { table! {
use diesel::sql_types::*;
localuser (user_id) { localuser (user_id) {
user_id -> Text, user_id -> Text,
username -> Text, username -> Text,
...@@ -7,9 +9,12 @@ table! { ...@@ -7,9 +9,12 @@ table! {
} }
table! { table! {
use diesel::sql_types::*;
use crate::models::users::*;
user (id) { user (id) {
id -> Text, id -> Text,
role -> Text, role -> RoleMapping,
} }
} }
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment