diff --git a/crates/cli/src/commands/server.rs b/crates/cli/src/commands/server.rs index 1367f131e..52465f077 100644 --- a/crates/cli/src/commands/server.rs +++ b/crates/cli/src/commands/server.rs @@ -160,8 +160,14 @@ impl Options { )?; // Load and compile the templates - let templates = - templates_from_config(&config.templates, &site_config, &url_builder).await?; + let templates = templates_from_config( + &config.templates, + &site_config, + &url_builder, + // Don't use strict mode in production yet + false, + ) + .await?; shutdown.register_reloadable(&templates); let http_client = mas_http::reqwest_client(); diff --git a/crates/cli/src/commands/templates.rs b/crates/cli/src/commands/templates.rs index 111f19682..6665f7f23 100644 --- a/crates/cli/src/commands/templates.rs +++ b/crates/cli/src/commands/templates.rs @@ -65,8 +65,14 @@ impl Options { &account_config, &captcha_config, )?; - let templates = - templates_from_config(&template_config, &site_config, &url_builder).await?; + let templates = templates_from_config( + &template_config, + &site_config, + &url_builder, + // Use strict mode in template checks + true, + ) + .await?; templates.check_render(clock.now(), &mut rng)?; Ok(ExitCode::SUCCESS) diff --git a/crates/cli/src/commands/worker.rs b/crates/cli/src/commands/worker.rs index 31d0d56c2..a1eb0fcce 100644 --- a/crates/cli/src/commands/worker.rs +++ b/crates/cli/src/commands/worker.rs @@ -52,8 +52,14 @@ impl Options { )?; // Load and compile the templates - let templates = - templates_from_config(&config.templates, &site_config, &url_builder).await?; + let templates = templates_from_config( + &config.templates, + &site_config, + &url_builder, + // Don't use strict mode on task workers for now + false, + ) + .await?; let mailer = mailer_from_config(&config.email, &templates)?; test_mailer_in_background(&mailer, Duration::from_secs(30)); diff --git a/crates/cli/src/util.rs b/crates/cli/src/util.rs index 976a08c32..4925d9866 100644 --- a/crates/cli/src/util.rs +++ b/crates/cli/src/util.rs @@ -232,6 +232,7 @@ pub async fn templates_from_config( config: &TemplatesConfig, site_config: &SiteConfig, url_builder: &UrlBuilder, + strict: bool, ) -> Result { Templates::load( config.path.clone(), @@ -240,6 +241,7 @@ pub async fn templates_from_config( config.translations_path.clone(), site_config.templates_branding(), site_config.templates_features(), + strict, ) .await .with_context(|| format!("Failed to load the templates at {}", config.path)) diff --git a/crates/handlers/src/test_utils.rs b/crates/handlers/src/test_utils.rs index fa8105763..f1859f352 100644 --- a/crates/handlers/src/test_utils.rs +++ b/crates/handlers/src/test_utils.rs @@ -176,6 +176,8 @@ impl TestState { workspace_root.join("translations"), site_config.templates_branding(), site_config.templates_features(), + // Strict mode in testing + true, ) .await?; diff --git a/crates/templates/src/context/branding.rs b/crates/templates/src/context/branding.rs index eb7e3546a..15932567f 100644 --- a/crates/templates/src/context/branding.rs +++ b/crates/templates/src/context/branding.rs @@ -58,9 +58,9 @@ impl Object for SiteBranding { fn get_value(self: &Arc, name: &Value) -> Option { match name.as_str()? { "server_name" => Some(self.server_name.clone().into()), - "policy_uri" => self.policy_uri.clone().map(Value::from), - "tos_uri" => self.tos_uri.clone().map(Value::from), - "imprint" => self.imprint.clone().map(Value::from), + "policy_uri" => Some(Value::from(self.policy_uri.clone())), + "tos_uri" => Some(Value::from(self.tos_uri.clone())), + "imprint" => Some(Value::from(self.imprint.clone())), _ => None, } } diff --git a/crates/templates/src/lib.rs b/crates/templates/src/lib.rs index bb208eb44..ee8a6282e 100644 --- a/crates/templates/src/lib.rs +++ b/crates/templates/src/lib.rs @@ -17,7 +17,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use mas_i18n::Translator; use mas_router::UrlBuilder; use mas_spa::ViteManifest; -use minijinja::Value; +use minijinja::{UndefinedBehavior, Value}; use rand::Rng; use serde::Serialize; use thiserror::Error; @@ -71,6 +71,9 @@ pub struct Templates { vite_manifest_path: Utf8PathBuf, translations_path: Utf8PathBuf, path: Utf8PathBuf, + /// Whether template rendering is in strict mode (for testing, + /// until this can be rolled out in production.) + strict: bool, } /// There was an issue while loading the templates @@ -151,6 +154,7 @@ impl Templates { translations_path: Utf8PathBuf, branding: SiteBranding, features: SiteFeatures, + strict: bool, ) -> Result { let (translator, environment) = Self::load_( &path, @@ -159,6 +163,7 @@ impl Templates { &translations_path, branding.clone(), features, + strict, ) .await?; Ok(Self { @@ -170,6 +175,7 @@ impl Templates { translations_path, branding, features, + strict, }) } @@ -180,6 +186,7 @@ impl Templates { translations_path: &Utf8Path, branding: SiteBranding, features: SiteFeatures, + strict: bool, ) -> Result<(Arc, Arc>), TemplateLoadingError> { let path = path.to_owned(); let span = tracing::Span::current(); @@ -205,6 +212,15 @@ impl Templates { span.in_scope(move || { let mut loaded: HashSet<_> = HashSet::new(); let mut env = minijinja::Environment::new(); + // Don't allow use of undefined variables + env.set_undefined_behavior(if strict { + UndefinedBehavior::Strict + } else { + // For now, allow semi-strict, because we don't have total test coverage of + // tests and some tests rely on if conditions against sometimes-undefined + // variables + UndefinedBehavior::SemiStrict + }); let root = path.canonicalize_utf8()?; info!(%root, "Loading templates from filesystem"); for entry in walkdir::WalkDir::new(&root) @@ -275,6 +291,7 @@ impl Templates { &self.translations_path, self.branding.clone(), self.features, + self.strict, ) .await?; @@ -524,6 +541,8 @@ mod tests { translations_path, branding, features, + // Use strict mode in tests + true, ) .await .unwrap(); diff --git a/templates/base.html b/templates/base.html index c7fb7e063..d5007ad83 100644 --- a/templates/base.html +++ b/templates/base.html @@ -28,7 +28,7 @@ {{ captcha.head() }} - -
+ {% for key, value in params|items %} {% endfor %} diff --git a/templates/pages/index.html b/templates/pages/index.html index b8a0d7547..3ef8ea51b 100644 --- a/templates/pages/index.html +++ b/templates/pages/index.html @@ -19,7 +19,7 @@

{{ _("app.human_name") }}

- {% if current_session %} + {% if current_session is not none %}

{{ _("mas.navbar.signed_in_as", username=current_session.user.username) }}

diff --git a/templates/pages/register/password.html b/templates/pages/register/password.html index f6f7a924f..82aa763fd 100644 --- a/templates/pages/register/password.html +++ b/templates/pages/register/password.html @@ -49,7 +49,7 @@

{{ _("mas.register.create_account.heading") }}

{% endcall %} - {% if branding.tos_uri %} + {% if branding.tos_uri is not none %} {% call(f) field.field(label=_("mas.register.terms_of_service", tos_uri=branding.tos_uri), name="accept_terms", form_state=form, inline=true, class="my-4") %}
diff --git a/templates/pages/upstream_oauth2/do_register.html b/templates/pages/upstream_oauth2/do_register.html index b3d8bdee8..f57564c43 100644 --- a/templates/pages/upstream_oauth2/do_register.html +++ b/templates/pages/upstream_oauth2/do_register.html @@ -26,7 +26,7 @@

- {% elif upstream_oauth_provider.human_name %} + {% elif upstream_oauth_provider.human_name is not none %}
{{ icon.user_profile_solid() }} @@ -55,9 +55,9 @@

{% endif %} - {% if upstream_oauth_provider.human_name %} + {% if upstream_oauth_provider.human_name is not none %}