// trifid-api, an open source reimplementation of the Defined Networking nebula management server. // Copyright (C) 2023 c0repwn3r // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . use actix_web::error::{JsonPayloadError, PayloadError}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct APIErrorsResponse { pub errors: Vec, } #[derive(Serialize, Deserialize, Debug, Clone)] pub struct APIError { pub code: String, pub message: String, #[serde(skip_serializing_if = "is_none")] #[serde(default)] pub path: Option, } fn is_none(o: &Option) -> bool { o.is_none() } impl From<&JsonPayloadError> for APIError { fn from(value: &JsonPayloadError) -> Self { match value { JsonPayloadError::OverflowKnownLength { length, limit } => { APIError { code: "ERR_PAYLOAD_OVERFLOW_KNOWN_LENGTH".to_string(), message: format!("Payload size is bigger than allowed & content length header set. (length: {}, limit: {})", length, limit), path: None } }, JsonPayloadError::Overflow { limit } => { APIError { code: "ERR_PAYLOAD_OVERFLOW".to_string(), message: format!("Payload size is bigger than allowed but no content-length header is set. (limit: {})", limit), path: None } }, JsonPayloadError::ContentType => { APIError { code: "ERR_NOT_JSON".to_string(), message: "Content-Type header not set to expected application/json".to_string(), path: None, } }, JsonPayloadError::Deserialize(e) => { APIError { code: "ERR_JSON_DESERIALIZE".to_string(), message: format!("Error deserializing JSON: {}", e), path: None, } }, JsonPayloadError::Serialize(e) => { APIError { code: "ERR_JSON_SERIALIZE".to_string(), message: format!("Error serializing JSON: {}", e), path: None, } }, JsonPayloadError::Payload(e) => { e.into() }, _ => { APIError { code: "ERR_UNKNOWN_ERROR".to_string(), message: "An unknown error has occured".to_string(), path: None, } } } } } impl From<&PayloadError> for APIError { fn from(value: &PayloadError) -> Self { match value { PayloadError::Incomplete(e) => APIError { code: "ERR_UNEXPECTED_EOF".to_string(), message: match e { None => "Payload reached EOF but was incomplete".to_string(), Some(e) => format!("Payload reached EOF but was incomplete: {}", e), }, path: None, }, PayloadError::EncodingCorrupted => APIError { code: "ERR_CORRUPTED_PAYLOAD".to_string(), message: "Payload content encoding corrupted".to_string(), path: None, }, PayloadError::Overflow => APIError { code: "ERR_PAYLOAD_OVERFLOW".to_string(), message: "Payload reached size limit".to_string(), path: None, }, PayloadError::UnknownLength => APIError { code: "ERR_PAYLOAD_UNKNOWN_LENGTH".to_string(), message: "Unable to determine payload length".to_string(), path: None, }, PayloadError::Http2Payload(e) => APIError { code: "ERR_HTTP2_ERROR".to_string(), message: format!("HTTP/2 error: {}", e), path: None, }, PayloadError::Io(e) => APIError { code: "ERR_IO_ERROR".to_string(), message: format!("I/O error: {}", e), path: None, }, _ => APIError { code: "ERR_UNKNOWN_ERROR".to_string(), message: "An unknown error has occured".to_string(), path: None, }, } } }