update rocket

main
Hannaeko 2022-04-22 19:16:57 +02:00
parent ede7a46a59
commit 06caf83e05
10 changed files with 776 additions and 591 deletions

1281
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
name = "nomilo" name = "nomilo"
version = "0.1.0-dev" version = "0.1.0-dev"
authors = ["Gaël Berthaud-Müller <blacksponge@tuta.io>"] authors = ["Gaël Berthaud-Müller <blacksponge@tuta.io>"]
edition = "2018" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -11,8 +11,8 @@ trust-dns-client = "0.20.1"
trust-dns-proto = "0.20.1" trust-dns-proto = "0.20.1"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0" serde_json = "1.0"
rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "0654890", version = "0.5.0-dev" } rocket = { git = "https://github.com/SergioBenitez/Rocket", rev = "6bdd2f8", version = "0.5.0-rc.1", features = ["json"] }
rocket_contrib = { git = "https://github.com/SergioBenitez/Rocket", rev = "0654890", default-features = false, features = ["json", "diesel_sqlite_pool"], version = "0.5.0-dev"} rocket_sync_db_pools = { git = "https://github.com/SergioBenitez/Rocket", rev = "6bdd2f8", default-features = false, features = ["diesel_sqlite_pool"], version = "0.1.0-rc.1"}
toml = "0.5" toml = "0.5"
base64 = "0.13.0" base64 = "0.13.0"
uuid = { version = "0.8.2", features = ["v4", "serde"] } uuid = { version = "0.8.2", features = ["v4", "serde"] }

View File

@ -8,12 +8,12 @@ use chrono::Duration;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct Config { pub struct Config {
pub dns: DnsConfig, pub dns: DnsClientConfig,
pub web_app: WebAppConfig, pub web_app: WebAppConfig,
} }
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
pub struct DnsConfig { pub struct DnsClientConfig {
pub server: SocketAddr pub server: SocketAddr
} }

View File

@ -1,7 +1,9 @@
use std::{future::Future, pin::Pin, task::{Context, Poll}}; use std::{future::Future, pin::Pin, task::{Context, Poll}};
use std::net::SocketAddr;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use rocket::{Request, State, http::Status, request::{FromRequest, Outcome}}; use rocket::{Request, State, http::Status, request::{FromRequest, Outcome}};
use rocket::outcome::try_outcome;
use tokio::{net::TcpStream as TokioTcpStream, task}; use tokio::{net::TcpStream as TokioTcpStream, task};
use trust_dns_client::{client::AsyncClient, error::ClientError, op::DnsResponse, tcp::TcpClientStream}; use trust_dns_client::{client::AsyncClient, error::ClientError, op::DnsResponse, tcp::TcpClientStream};
use trust_dns_proto::error::ProtoError; use trust_dns_proto::error::ProtoError;
@ -10,7 +12,6 @@ use trust_dns_proto::iocompat::AsyncIoTokioAsStd;
use crate::config::Config; use crate::config::Config;
pub struct DnsClient(AsyncClient); pub struct DnsClient(AsyncClient);
impl Deref for DnsClient { impl Deref for DnsClient {
@ -27,27 +28,33 @@ impl DerefMut for DnsClient {
} }
} }
impl DnsClient {
#[rocket::async_trait] pub async fn new(addr: SocketAddr) -> Result<Self, ProtoError> {
impl<'r> FromRequest<'r> for DnsClient { let (stream, handle) = TcpClientStream::<AsyncIoTokioAsStd<TokioTcpStream>>::new(addr);
type Error = ();
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let config = try_outcome!(request.guard::<State<Config>>().await);
let (stream, handle) = TcpClientStream::<AsyncIoTokioAsStd<TokioTcpStream>>::new(config.dns.server);
let client = AsyncClient::with_timeout( let client = AsyncClient::with_timeout(
stream, stream,
handle, handle,
std::time::Duration::from_secs(5), std::time::Duration::from_secs(5),
None); None);
let (client, bg) = match client.await { let (client, bg) = client.await?;
task::spawn(bg);
return Ok(DnsClient(client))
}
}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for DnsClient {
type Error = ();
async fn from_request(request: &'r Request<'_>) -> Outcome<Self, Self::Error> {
let config = try_outcome!(request.guard::<&State<Config>>().await);
match DnsClient::new(config.dns.server).await {
Err(e) => { Err(e) => {
println!("Failed to connect to DNS server {:#?}", e); println!("Failed to connect to DNS server {:#?}", e);
return Outcome::Failure((Status::InternalServerError, ())) Outcome::Failure((Status::InternalServerError, ()))
}, },
Ok(c) => c Ok(c) => Outcome::Success(c)
}; }
task::spawn(bg);
Outcome::Success(DnsClient(client))
} }
} }

View File

@ -1,7 +1,6 @@
#![feature(proc_macro_hygiene, decl_macro)] #![feature(proc_macro_hygiene, decl_macro)]
#[macro_use] extern crate rocket; #[macro_use] extern crate rocket;
#[macro_use] extern crate rocket_contrib;
#[macro_use] extern crate diesel; #[macro_use] extern crate diesel;
mod models; mod models;
@ -12,17 +11,18 @@ mod dns;
use routes::users::*; use routes::users::*;
use routes::zones::*; use routes::zones::*;
use rocket_sync_db_pools::database;
#[database("db")] #[database("db")]
pub struct DbConn(diesel::SqliteConnection); pub struct DbConn(diesel::SqliteConnection);
#[launch] #[launch]
async fn rocket() -> rocket::Rocket { async fn rocket() -> _ {
let app_config = config::load("config.toml".into()); let app_config = config::load("config.toml".into());
println!("{:#?}", app_config); println!("{:#?}", app_config);
rocket::ignite() rocket::build()
.manage(app_config) .manage(app_config)
.attach(DbConn::fairing()) .attach(DbConn::fairing())
.mount("/api/v1", routes![ .mount("/api/v1", routes![

View File

@ -1,8 +1,9 @@
use serde::Serialize; use serde::Serialize;
use serde_json::json;
use rocket::http::Status; use rocket::http::Status;
use rocket::request::{Request, Outcome}; use rocket::request::{Request, Outcome};
use rocket::response::{self, Response, Responder}; use rocket::response::{self, Response, Responder};
use rocket_contrib::json::Json; use rocket::serde::json::Json;
use serde_json::Value; use serde_json::Value;
use djangohashers::{HasherError}; use djangohashers::{HasherError};
use diesel::result::Error as DieselError; use diesel::result::Error as DieselError;
@ -50,8 +51,8 @@ pub struct ErrorResponse {
#[serde(remote = "Status")] #[serde(remote = "Status")]
struct StatusDef { struct StatusDef {
code: u16, code: u16,
#[serde(rename = "status")] #[serde(rename = "status", getter = "Status::reason")]
reason: &'static str, reason: Option<&'static str>,
} }
impl ErrorResponse { impl ErrorResponse {

View File

@ -95,7 +95,7 @@ pub enum RData {
}, },
// ZERO, // ZERO,
// TODO: DS // TODO: DS (added in https://github.com/bluejekyll/trust-dns/pull/1635)
// TODO: TLSA // TODO: TLSA
} }
@ -254,7 +254,7 @@ impl TryFrom<RData> for dns::RData {
struct CAAValue<'a>(&'a dns::caa::Value); struct CAAValue<'a>(&'a dns::caa::Value);
// trust_dns Display implementation panics if no parameters // trust_dns Display implementation panics if no parameters (fixed in https://github.com/bluejekyll/trust-dns/pull/1631)
// Implementation based on caa::emit_value // Implementation based on caa::emit_value
// Also the quotes are strips to render in JSON // Also the quotes are strips to render in JSON
impl<'a> fmt::Display for CAAValue<'a> { impl<'a> fmt::Display for CAAValue<'a> {

View File

@ -3,6 +3,7 @@ use diesel::prelude::*;
use diesel::result::Error as DieselError; use diesel::result::Error as DieselError;
use diesel_derive_enum::DbEnum; use diesel_derive_enum::DbEnum;
use rocket::{State, request::{FromRequest, Request, Outcome}}; use rocket::{State, request::{FromRequest, Request, Outcome}};
use rocket::outcome::try_outcome;
use serde::{Deserialize}; use serde::{Deserialize};
// TODO: Maybe just use argon2 crate directly // TODO: Maybe just use argon2 crate directly
use djangohashers::{make_password_with_algorithm, check_password, Algorithm}; use djangohashers::{make_password_with_algorithm, check_password, Algorithm};
@ -129,7 +130,7 @@ impl<'r> FromRequest<'r> for UserInfo {
return ErrorResponse::from(UserError::MalformedHeader).into() return ErrorResponse::from(UserError::MalformedHeader).into()
}; };
let config = try_outcome!(request.guard::<State<Config>>().await.map_failure(make_500)); let config = try_outcome!(request.guard::<&State<Config>>().await.map_failure(make_500));
let conn = try_outcome!(request.guard::<DbConn>().await.map_failure(make_500)); let conn = try_outcome!(request.guard::<DbConn>().await.map_failure(make_500));
let token_data = AuthClaims::decode( let token_data = AuthClaims::decode(

View File

@ -1,5 +1,5 @@
use rocket_contrib::json::Json; use rocket::serde::json::Json;
use rocket::{Response, State}; use rocket::State;
use rocket::http::Status; use rocket::http::Status;
use crate::config::Config; use crate::config::Config;
@ -10,7 +10,7 @@ use crate::models;
#[post("/users/me/token", data = "<auth_request>")] #[post("/users/me/token", data = "<auth_request>")]
pub async fn create_auth_token( pub async fn create_auth_token(
conn: DbConn, conn: DbConn,
config: State<'_, Config>, config: &State<Config>,
auth_request: Json<models::AuthTokenRequest> auth_request: Json<models::AuthTokenRequest>
) -> Result<Json<models::AuthTokenResponse>, models::ErrorResponse> { ) -> Result<Json<models::AuthTokenResponse>, models::ErrorResponse> {
@ -26,13 +26,11 @@ pub async fn create_auth_token(
} }
#[post("/users", data = "<user_request>")] #[post("/users", data = "<user_request>")]
pub async fn create_user<'r>(conn: DbConn, user_request: Json<models::CreateUserRequest>) -> Result<Response<'r>, models::ErrorResponse> { pub async fn create_user<'r>(conn: DbConn, user_request: Json<models::CreateUserRequest>) -> Result<Status, models::ErrorResponse> {
// TODO: Check current user if any to check if user has permission to create users (with or without role) // TODO: Check current user if any to check if user has permission to create users (with or without role)
conn.run(|c| { conn.run(|c| {
models::LocalUser::create_user(&c, user_request.into_inner()) models::LocalUser::create_user(&c, user_request.into_inner())
}).await?; }).await?;
Response::build() Ok(Status::Created)
.status(Status::Created)
.ok()
} }

View File

@ -1,7 +1,6 @@
use rocket::Response;
use rocket::http::Status; use rocket::http::Status;
use rocket_contrib::json::Json; use rocket::serde::json::Json;
use crate::DbConn; use crate::DbConn;
use crate::dns::{DnsClient, DnsConnectorClient, RecordConnector, ZoneConnector}; use crate::dns::{DnsClient, DnsConnectorClient, RecordConnector, ZoneConnector};
@ -176,7 +175,7 @@ pub async fn add_member_to_zone<'r>(
zone: models::AbsoluteName, zone: models::AbsoluteName,
user_info: Result<models::UserInfo, models::ErrorResponse>, user_info: Result<models::UserInfo, models::ErrorResponse>,
zone_member_request: Json<models::AddZoneMemberRequest> zone_member_request: Json<models::AddZoneMemberRequest>
) -> Result<Response<'r>, models::ErrorResponse> { ) -> Result<Status, models::ErrorResponse> {
let user_info = user_info?; let user_info = user_info?;
let zone_name = zone.to_utf8(); let zone_name = zone.to_utf8();
@ -191,7 +190,5 @@ pub async fn add_member_to_zone<'r>(
zone.add_member(&c, &new_member) zone.add_member(&c, &new_member)
}).await?; }).await?;
Response::build() Ok(Status::Created) // TODO: change this?
.status(Status::Created) // TODO: change this?
.ok()
} }