You've already forked authentication-service
mirror of
https://github.com/matrix-org/matrix-authentication-service.git
synced 2025-08-07 17:03:01 +03:00
Mount the static assets on /assets
This commit is contained in:
@@ -27,7 +27,7 @@ use mas_email::Mailer;
|
|||||||
use mas_handlers::{AppState, MatrixHomeserver};
|
use mas_handlers::{AppState, MatrixHomeserver};
|
||||||
use mas_http::ServerLayer;
|
use mas_http::ServerLayer;
|
||||||
use mas_policy::PolicyFactory;
|
use mas_policy::PolicyFactory;
|
||||||
use mas_router::UrlBuilder;
|
use mas_router::{Route, UrlBuilder};
|
||||||
use mas_storage::MIGRATOR;
|
use mas_storage::MIGRATOR;
|
||||||
use mas_tasks::TaskQueue;
|
use mas_tasks::TaskQueue;
|
||||||
use mas_templates::Templates;
|
use mas_templates::Templates;
|
||||||
@@ -201,10 +201,16 @@ impl Options {
|
|||||||
.context("failed to load the policy")?;
|
.context("failed to load the policy")?;
|
||||||
let policy_factory = Arc::new(policy_factory);
|
let policy_factory = Arc::new(policy_factory);
|
||||||
|
|
||||||
|
let url_builder = UrlBuilder::new(config.http.public_base.clone());
|
||||||
|
|
||||||
// Load and compile the templates
|
// Load and compile the templates
|
||||||
let templates = Templates::load(config.templates.path.clone(), config.templates.builtin)
|
let templates = Templates::load(
|
||||||
.await
|
config.templates.path.clone(),
|
||||||
.context("could not load templates")?;
|
config.templates.builtin,
|
||||||
|
url_builder.clone(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.context("could not load templates")?;
|
||||||
|
|
||||||
let mailer = Mailer::new(
|
let mailer = Mailer::new(
|
||||||
&templates,
|
&templates,
|
||||||
@@ -213,8 +219,6 @@ impl Options {
|
|||||||
&config.email.reply_to,
|
&config.email.reply_to,
|
||||||
);
|
);
|
||||||
|
|
||||||
let url_builder = UrlBuilder::new(config.http.public_base.clone());
|
|
||||||
|
|
||||||
let static_files = mas_static_files::service(&config.http.web_root);
|
let static_files = mas_static_files::service(&config.http.web_root);
|
||||||
|
|
||||||
let homeserver = MatrixHomeserver::new(config.matrix.homeserver.clone());
|
let homeserver = MatrixHomeserver::new(config.matrix.homeserver.clone());
|
||||||
@@ -246,7 +250,7 @@ impl Options {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let router = mas_handlers::router(state)
|
let router = mas_handlers::router(state)
|
||||||
.fallback_service(static_files)
|
.nest(mas_router::StaticAsset::route(), static_files)
|
||||||
.layer(ServerLayer::default());
|
.layer(ServerLayer::default());
|
||||||
|
|
||||||
info!("Listening on http://{}", listener.local_addr().unwrap());
|
info!("Listening on http://{}", listener.local_addr().unwrap());
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use mas_config::TemplatesConfig;
|
|
||||||
use mas_templates::Templates;
|
use mas_templates::Templates;
|
||||||
|
|
||||||
#[derive(Parser, Debug)]
|
#[derive(Parser, Debug)]
|
||||||
@@ -58,11 +57,9 @@ impl Options {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SC::Check { path, skip_builtin } => {
|
SC::Check { path, skip_builtin } => {
|
||||||
let config = TemplatesConfig {
|
let url_builder = mas_router::UrlBuilder::new("https://example.com/".parse()?);
|
||||||
path: Some(path.to_string()),
|
let templates =
|
||||||
builtin: !skip_builtin,
|
Templates::load(Some(path.into()), !skip_builtin, url_builder).await?;
|
||||||
};
|
|
||||||
let templates = Templates::load(config.path.clone(), config.builtin).await?;
|
|
||||||
templates.check_render().await?;
|
templates.check_render().await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@@ -280,7 +280,9 @@ where
|
|||||||
async fn test_state(pool: PgPool) -> Result<Arc<AppState>, anyhow::Error> {
|
async fn test_state(pool: PgPool) -> Result<Arc<AppState>, anyhow::Error> {
|
||||||
use mas_email::MailTransport;
|
use mas_email::MailTransport;
|
||||||
|
|
||||||
let templates = Templates::load(None, true).await?;
|
let url_builder = UrlBuilder::new("https://example.com/".parse()?);
|
||||||
|
|
||||||
|
let templates = Templates::load(None, true, url_builder.clone()).await?;
|
||||||
|
|
||||||
// TODO: add test keys to the store
|
// TODO: add test keys to the store
|
||||||
let key_store = Keystore::default();
|
let key_store = Keystore::default();
|
||||||
@@ -291,8 +293,6 @@ async fn test_state(pool: PgPool) -> Result<Arc<AppState>, anyhow::Error> {
|
|||||||
let mailbox = "server@example.com".parse()?;
|
let mailbox = "server@example.com".parse()?;
|
||||||
let mailer = Mailer::new(&templates, &transport, &mailbox, &mailbox);
|
let mailer = Mailer::new(&templates, &transport, &mailbox, &mailbox);
|
||||||
|
|
||||||
let url_builder = UrlBuilder::new("https://example.com/".parse()?);
|
|
||||||
|
|
||||||
let homeserver = MatrixHomeserver::new("example.com".to_owned());
|
let homeserver = MatrixHomeserver::new("example.com".to_owned());
|
||||||
let policy_factory = PolicyFactory::load_default(serde_json::json!({})).await?;
|
let policy_factory = PolicyFactory::load_default(serde_json::json!({})).await?;
|
||||||
let policy_factory = Arc::new(policy_factory);
|
let policy_factory = Arc::new(policy_factory);
|
||||||
|
@@ -522,3 +522,26 @@ impl Route for CompatLoginSsoComplete {
|
|||||||
format!("/complete-compat-sso/{}", self.id).into()
|
format!("/complete-compat-sso/{}", self.id).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `GET /assets`
|
||||||
|
pub struct StaticAsset {
|
||||||
|
path: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StaticAsset {
|
||||||
|
#[must_use]
|
||||||
|
pub fn new(path: String) -> Self {
|
||||||
|
Self { path }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Route for StaticAsset {
|
||||||
|
type Query = ();
|
||||||
|
fn route() -> &'static str {
|
||||||
|
"/assets"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn path(&self) -> std::borrow::Cow<'static, str> {
|
||||||
|
format!("/assets/{}", self.path).into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -91,4 +91,10 @@ impl UrlBuilder {
|
|||||||
pub fn jwks_uri(&self) -> Url {
|
pub fn jwks_uri(&self) -> Url {
|
||||||
self.url_for(&crate::endpoints::OAuth2Keys)
|
self.url_for(&crate::endpoints::OAuth2Keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Static asset
|
||||||
|
#[must_use]
|
||||||
|
pub fn static_asset(&self, path: String) -> Url {
|
||||||
|
self.url_for(&crate::endpoints::StaticAsset::new(path))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -16,14 +16,16 @@
|
|||||||
|
|
||||||
use std::{collections::HashMap, str::FromStr};
|
use std::{collections::HashMap, str::FromStr};
|
||||||
|
|
||||||
|
use mas_router::{Route, UrlBuilder};
|
||||||
use tera::{helpers::tests::number_args_allowed, Tera, Value};
|
use tera::{helpers::tests::number_args_allowed, Tera, Value};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
pub fn register(tera: &mut Tera) {
|
pub fn register(tera: &mut Tera, url_builder: UrlBuilder) {
|
||||||
tera.register_tester("empty", self::tester_empty);
|
tera.register_tester("empty", self::tester_empty);
|
||||||
tera.register_function("add_params_to_uri", function_add_params_to_uri);
|
tera.register_function("add_params_to_uri", function_add_params_to_uri);
|
||||||
tera.register_function("merge", function_merge);
|
tera.register_function("merge", function_merge);
|
||||||
tera.register_function("dict", function_dict);
|
tera.register_function("dict", function_dict);
|
||||||
|
tera.register_function("static_asset", make_static_asset(url_builder));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tester_empty(value: Option<&Value>, params: &[Value]) -> Result<bool, tera::Error> {
|
fn tester_empty(value: Option<&Value>, params: &[Value]) -> Result<bool, tera::Error> {
|
||||||
@@ -115,3 +117,26 @@ fn function_dict(params: &HashMap<String, Value>) -> Result<Value, tera::Error>
|
|||||||
let ret = params.clone().into_iter().collect();
|
let ret = params.clone().into_iter().collect();
|
||||||
Ok(Value::Object(ret))
|
Ok(Value::Object(ret))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_static_asset(url_builder: UrlBuilder) -> impl tera::Function {
|
||||||
|
Box::new(
|
||||||
|
move |args: &HashMap<String, Value>| -> Result<Value, tera::Error> {
|
||||||
|
if let Some(path) = args.get("path").and_then(Value::as_str) {
|
||||||
|
let absolute = args
|
||||||
|
.get("absolute")
|
||||||
|
.and_then(Value::as_bool)
|
||||||
|
.unwrap_or(false);
|
||||||
|
let path = path.to_owned();
|
||||||
|
let url = if absolute {
|
||||||
|
url_builder.static_asset(path).into()
|
||||||
|
} else {
|
||||||
|
let destination = mas_router::StaticAsset::new(path);
|
||||||
|
destination.relative_url().into_owned()
|
||||||
|
};
|
||||||
|
Ok(Value::String(url))
|
||||||
|
} else {
|
||||||
|
Err(tera::Error::msg("Invalid parameter 'path'"))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@@ -34,6 +34,7 @@ use std::{
|
|||||||
|
|
||||||
use anyhow::{bail, Context as _};
|
use anyhow::{bail, Context as _};
|
||||||
use mas_data_model::StorageBackend;
|
use mas_data_model::StorageBackend;
|
||||||
|
use mas_router::UrlBuilder;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use tera::{Context, Error as TeraError, Tera};
|
use tera::{Context, Error as TeraError, Tera};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@@ -62,6 +63,7 @@ pub use self::{
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Templates {
|
pub struct Templates {
|
||||||
tera: Arc<RwLock<Tera>>,
|
tera: Arc<RwLock<Tera>>,
|
||||||
|
url_builder: UrlBuilder,
|
||||||
path: Option<String>,
|
path: Option<String>,
|
||||||
builtin: bool,
|
builtin: bool,
|
||||||
}
|
}
|
||||||
@@ -134,16 +136,25 @@ impl Templates {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Load the templates from the given config
|
/// Load the templates from the given config
|
||||||
pub async fn load(path: Option<String>, builtin: bool) -> Result<Self, TemplateLoadingError> {
|
pub async fn load(
|
||||||
let tera = Self::load_(path.as_deref(), builtin).await?;
|
path: Option<String>,
|
||||||
|
builtin: bool,
|
||||||
|
url_builder: UrlBuilder,
|
||||||
|
) -> Result<Self, TemplateLoadingError> {
|
||||||
|
let tera = Self::load_(path.as_deref(), builtin, url_builder.clone()).await?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
tera: Arc::new(RwLock::new(tera)),
|
tera: Arc::new(RwLock::new(tera)),
|
||||||
path,
|
path,
|
||||||
|
url_builder,
|
||||||
builtin,
|
builtin,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn load_(path: Option<&str>, builtin: bool) -> Result<Tera, TemplateLoadingError> {
|
async fn load_(
|
||||||
|
path: Option<&str>,
|
||||||
|
builtin: bool,
|
||||||
|
url_builder: UrlBuilder,
|
||||||
|
) -> Result<Tera, TemplateLoadingError> {
|
||||||
let mut teras = Vec::new();
|
let mut teras = Vec::new();
|
||||||
|
|
||||||
let roots = Self::roots(path, builtin).await;
|
let roots = Self::roots(path, builtin).await;
|
||||||
@@ -183,7 +194,7 @@ impl Templates {
|
|||||||
tera.build_inheritance_chains()?;
|
tera.build_inheritance_chains()?;
|
||||||
tera.check_macro_files()?;
|
tera.check_macro_files()?;
|
||||||
|
|
||||||
self::functions::register(&mut tera);
|
self::functions::register(&mut tera, url_builder);
|
||||||
|
|
||||||
let loaded: HashSet<_> = tera.get_template_names().collect();
|
let loaded: HashSet<_> = tera.get_template_names().collect();
|
||||||
let needed: HashSet<_> = TEMPLATES.into_iter().map(|(name, _)| name).collect();
|
let needed: HashSet<_> = TEMPLATES.into_iter().map(|(name, _)| name).collect();
|
||||||
@@ -202,7 +213,8 @@ impl Templates {
|
|||||||
/// Reload the templates on disk
|
/// Reload the templates on disk
|
||||||
pub async fn reload(&self) -> anyhow::Result<()> {
|
pub async fn reload(&self) -> anyhow::Result<()> {
|
||||||
// Prepare the new Tera instance
|
// Prepare the new Tera instance
|
||||||
let new_tera = Self::load_(self.path.as_deref(), self.builtin).await?;
|
let new_tera =
|
||||||
|
Self::load_(self.path.as_deref(), self.builtin, self.url_builder.clone()).await?;
|
||||||
|
|
||||||
// Swap it
|
// Swap it
|
||||||
*self.tera.write().await = new_tera;
|
*self.tera.write().await = new_tera;
|
||||||
@@ -378,7 +390,8 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn check_builtin_templates() {
|
async fn check_builtin_templates() {
|
||||||
let templates = Templates::load(None, true).await.unwrap();
|
let url_builder = UrlBuilder::new("https://example.com/".parse().unwrap());
|
||||||
|
let templates = Templates::load(None, true, url_builder).await.unwrap();
|
||||||
templates.check_render().await.unwrap();
|
templates.check_render().await.unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -27,7 +27,7 @@ limitations under the License.
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{% block title %}matrix-authentication-service{% endblock title %}</title>
|
<title>{% block title %}matrix-authentication-service{% endblock title %}</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="stylesheet" href="/tailwind.css">
|
<link rel="stylesheet" href="{{ static_asset(path='tailwind.css') }}">
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-white text-black-900 dark:bg-black-800 dark:text-white flex flex-col min-h-screen">
|
<body class="bg-white text-black-900 dark:bg-black-800 dark:text-white flex flex-col min-h-screen">
|
||||||
{% block content %}{% endblock content %}
|
{% block content %}{% endblock content %}
|
||||||
|
Reference in New Issue
Block a user