1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-07-31 09:24:31 +03:00

Add a 404 HTMl fallback

This commit is contained in:
Quentin Gliech
2023-08-09 13:55:35 +02:00
parent bbd0956f2d
commit 3e6ea9a158
6 changed files with 116 additions and 6 deletions

View File

@ -235,6 +235,8 @@ where
}
}
router = router.fallback(mas_handlers::fallback);
router
.layer(
InFlightCounterLayer::new("http.server.active_requests").on_request((

View File

@ -34,21 +34,26 @@ use std::{convert::Infallible, sync::Arc, time::Duration};
use axum::{
body::{Bytes, HttpBody},
extract::{FromRef, FromRequestParts},
extract::{FromRef, FromRequestParts, OriginalUri, State},
http::Method,
response::{Html, IntoResponse},
routing::{get, on, post, MethodFilter},
Router,
};
use headers::HeaderName;
use hyper::header::{
use hyper::{
header::{
ACCEPT, ACCEPT_LANGUAGE, AUTHORIZATION, CONTENT_LANGUAGE, CONTENT_LENGTH, CONTENT_TYPE,
},
StatusCode, Version,
};
use mas_axum_utils::FancyError;
use mas_http::CorsLayerExt;
use mas_keystore::{Encrypter, Keystore};
use mas_policy::PolicyFactory;
use mas_router::{Route, UrlBuilder};
use mas_storage::{BoxClock, BoxRepository, BoxRng};
use mas_templates::{ErrorContext, Templates};
use mas_templates::{ErrorContext, NotFoundContext, Templates};
use passwords::PasswordManager;
use sqlx::PgPool;
use tower::util::AndThenLayer;
@ -368,3 +373,22 @@ where
},
))
}
/// The fallback handler for all routes that don't match anything else.
///
/// # Errors
///
/// Returns an error if the template rendering fails.
pub async fn fallback(
State(templates): State<Templates>,
OriginalUri(uri): OriginalUri,
method: Method,
version: Version,
) -> Result<impl IntoResponse, FancyError> {
let ctx = NotFoundContext::new(&method, version, &uri);
// XXX: this should look at the Accept header and return JSON if requested
let res = templates.render_not_found(&ctx).await?;
Ok((StatusCode::NOT_FOUND, Html(res)))
}

View File

@ -14,7 +14,8 @@
//! Contexts used in templates
use chrono::Utc;
use chrono::{DateTime, Utc};
use http::{Method, Uri, Version};
use mas_data_model::{
AuthorizationGrant, BrowserSession, Client, CompatSsoLogin, CompatSsoLoginState,
UpstreamOAuthLink, UpstreamOAuthProvider, User, UserEmail, UserEmailVerification,
@ -1009,3 +1010,40 @@ impl ErrorContext {
self.details.as_deref()
}
}
/// Context used by the not found (`404.html`) template
#[derive(Serialize)]
pub struct NotFoundContext {
method: String,
version: String,
uri: String,
}
impl NotFoundContext {
/// Constructs a context for the not found page
#[must_use]
pub fn new(method: &Method, version: Version, uri: &Uri) -> Self {
Self {
method: method.to_string(),
version: format!("{version:?}"),
uri: uri.to_string(),
}
}
}
impl TemplateContext for NotFoundContext {
fn sample(_now: DateTime<Utc>, _rng: &mut impl Rng) -> Vec<Self>
where
Self: Sized,
{
vec![
Self::new(&Method::GET, Version::HTTP_11, &"/".parse().unwrap()),
Self::new(&Method::POST, Version::HTTP_2, &"/foo/bar".parse().unwrap()),
Self::new(
&Method::PUT,
Version::HTTP_10,
&"/foo?bar=baz".parse().unwrap(),
),
]
}
}

View File

@ -49,7 +49,7 @@ pub use self::{
context::{
AppContext, CompatSsoContext, ConsentContext, EmailAddContext, EmailVerificationContext,
EmailVerificationPageContext, EmptyContext, ErrorContext, FormPostContext, IndexContext,
LoginContext, LoginFormField, PolicyViolationContext, PostAuthContext,
LoginContext, LoginFormField, NotFoundContext, PolicyViolationContext, PostAuthContext,
PostAuthContextInner, ReauthContext, ReauthFormField, RegisterContext, RegisterFormField,
TemplateContext, UpstreamExistingLinkContext, UpstreamRegister, UpstreamSuggestLink,
WithCsrf, WithOptionalSession, WithSession,
@ -222,6 +222,9 @@ pub enum TemplateError {
}
register_templates! {
/// Render the not found fallback page
pub fn render_not_found(NotFoundContext) { "pages/404.html" }
/// Render the frontend app
pub fn render_app(AppContext) { "app.html" }
@ -294,6 +297,7 @@ impl Templates {
now: chrono::DateTime<chrono::Utc>,
rng: &mut impl Rng,
) -> anyhow::Result<()> {
check::render_not_found(self, now, rng).await?;
check::render_app(self, now, rng).await?;
check::render_login(self, now, rng).await?;
check::render_register(self, now, rng).await?;

View File

@ -13,6 +13,13 @@
* limitations under the License.
*/
@import "@fontsource/inter/400.css";
@import "@fontsource/inter/500.css";
@import "@fontsource/inter/600.css";
@import "@fontsource/inter/700.css";
@import "@vector-im/compound-design-tokens/assets/web/css/compound-design-tokens.css";
@import "@vector-im/compound-web/dist/style.css";
@config "../tailwind.templates.config.cjs";
@tailwind base;

35
templates/pages/404.html Normal file
View File

@ -0,0 +1,35 @@
{#
Copyright 2023 The Matrix.org Foundation C.I.C.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
#}
{% extends "base.html" %}
{% block content %}
<section class="flex-1 flex items-center justify-center">
<div class="w-64 flex flex-col gap-2">
<h1 class="text-xl font-semibold">Page not found</h1>
<p>The page you were looking for doesn't exist or has been moved</p>
<a class="text-links hover:text-links/70" href="/">Go back to the homepage</a>
<hr />
<code>
<pre class="whitespace-pre-wrap break-all">{{ method }} {{ uri }} {{ version }}
{{ version }} 404 Not Found</pre>
</code>
</div>
</section>
{% endblock %}