mirror of
https://forgejo.ellis.link/continuwuation/continuwuity.git
synced 2026-05-26 20:49:55 +00:00
feat: Add a panic handler and clean up error page
This commit is contained in:
+19
-3
@@ -1,3 +1,5 @@
|
|||||||
|
use std::any::Any;
|
||||||
|
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use axum::{
|
use axum::{
|
||||||
Router,
|
Router,
|
||||||
@@ -6,7 +8,7 @@ use axum::{
|
|||||||
response::{Html, IntoResponse, Response},
|
response::{Html, IntoResponse, Response},
|
||||||
};
|
};
|
||||||
use conduwuit_service::state;
|
use conduwuit_service::state;
|
||||||
use tower_http::set_header::SetResponseHeaderLayer;
|
use tower_http::{catch_panic::CatchPanicLayer, set_header::SetResponseHeaderLayer};
|
||||||
use tower_sec_fetch::SecFetchLayer;
|
use tower_sec_fetch::SecFetchLayer;
|
||||||
|
|
||||||
use crate::pages::TemplateContext;
|
use crate::pages::TemplateContext;
|
||||||
@@ -26,7 +28,7 @@ enum WebError {
|
|||||||
QueryRejection(#[from] QueryRejection),
|
QueryRejection(#[from] QueryRejection),
|
||||||
#[error("{0}")]
|
#[error("{0}")]
|
||||||
FormRejection(#[from] FormRejection),
|
FormRejection(#[from] FormRejection),
|
||||||
#[error("Bad request: {0}")]
|
#[error("{0}")]
|
||||||
BadRequest(String),
|
BadRequest(String),
|
||||||
|
|
||||||
#[error("This page does not exist.")]
|
#[error("This page does not exist.")]
|
||||||
@@ -34,8 +36,10 @@ enum WebError {
|
|||||||
|
|
||||||
#[error("Failed to render template: {0}")]
|
#[error("Failed to render template: {0}")]
|
||||||
Render(#[from] askama::Error),
|
Render(#[from] askama::Error),
|
||||||
#[error("Internal server error: {0}")]
|
#[error("{0}")]
|
||||||
InternalError(#[from] conduwuit_core::Error),
|
InternalError(#[from] conduwuit_core::Error),
|
||||||
|
#[error("Request handler panicked! {0}")]
|
||||||
|
Panic(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IntoResponse for WebError {
|
impl IntoResponse for WebError {
|
||||||
@@ -85,8 +89,20 @@ pub fn build() -> Router<state::State> {
|
|||||||
Router::new()
|
Router::new()
|
||||||
.merge(resources::build())
|
.merge(resources::build())
|
||||||
.merge(password_reset::build())
|
.merge(password_reset::build())
|
||||||
|
.merge(debug::build())
|
||||||
.fallback(async || WebError::NotFound),
|
.fallback(async || WebError::NotFound),
|
||||||
)
|
)
|
||||||
|
.layer(CatchPanicLayer::custom(|panic: Box<dyn Any + Send + 'static>| {
|
||||||
|
let details = if let Some(s) = panic.downcast_ref::<String>() {
|
||||||
|
s.clone()
|
||||||
|
} else if let Some(s) = panic.downcast_ref::<&str>() {
|
||||||
|
(*s).to_owned()
|
||||||
|
} else {
|
||||||
|
"(opaque panic payload)".to_owned()
|
||||||
|
};
|
||||||
|
|
||||||
|
WebError::Panic(details).into_response()
|
||||||
|
}))
|
||||||
.layer(SetResponseHeaderLayer::if_not_present(
|
.layer(SetResponseHeaderLayer::if_not_present(
|
||||||
header::CONTENT_SECURITY_POLICY,
|
header::CONTENT_SECURITY_POLICY,
|
||||||
HeaderValue::from_static("default-src 'self'; img-src 'self' data:;"),
|
HeaderValue::from_static("default-src 'self'; img-src 'self' data:;"),
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
use std::convert::Infallible;
|
||||||
|
|
||||||
|
use axum::{Router, routing::get};
|
||||||
|
use conduwuit_core::Error;
|
||||||
|
|
||||||
|
use crate::WebError;
|
||||||
|
|
||||||
|
pub(crate) fn build() -> Router<crate::State> {
|
||||||
|
Router::new()
|
||||||
|
.route("/_debug/panic", get(async || -> Infallible { panic!("Guru meditation error") }))
|
||||||
|
.route(
|
||||||
|
"/_debug/error",
|
||||||
|
get(async || -> WebError {
|
||||||
|
Error::Err(std::borrow::Cow::Borrowed("Guru meditation error")).into()
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
mod components;
|
mod components;
|
||||||
|
pub(super) mod debug;
|
||||||
pub(super) mod index;
|
pub(super) mod index;
|
||||||
pub(super) mod password_reset;
|
pub(super) mod password_reset;
|
||||||
pub(super) mod resources;
|
pub(super) mod resources;
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ use crate::{
|
|||||||
template,
|
template,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const INVALID_TOKEN_ERROR: &str = "Invalid reset token. Your reset link may have expired.";
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct PasswordResetQuery {
|
struct PasswordResetQuery {
|
||||||
token: String,
|
token: String,
|
||||||
@@ -67,7 +69,7 @@ async fn password_reset_form(
|
|||||||
reset_form: Form<'static>,
|
reset_form: Form<'static>,
|
||||||
) -> Result<impl IntoResponse, WebError> {
|
) -> Result<impl IntoResponse, WebError> {
|
||||||
let Some(token) = services.password_reset.check_token(&query.token).await else {
|
let Some(token) = services.password_reset.check_token(&query.token).await else {
|
||||||
return Err(WebError::BadRequest("Invalid reset token".to_owned()));
|
return Err(WebError::BadRequest(INVALID_TOKEN_ERROR.to_owned()));
|
||||||
};
|
};
|
||||||
|
|
||||||
let user_card = UserCard::for_local_user(&services, &token.info.user).await;
|
let user_card = UserCard::for_local_user(&services, &token.info.user).await;
|
||||||
@@ -96,7 +98,7 @@ async fn post_password_reset(
|
|||||||
match form.validate() {
|
match form.validate() {
|
||||||
| Ok(()) => {
|
| Ok(()) => {
|
||||||
let Some(token) = services.password_reset.check_token(&query.token).await else {
|
let Some(token) = services.password_reset.check_token(&query.token).await else {
|
||||||
return Err(WebError::BadRequest("Invalid reset token".to_owned()));
|
return Err(WebError::BadRequest(INVALID_TOKEN_ERROR.to_owned()));
|
||||||
};
|
};
|
||||||
let user_id = token.info.user.clone();
|
let user_id = token.info.user.clone();
|
||||||
|
|
||||||
|
|||||||
@@ -24,12 +24,17 @@
|
|||||||
<h1>
|
<h1>
|
||||||
{% if status == StatusCode::NOT_FOUND %}
|
{% if status == StatusCode::NOT_FOUND %}
|
||||||
Not found
|
Not found
|
||||||
|
{% else if status == StatusCode::INTERNAL_SERVER_ERROR %}
|
||||||
|
Internal server error
|
||||||
{% else %}
|
{% else %}
|
||||||
Request error
|
Bad request
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<small aria-hidden>(︶^︶)</small>
|
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
{% if status == StatusCode::INTERNAL_SERVER_ERROR %}
|
||||||
|
<p>Please <a href="https://forgejo.ellis.link/continuwuation/continuwuity/issues/new">submit a bug report</a> 🥺</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<pre><code>{{ error }}</code></pre>
|
<pre><code>{{ error }}</code></pre>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user