2022-10-02 17:44:08 +00:00
|
|
|
use actix_web::{
|
2023-02-19 17:10:29 +00:00
|
|
|
body::{BodySize, BoxBody, MessageBody},
|
2023-02-21 21:39:42 +00:00
|
|
|
dev::{ConnectionInfo, ServiceResponse},
|
2022-10-02 17:44:08 +00:00
|
|
|
error::{Error, JsonPayloadError},
|
2023-02-19 17:10:29 +00:00
|
|
|
http::StatusCode,
|
2023-02-22 15:18:19 +00:00
|
|
|
middleware::{
|
|
|
|
DefaultHeaders,
|
|
|
|
ErrorHandlerResponse,
|
|
|
|
ErrorHandlers,
|
|
|
|
},
|
2023-02-19 16:50:02 +00:00
|
|
|
web::{Form, Json},
|
|
|
|
Either,
|
2023-02-19 17:10:29 +00:00
|
|
|
HttpRequest,
|
2022-10-02 17:44:08 +00:00
|
|
|
};
|
2023-02-19 17:10:29 +00:00
|
|
|
use serde_json::json;
|
2022-10-02 17:44:08 +00:00
|
|
|
|
2023-02-21 21:39:42 +00:00
|
|
|
use mitra_utils::urls::guess_protocol;
|
|
|
|
|
2022-10-02 17:44:08 +00:00
|
|
|
use crate::errors::HttpError;
|
|
|
|
|
2023-02-19 16:50:02 +00:00
|
|
|
pub type FormOrJson<T> = Either<Form<T>, Json<T>>;
|
|
|
|
|
2023-02-19 17:10:29 +00:00
|
|
|
/// Error handler for 401 Unauthorized
|
|
|
|
pub fn create_auth_error_handler<B: MessageBody + 'static>() -> ErrorHandlers<B> {
|
|
|
|
// Creates and returns actix middleware
|
|
|
|
ErrorHandlers::new()
|
|
|
|
.handler(StatusCode::UNAUTHORIZED, |response: ServiceResponse<B>| {
|
|
|
|
let response_new = response.map_body(|_, body| {
|
|
|
|
if let BodySize::None | BodySize::Sized(0) = body.size() {
|
|
|
|
// Insert error description if response body is empty
|
|
|
|
// https://github.com/actix/actix-extras/issues/156
|
|
|
|
let error_data = json!({
|
|
|
|
"message": "auth header is not present",
|
|
|
|
});
|
|
|
|
return BoxBody::new(error_data.to_string());
|
|
|
|
};
|
|
|
|
body.boxed()
|
|
|
|
});
|
|
|
|
Ok(ErrorHandlerResponse::Response(response_new.map_into_right_body()))
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2023-02-22 15:18:19 +00:00
|
|
|
pub fn create_default_headers_middleware() -> DefaultHeaders {
|
|
|
|
DefaultHeaders::new()
|
|
|
|
.add((
|
|
|
|
"Content-Security-Policy",
|
|
|
|
// script-src unsafe-inline required by MetaMask
|
|
|
|
// style-src oauth-authorization required by OAuth authorization page
|
|
|
|
"default-src 'none'; \
|
|
|
|
connect-src 'self'; \
|
|
|
|
img-src 'self' data:; \
|
|
|
|
media-src 'self'; \
|
|
|
|
script-src 'self' 'unsafe-inline'; \
|
|
|
|
style-src 'self' 'nonce-oauth-authorization'; \
|
|
|
|
frame-ancestors 'none'; \
|
|
|
|
base-uri 'self'; \
|
|
|
|
form-action 'self'",
|
|
|
|
))
|
|
|
|
.add(("X-Content-Type-Options", "nosniff"))
|
|
|
|
}
|
|
|
|
|
2023-02-19 16:50:02 +00:00
|
|
|
/// Convert JSON payload deserialization errors into validation errors
|
2022-10-02 17:44:08 +00:00
|
|
|
pub fn json_error_handler(
|
|
|
|
error: JsonPayloadError,
|
|
|
|
_: &HttpRequest,
|
|
|
|
) -> Error {
|
|
|
|
match error {
|
|
|
|
JsonPayloadError::Deserialize(de_error) => {
|
|
|
|
HttpError::ValidationError(de_error.to_string()).into()
|
|
|
|
},
|
|
|
|
other_error => other_error.into(),
|
|
|
|
}
|
|
|
|
}
|
2023-02-21 21:39:42 +00:00
|
|
|
|
|
|
|
pub fn get_request_base_url(connection_info: ConnectionInfo) -> String {
|
|
|
|
// TODO: HTTP server should set X-Forwarded-Proto header
|
|
|
|
// let scheme = connection_info.scheme();
|
|
|
|
let host = connection_info.host();
|
|
|
|
let scheme = if let Some((hostname, _port)) = host.split_once(':') {
|
|
|
|
guess_protocol(hostname)
|
|
|
|
} else {
|
|
|
|
guess_protocol(host)
|
|
|
|
};
|
|
|
|
format!("{}://{}", scheme, host)
|
|
|
|
}
|