proper error catchers
This commit is contained in:
parent
94d90c21a2
commit
a6ea23c32d
|
@ -1941,6 +1941,7 @@ dependencies = [
|
|||
"base64 0.21.0",
|
||||
"dotenvy",
|
||||
"log",
|
||||
"paste",
|
||||
"rocket",
|
||||
"serde",
|
||||
"sqlx",
|
||||
|
|
|
@ -13,4 +13,5 @@ sqlx = { version = "0.6", features = [ "runtime-tokio-native-tls" , "postgres" ]
|
|||
tokio = { version = "1", features = ["full"] }
|
||||
toml = "0.7.1"
|
||||
serde = "1.0.152"
|
||||
dotenvy = "0.15.6"
|
||||
dotenvy = "0.15.6"
|
||||
paste = "1.0.11"
|
|
@ -1,6 +1,4 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use base64::{decode, Engine};
|
||||
use rocket::info;
|
||||
use crate::format::PEMValidationError::{IncorrectSegmentLength, InvalidBase64Data, MissingStartSentinel};
|
||||
use crate::util::base64decode;
|
||||
|
||||
|
|
|
@ -3,107 +3,17 @@ use std::fs;
|
|||
use std::path::Path;
|
||||
use dotenvy::dotenv;
|
||||
use log::{error, info};
|
||||
use rocket::{routes, post, State, Rocket, Ignite};
|
||||
use rocket::{serde::Serialize};
|
||||
use rocket::http::{ContentType, Status};
|
||||
use rocket::serde::Deserialize;
|
||||
use rocket::serde::json::Json;
|
||||
use rocket::{catchers, routes};
|
||||
use sqlx::migrate::Migrator;
|
||||
use sqlx::PgPool;
|
||||
use sqlx::postgres::PgPoolOptions;
|
||||
use crate::config::TFConfig;
|
||||
use crate::format::{validate_dh_pubkey_base64, validate_ed_pubkey_base64};
|
||||
|
||||
pub mod format;
|
||||
pub mod util;
|
||||
pub mod db;
|
||||
pub mod config;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct EnrollRequest {
|
||||
pub code: String,
|
||||
#[serde(rename = "dhPubkey")]
|
||||
pub dh_pubkey: String,
|
||||
#[serde(rename = "edPubkey")]
|
||||
pub ed_pubkey: String,
|
||||
pub timestamp: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct EnrollResponseMetadata {}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct EnrollResponseOrganization {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct EnrollResponseData {
|
||||
pub config: String,
|
||||
pub host_id: String,
|
||||
pub counter: i64,
|
||||
pub trusted_keys: String,
|
||||
pub organization: EnrollResponseOrganization,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct EnrollResponse {
|
||||
pub data: EnrollResponseData,
|
||||
pub metadata: EnrollResponseMetadata,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct APIError {
|
||||
errors: Vec<APIErrorSingular>
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct APIErrorSingular {
|
||||
code: String,
|
||||
message: String
|
||||
}
|
||||
|
||||
pub const ERR_MSG_MALFORMED_REQUEST: &str = "unable to parse the request body - is it valid JSON, using correct types?";
|
||||
pub const ERR_MSG_MALFORMED_REQUEST_CODE: &str = "ERR_MALFORMED_REQUEST";
|
||||
|
||||
#[post("/v2/enroll", data = "<request>")]
|
||||
fn enroll_endpoint(request: String, pool: &State<PgPool>) -> Result<(ContentType, Json<EnrollResponse>), (Status, Json<APIError>)> {
|
||||
let request: EnrollRequest = match rocket::serde::json::from_str(request.as_str()) {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return Err((Status::BadRequest, Json(APIError { errors: vec![APIErrorSingular { code: ERR_MSG_MALFORMED_REQUEST_CODE.to_string(), message: format!("{} - {}", ERR_MSG_MALFORMED_REQUEST, e) }]})))
|
||||
}
|
||||
};
|
||||
// validate request
|
||||
if let Err(e) = validate_dh_pubkey_base64(request.dh_pubkey.as_str()) {
|
||||
return Err((Status::BadRequest, Json(APIError { errors: vec![APIErrorSingular { code: ERR_MSG_MALFORMED_REQUEST_CODE.to_string(), message: format!("{} - invalid dhPubkey - {}", ERR_MSG_MALFORMED_REQUEST, e) }]})))
|
||||
}
|
||||
if let Err(e) = validate_ed_pubkey_base64(request.ed_pubkey.as_str()) {
|
||||
return Err((Status::BadRequest, Json(APIError { errors: vec![APIErrorSingular { code: ERR_MSG_MALFORMED_REQUEST_CODE.to_string(), message: format!("{} - invalid edPubkey - {}", ERR_MSG_MALFORMED_REQUEST, e) }]})))
|
||||
}
|
||||
Ok((ContentType::JSON, Json(EnrollResponse {
|
||||
data: EnrollResponseData {
|
||||
config: "sdf".to_string(),
|
||||
host_id: "sdf".to_string(),
|
||||
counter: 0,
|
||||
trusted_keys: "sdf".to_string(),
|
||||
organization: EnrollResponseOrganization { id: "99s98d9878fds".to_string(), name: "e3team CA".to_string() },
|
||||
},
|
||||
metadata: EnrollResponseMetadata {},
|
||||
})))
|
||||
}
|
||||
|
||||
#[post("/v1/dnclient")]
|
||||
fn dnclient_endpoint() -> &'static str {
|
||||
"DNClient functionality is not yet implemented"
|
||||
}
|
||||
pub mod routes;
|
||||
|
||||
static MIGRATOR: Migrator = sqlx::migrate!();
|
||||
|
||||
|
@ -165,9 +75,36 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||
info!("[tfapi] building rocket config");
|
||||
|
||||
let figment = rocket::Config::figment().merge(("port", config.listen_port));
|
||||
/*
|
||||
error_handler!(400, "ERR_MALFORMED_REQUEST", "unable to parse the request body, is it properly formatted?");
|
||||
error_handler!(401, "ERR_AUTHENTICATION_REQUIRED", "this endpoint requires authentication but it was not provided");
|
||||
error_handler!(403, "ERR_UNAUTHORIZED", "authorization was provided but it is expired or invalid");
|
||||
error_handler!(404, "ERR_NOT_FOUND", "resource not found");
|
||||
error_handler!(405, "ERR_METHOD_NOT_ALLOWED", "method not allowed for this endpoint");
|
||||
error_handler!(500, "ERR_QL_QUERY_FAILED", "graphql query timed out");
|
||||
error_handler!(501, "ERR_NOT_IMPLEMENTED", "query not supported by this version of graphql");
|
||||
error_handler!(502, "ERR_PROXY_ERR", "servers under load, please try again later");
|
||||
error_handler!(503, "ERR_SERVER_OVERLOADED", "servers under load, please try again later");
|
||||
error_handler!(504, "ERR_PROXY_TIMEOUT", "servers under load, please try again later");
|
||||
error_handler!(505, "ERR_CLIENT_UNSUPPORTED", "your version of dnclient is out of date, please update");
|
||||
|
||||
*/
|
||||
let _ = rocket::custom(figment)
|
||||
.mount("/", routes![enroll_endpoint, dnclient_endpoint])
|
||||
.mount("/", routes![
|
||||
crate::routes::v1::auth::verify_magic_link::verify_magic_link
|
||||
])
|
||||
.register("/", catchers![
|
||||
crate::routes::handler_400,
|
||||
crate::routes::handler_401,
|
||||
crate::routes::handler_403,
|
||||
crate::routes::handler_404,
|
||||
crate::routes::handler_500,
|
||||
crate::routes::handler_501,
|
||||
crate::routes::handler_502,
|
||||
crate::routes::handler_503,
|
||||
crate::routes::handler_504,
|
||||
crate::routes::handler_505,
|
||||
])
|
||||
.manage(pool)
|
||||
.manage(config)
|
||||
.launch().await?;
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
pub mod v1;
|
||||
|
||||
use rocket::catch;
|
||||
use serde::{Serialize};
|
||||
use rocket::http::Status;
|
||||
|
||||
pub const ERR_MSG_MALFORMED_REQUEST: &str = "unable to parse the request body - is it valid JSON, using correct types?";
|
||||
pub const ERR_MSG_MALFORMED_REQUEST_CODE: &str = "ERR_MALFORMED_REQUEST";
|
||||
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct APIError {
|
||||
errors: Vec<APIErrorSingular>
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct APIErrorSingular {
|
||||
code: String,
|
||||
message: String
|
||||
}
|
||||
|
||||
macro_rules! error_handler {
|
||||
($code: expr, $err: expr, $msg: expr) => {
|
||||
::paste::paste! {
|
||||
#[catch($code)]
|
||||
pub fn [<handler_ $code>]() -> (Status, String) {
|
||||
(Status::from_code($code).unwrap(), format!("{{\"errors\":[{{\"code\":\"{}\",\"message\":\"{}\"}}]}}", $err, $msg))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
error_handler!(400, "ERR_MALFORMED_REQUEST", "unable to parse the request body, is it properly formatted?");
|
||||
error_handler!(401, "ERR_AUTHENTICATION_REQUIRED", "this endpoint requires authentication but it was not provided");
|
||||
error_handler!(403, "ERR_UNAUTHORIZED", "authorization was provided but it is expired or invalid");
|
||||
error_handler!(404, "ERR_NOT_FOUND", "resource not found");
|
||||
error_handler!(405, "ERR_METHOD_NOT_ALLOWED", "method not allowed for this endpoint");
|
||||
error_handler!(500, "ERR_QL_QUERY_FAILED", "graphql query timed out");
|
||||
error_handler!(501, "ERR_NOT_IMPLEMENTED", "query not supported by this version of graphql");
|
||||
error_handler!(502, "ERR_PROXY_ERR", "servers under load, please try again later");
|
||||
error_handler!(503, "ERR_SERVER_OVERLOADED", "servers under load, please try again later");
|
||||
error_handler!(504, "ERR_PROXY_TIMEOUT", "servers under load, please try again later");
|
||||
error_handler!(505, "ERR_CLIENT_UNSUPPORTED", "your version of dnclient is out of date, please update");
|
|
@ -0,0 +1 @@
|
|||
pub mod verify_magic_link;
|
|
@ -0,0 +1,38 @@
|
|||
use rocket::http::{ContentType, Status};
|
||||
use rocket::serde::json::Json;
|
||||
use serde::{Serialize, Deserialize};
|
||||
use crate::routes::{APIError, APIErrorSingular, ERR_MSG_MALFORMED_REQUEST, ERR_MSG_MALFORMED_REQUEST_CODE};
|
||||
use rocket::post;
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct VerifyMagicLinkRequest {
|
||||
#[serde(rename = "magicLinkToken")]
|
||||
pub magic_link_token: String,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct VerifyMagicLinkResponseMetadata {}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct VerifyMagicLinkResponseData {
|
||||
#[serde(rename = "sessionToken")]
|
||||
pub session_token: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct VerifyMagicLinkResponse {
|
||||
pub data: VerifyMagicLinkResponseData,
|
||||
pub metadata: VerifyMagicLinkResponseMetadata,
|
||||
}
|
||||
|
||||
#[post("/v1/auth/verify-magic-link", data = "<req>")]
|
||||
pub fn verify_magic_link(req: Json<VerifyMagicLinkRequest>) -> Result<(ContentType, Json<VerifyMagicLinkResponse>), (Status, Json<APIError>)> {
|
||||
// handle request
|
||||
|
||||
Ok((ContentType::JSON, Json(VerifyMagicLinkResponse {
|
||||
data: VerifyMagicLinkResponseData { session_token: "sd[if0sf0dsfsdf".to_string() },
|
||||
metadata: VerifyMagicLinkResponseMetadata {},
|
||||
})))
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
pub mod auth;
|
Loading…
Reference in New Issue