diff --git a/trifid-api/src/main.rs b/trifid-api/src/main.rs index 56797de..2be2a84 100644 --- a/trifid-api/src/main.rs +++ b/trifid-api/src/main.rs @@ -92,6 +92,7 @@ async fn main() -> Result<(), Box> { .service(routes::v1::roles::create_role_request) .service(routes::v1::roles::get_roles) .service(routes::v1::roles::get_role) + .service(routes::v1::roles::delete_role) }).bind(CONFIG.server.bind)?.run().await?; Ok(()) diff --git a/trifid-api/src/routes/v1/roles.rs b/trifid-api/src/routes/v1/roles.rs index 33aa3d8..daa0277 100644 --- a/trifid-api/src/routes/v1/roles.rs +++ b/trifid-api/src/routes/v1/roles.rs @@ -25,6 +25,10 @@ //#GET /v1/roles/{role_id} t+parity:full t+type:documented t+status:done // This endpoint has full parity with the original API. It has been recreated from the original API documentation. // This endpoint is considered done. No major features should be added or removed, unless it fixes bugs. +// +//#DELETE /v1/roles/{role_id} t+parity:full t+type:documented t+status:done +// This endpoint has full parity with the original API. It has been recreated from the original API documentation. +// This endpoint is considered done. No major features should be added or removed, unless it fixes bugs. use std::time::{SystemTime, UNIX_EPOCH}; use actix_web::{get, HttpRequest, HttpResponse, post}; @@ -41,6 +45,7 @@ use trifid_api_entities::entity::firewall_rule; use trifid_api_entities::entity::role; use crate::cursor::Cursor; use crate::tokens::random_id; +use actix_web::delete; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct CreateRoleRequest { @@ -653,4 +658,98 @@ pub struct GetRoleResponse { pub metadata: GetRoleResponseMetadata } #[derive(Serialize, Deserialize, Debug, Clone)] -pub struct GetRoleResponseMetadata {} \ No newline at end of file +pub struct GetRoleResponseMetadata {} + +#[delete("/v1/roles/{role_id}")] +pub async fn delete_role(net: Path, req_info: HttpRequest, db: Data) -> HttpResponse { + // For this endpoint, you either need to be a fully authenticated user OR a token with roles:delete + let session_info = enforce_2fa(&req_info, &db.conn).await.unwrap_or(TokenInfo::NotPresent); + let api_token_info = enforce_api_token(&req_info, &["roles:delete"], &db.conn).await.unwrap_or(TokenInfo::NotPresent); + + // If neither are present, throw an error + if matches!(session_info, TokenInfo::NotPresent) && matches!(api_token_info, TokenInfo::NotPresent) { + return HttpResponse::Unauthorized().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_UNAUTHORIZED".to_string(), + message: "This endpoint requires either a fully authenticated user or a token with the roles:delete scope".to_string(), + path: None, + } + ], + }) + } + + // If both are present, throw an error + if matches!(session_info, TokenInfo::AuthToken(_)) && matches!(api_token_info, TokenInfo::ApiToken(_)) { + return HttpResponse::BadRequest().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_AMBIGUOUS_AUTHENTICATION".to_string(), + message: "Both a user token and an API token with the proper scope was provided. Please only provide one.".to_string(), + path: None + } + ], + }) + } + + let role: Option = match role::Entity::find().filter(role::Column::Id.eq(net.into_inner())).one(&db.conn).await { + Ok(r) => r, + Err(e) => { + error!("database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error performing the database request, please try again later.".to_string(), + path: None, + } + ], + }); + } + }; + + if let Some(role) = role { + match role.delete(&db.conn).await { + Ok(_) => (), + Err(e) => { + error!("database error: {}", e); + return HttpResponse::InternalServerError().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_DB_ERROR".to_string(), + message: "There was an error performing the database request, please try again later.".to_string(), + path: None, + } + ], + }); + } + }; + + HttpResponse::Ok().json(RoleDeleteResponse { + data: RoleDeleteResponseData {}, + metadata: RoleDeleteResponseMetadata {}, + }) + } else { + HttpResponse::NotFound().json(APIErrorsResponse { + errors: vec![ + APIError { + code: "ERR_MISSING_ROLE".to_string(), + message: "Role does not exist".to_string(), + path: None, + } + ], + }) + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct RoleDeleteResponse { + data: RoleDeleteResponseData, + metadata: RoleDeleteResponseMetadata +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct RoleDeleteResponseData {} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct RoleDeleteResponseMetadata {} \ No newline at end of file