Skip to content

Commit

Permalink
Svelte 5 Migration 17: HtmlCached for pre-compression + caching for…
Browse files Browse the repository at this point in the history
… dynamic HTML (#719)

* create `HtmlCached` to provide dynamic HTML template pre-compression + caching

* add `/providers/callback` + `/users/register` + `/logout` html to pre-compression cache
  • Loading branch information
sebadob authored Feb 10, 2025
1 parent 288b0d8 commit b7f1724
Show file tree
Hide file tree
Showing 260 changed files with 864 additions and 623 deletions.
5 changes: 0 additions & 5 deletions frontend/src/lib_svelte5/nav/NavSide.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import Button from "$lib5/Button.svelte";
import LangSelector from "$lib5/LangSelector.svelte";
import {page} from "$app/state";
import {useI18n} from "$state/i18n.svelte.ts";
import {useSession} from "$state/session.svelte.ts";
import AppVersion from "../../components/AppVersion.svelte";
import RauthyLogo from "$lib/icons/RauthyLogo.svelte";
import NavLink from "$lib5/nav/NavLink.svelte";
Expand All @@ -25,10 +23,8 @@
import IconCheckBadge from "$icons/IconCheckBadge.svelte";
import {useI18nAdmin} from "$state/i18n_admin.svelte.ts";
let t = useI18n();
let ta = useI18nAdmin();
let session = useSession('admin');
let timeout: undefined | number;
let optsButtons = $state(false);
Expand All @@ -37,7 +33,6 @@
let collapsed = $state(true);
let innerWidth: undefined | number = $state();
let widthLogo = $derived(compact ? '2rem' : '5.5rem');
// cannot be derived because of static pre-rendering
$effect(() => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/utils/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export const PKCE_CHALLENGES = [{
];

// All TPL_* values match a possibly existing `<template>` id
// -> src/models/src/html_templates.rs -> HtmlTemplate
// -> src/models/src/html/templates.rs -> HtmlTemplate
export const TPL_AUTH_PROVIDERS = 'tpl_auth_providers';
export const TPL_CLIENT_NAME = 'tpl_client_name';
export const TPL_CLIENT_URL = 'tpl_client_url';
Expand Down
1 change: 1 addition & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ build-ui:
PAGES=(
"templates/html/*.html"
"templates/html/admin/*.html"
"templates/html/admin/config/*.html"
"templates/html/error/*.html"
"templates/html/error/error/*.html"
"templates/html/error/error/error/*.html"
Expand Down
12 changes: 3 additions & 9 deletions src/api/src/auth_providers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,15 @@ use rauthy_api_types::auth_providers::{
};
use rauthy_api_types::auth_providers::{ProviderLookupResponse, ProviderResponse};
use rauthy_api_types::users::{UserResponse, WebauthnLoginResponse};
use rauthy_common::constants::{HEADER_HTML, HEADER_JSON};
use rauthy_common::constants::HEADER_JSON;
use rauthy_error::{ErrorResponse, ErrorResponseType};
use rauthy_models::app_state::AppState;
use rauthy_models::entity::auth_providers::{
AuthProvider, AuthProviderCallback, AuthProviderLinkCookie, AuthProviderTemplate,
};
use rauthy_models::entity::colors::ColorEntity;
use rauthy_models::entity::logos::{Logo, LogoType};
use rauthy_models::entity::users::User;
use rauthy_models::html_templates::ProviderCallbackHtml;
use rauthy_models::language::Language;
use rauthy_models::html::HtmlCached;
use tracing::debug;
use validator::Validate;

Expand Down Expand Up @@ -148,11 +146,7 @@ pub async fn post_provider_login(

#[get("/providers/callback")]
pub async fn get_provider_callback_html(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy().await?;
let lang = Language::try_from(&req).unwrap_or_default();
let body = ProviderCallbackHtml::build(&colors, &lang);

Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
HtmlCached::Device.handle(req, true).await
}

/// Callback for an upstream auth provider login
Expand Down
2 changes: 1 addition & 1 deletion src/api/src/dev_only.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub async fn get_template(
use actix_web::FromRequest;
use rauthy_common::constants::DEV_MODE;
use rauthy_models::app_state::AppState;
use rauthy_models::html_templates::HtmlTemplate;
use rauthy_models::html::templates::HtmlTemplate;

if !*DEV_MODE {
return Ok(HttpResponse::NotFound().finish());
Expand Down
10 changes: 4 additions & 6 deletions src/api/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,19 +158,17 @@ pub async fn post_event_test(
.send(&data.tx_events)
.await?;
Event::rauthy_unhealthy_db().send(&data.tx_events).await?;
Event::secrets_migrated(ip.clone())
.send(&data.tx_events)
.await?;
Event::test(ip.clone()).send(&data.tx_events).await?;
Event::secrets_migrated(ip).send(&data.tx_events).await?;
Event::test(ip).send(&data.tx_events).await?;

let old_email = "old@mail";
let new_mail = "new@mail";
let text = format!("{} -> {}", old_email, new_mail);
let text_admin = format!("Change by admin: {} -> {}", old_email, new_mail);
Event::user_email_change(text, Some(ip.clone()))
Event::user_email_change(text, Some(ip))
.send(&data.tx_events)
.await?;
Event::user_email_change(text_admin, Some(ip.clone()))
Event::user_email_change(text_admin, Some(ip))
.send(&data.tx_events)
.await?;

Expand Down
68 changes: 30 additions & 38 deletions src/api/src/html.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,12 @@ use actix_web::http::header;
use actix_web::{get, web, HttpRequest, HttpResponse};
use rauthy_common::constants::HEADER_HTML;
use rauthy_error::ErrorResponse;
use rauthy_models::entity::auth_providers::AuthProviderTemplate;
use rauthy_models::entity::colors::ColorEntity;
use rauthy_models::html_templates::{
AccountHtml, AdminApiKeysHtml, AdminAttributesHtml, AdminBlacklistHtml, AdminClientsHtml,
AdminConfigHtml, AdminDocsHtml, AdminGroupsHtml, AdminHtml, AdminRolesHtml, AdminScopesHtml,
AdminSessionsHtml, AdminUsersHtml, DeviceHtml, FedCMHtml, HtmlTemplate, IndexHtml,
ProvidersHtml,
use rauthy_models::html::templates::{
AdminApiKeysHtml, AdminAttributesHtml, AdminBlacklistHtml, AdminClientsHtml, AdminGroupsHtml,
AdminHtml, AdminRolesHtml, AdminScopesHtml, AdminSessionsHtml, AdminUsersHtml, ProvidersHtml,
};
use rauthy_models::language::Language;
use rauthy_models::html::HtmlCached;
use std::borrow::Cow;

#[get("/{_:.*}")]
Expand Down Expand Up @@ -47,22 +44,12 @@ pub async fn get_static_assets(

#[get("/")]
pub async fn get_index(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy().await?;
let lang = Language::try_from(&req).unwrap_or_default();
let body = IndexHtml::build(&colors, &lang);

Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
HtmlCached::Index.handle(req, true).await
}

#[get("/account")]
pub async fn get_account_html(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy().await?;
let lang = Language::try_from(&req).unwrap_or_default();
let providers = AuthProviderTemplate::get_all_json_template().await?;
// let body = AccountHtml::build(&colors, &lang, Some(providers));
let body = AccountHtml::build(&colors, &lang, &[HtmlTemplate::AuthProviders(providers)]);

Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
HtmlCached::Account.handle(req, true).await
}

#[get("/admin")]
Expand Down Expand Up @@ -105,20 +92,31 @@ pub async fn get_admin_clients_html() -> Result<HttpResponse, ErrorResponse> {
Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
}

#[get("/admin/config")]
pub async fn get_admin_config_html() -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy().await?;
let body = AdminConfigHtml::build(&colors);
#[get("/admin/config/argon2")]
pub async fn get_admin_config_argon2_html(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
HtmlCached::ConfigArgon2.handle(req, true).await
}

Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
#[get("/admin/config/encryption")]
pub async fn get_admin_config_encryption_html(
req: HttpRequest,
) -> Result<HttpResponse, ErrorResponse> {
HtmlCached::ConfigEncryption.handle(req, true).await
}

#[get("/admin/docs")]
pub async fn get_admin_docs_html() -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy().await?;
let body = AdminDocsHtml::build(&colors);
#[get("/admin/config/jwks")]
pub async fn get_admin_config_jwks_html(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
HtmlCached::ConfigJwks.handle(req, true).await
}

Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
#[get("/admin/config/policy")]
pub async fn get_admin_config_policy_html(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
HtmlCached::ConfigPolicy.handle(req, true).await
}

#[get("/admin/docs")]
pub async fn get_admin_docs_html(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
HtmlCached::Docs.handle(req, true).await
}

#[get("/admin/events")]
Expand Down Expand Up @@ -179,16 +177,10 @@ pub async fn get_admin_users_html() -> Result<HttpResponse, ErrorResponse> {

#[get("/device")]
pub async fn get_device_html(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy().await?;
let lang = Language::try_from(&req).unwrap_or_default();
let body = DeviceHtml::build(&colors, &lang);

Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
HtmlCached::Device.handle(req, true).await
}

#[get("/fedcm")]
pub async fn get_fed_cm_html() -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy().await?;
let body = FedCMHtml::build(&colors);
Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
pub async fn get_fed_cm_html(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
HtmlCached::FedCM.handle(req, true).await
}
27 changes: 7 additions & 20 deletions src/api/src/oidc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ use rauthy_models::entity::sessions::Session;
use rauthy_models::entity::users::User;
use rauthy_models::entity::webauthn::WebauthnCookie;
use rauthy_models::entity::well_known::WellKnown;
use rauthy_models::html_templates::{
use rauthy_models::html::templates::{
AuthorizeHtml, CallbackHtml, Error1Html, ErrorHtml, FrontendAction, HtmlTemplate,
};
use rauthy_models::language::Language;
Expand Down Expand Up @@ -626,33 +626,20 @@ pub async fn get_logout(
}

// If we get any logout errors, maybe because there is no session anymore or whatever happens,
// just redirect to rauthy's root page, since the user is not logged in anyway anymore.
// just redirect to rauthy's root page, since the user is not logged-in anyway anymore.
if principal.validate_session_auth().is_err() {
return HttpResponse::build(StatusCode::from_u16(302).unwrap())
.insert_header(("location", "/auth/v1/"))
.finish();
}

let lang = Language::try_from(&req).unwrap_or_default();
let body = match logout::get_logout_html(
params,
principal.into_inner().session.unwrap(),
&data,
&lang,
)
.await
{
Ok(t) => t,
Err(_) => {
return HttpResponse::build(StatusCode::from_u16(302).unwrap())
logout::get_logout_html(req, params, principal.into_inner().session.unwrap(), &data)
.await
.unwrap_or_else(|_| {
HttpResponse::build(StatusCode::from_u16(302).unwrap())
.insert_header(("location", "/auth/v1/"))
.finish()
}
};

HttpResponse::build(StatusCode::OK)
.append_header(HEADER_HTML)
.body(body)
})
}

/// Send the logout confirmation
Expand Down
14 changes: 4 additions & 10 deletions src/api/src/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ use rauthy_models::entity::webauthn;
use rauthy_models::entity::webauthn::{PasskeyEntity, WebauthnAdditionalData};
use rauthy_models::entity::webids::WebId;
use rauthy_models::events::event::Event;
use rauthy_models::html_templates::{Error1Html, Error3Html, ErrorHtml, UserRegisterHtml};
use rauthy_models::html::templates::{Error3Html, ErrorHtml};
use rauthy_models::html::HtmlCached;
use rauthy_models::language::Language;
use rauthy_service::password_reset;
use spow::pow::Pow;
Expand Down Expand Up @@ -267,17 +268,10 @@ pub async fn delete_cust_attr(
)]
#[get("/users/register")]
pub async fn get_users_register(req: HttpRequest) -> Result<HttpResponse, ErrorResponse> {
let colors = ColorEntity::find_rauthy().await?;
let lang = Language::try_from(&req).unwrap_or_default();

if !*OPEN_USER_REG {
let status = StatusCode::NOT_FOUND;
let body = Error1Html::build(&colors, &lang, status, "Open User Registration is disabled");
return Ok(ErrorHtml::response(body, status));
return Ok(HttpResponse::NotFound().finish());
}

let body = UserRegisterHtml::build(&colors, &lang);
Ok(HttpResponse::Ok().insert_header(HEADER_HTML).body(body))
HtmlCached::UserRegistration.handle(req, true).await
}

/// Creates a new user with almost all values set to default
Expand Down
5 changes: 4 additions & 1 deletion src/bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,10 @@ async fn actix_main(app_state: web::Data<AppState>) -> std::io::Result<()> {
.service(html::get_admin_attr_html)
.service(html::get_admin_blacklist_html)
.service(html::get_admin_clients_html)
.service(html::get_admin_config_html)
.service(html::get_admin_config_argon2_html)
.service(html::get_admin_config_encryption_html)
.service(html::get_admin_config_jwks_html)
.service(html::get_admin_config_policy_html)
.service(html::get_admin_docs_html)
.service(html::get_admin_events_html)
.service(html::get_admin_groups_html)
Expand Down
2 changes: 2 additions & 0 deletions src/common/src/compression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub fn compress_br_dyn(input: &[u8]) -> Result<Vec<u8>, ErrorResponse> {

#[inline]
fn compress_br_with(input: &[u8], params: &BrotliEncoderParams) -> Result<Vec<u8>, ErrorResponse> {
// TODO test if its worth it to take owned data and outsource into blocking task
let mut writer = Cursor::new(Vec::with_capacity(input.len()));
let mut reader = Cursor::new(input);
brotli::BrotliCompress(&mut reader, &mut writer, params)?;
Expand All @@ -46,6 +47,7 @@ fn compress_br_with(input: &[u8], params: &BrotliEncoderParams) -> Result<Vec<u8

#[inline]
pub fn compress_gzip(input: &[u8]) -> Result<Vec<u8>, ErrorResponse> {
// TODO test if its worth it to take owned data and outsource into blocking task
let mut encoder = Encoder::new(Vec::new())?;
encoder.write_all(input)?;
Ok(encoder.finish().into_result()?)
Expand Down
2 changes: 1 addition & 1 deletion src/middlewares/src/ip_blacklist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use rauthy_common::utils::real_ip_from_svc_req;
use rauthy_error::{ErrorResponse, ErrorResponseType};
use rauthy_models::app_state::AppState;
use rauthy_models::events::ip_blacklist_handler::{IpBlacklistCheck, IpBlacklistReq};
use rauthy_models::html_templates::TooManyRequestsHtml;
use rauthy_models::html::templates::TooManyRequestsHtml;
use std::future::{ready, Ready};
use std::rc::Rc;
use tokio::sync::oneshot;
Expand Down
2 changes: 1 addition & 1 deletion src/models/src/entity/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::entity::sessions::Session;
use crate::entity::users_values::UserValues;
use crate::entity::webauthn::{PasskeyEntity, WebauthnServiceReq};
use crate::events::event::Event;
use crate::html_templates::{HtmlTemplate, UserEmailChangeConfirmHtml};
use crate::html::templates::{HtmlTemplate, UserEmailChangeConfirmHtml};
use crate::language::Language;
use actix_web::{web, HttpRequest};
use argon2::PasswordHash;
Expand Down
Loading

0 comments on commit b7f1724

Please sign in to comment.