From 8eaaa1f2c2e86a866808f70ad004c1c192dfa459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20Balatoni?= Date: Sun, 25 Oct 2026 01:04:40 +0200 Subject: [PATCH] feat(server): derive GitHub OAuth, CSP and install URLs from the configured host --- lib/apps/fabro-cli/src/commands/server/mod.rs | 1 + .../fabro-server/src/auth/github_endpoints.rs | 40 +++++++-- lib/apps/fabro-server/src/csp.rs | 68 ++++++++++----- lib/apps/fabro-server/src/install.rs | 85 ++++++++++++++----- lib/apps/fabro-server/src/security_headers.rs | 16 ++-- lib/apps/fabro-server/src/server.rs | 12 ++- .../fabro-server/src/server/handler/system.rs | 5 +- lib/apps/fabro-server/src/server/tests.rs | 54 ++++++++++++ lib/apps/fabro-server/src/web_auth.rs | 14 +-- 9 files changed, 229 insertions(+), 66 deletions(-) diff --git a/lib/apps/fabro-cli/src/commands/server/mod.rs b/lib/apps/fabro-cli/src/commands/server/mod.rs index 2f3f3f8dc..851e82b47 100644 --- a/lib/apps/fabro-cli/src/commands/server/mod.rs +++ b/lib/apps/fabro-cli/src/commands/server/mod.rs @@ -224,6 +224,7 @@ async fn run_install_mode(bootstrap: InstallBootstrap, printer: Printer) -> Resu &bootstrap.storage_dir, &bootstrap.config_path, ) + .with_github_host(crate::user_config::github_host()?) .with_finish_hook(persist_install_dev_token_hook()); install::serve_install_command(bootstrap.bind_request, state, move |bind| { announce_install_mode(bind, &token, styles, printer); diff --git a/lib/apps/fabro-server/src/auth/github_endpoints.rs b/lib/apps/fabro-server/src/auth/github_endpoints.rs index 951c3af03..a7d59e680 100644 --- a/lib/apps/fabro-server/src/auth/github_endpoints.rs +++ b/lib/apps/fabro-server/src/auth/github_endpoints.rs @@ -4,6 +4,7 @@ )] use fabro_http::Url; +use fabro_types::GitHubHost; #[doc(hidden)] #[derive(Debug, Clone)] @@ -13,11 +14,12 @@ pub struct GithubEndpoints { } impl GithubEndpoints { - pub fn production_defaults() -> Self { + pub fn from_host(host: &GitHubHost) -> Self { Self { - oauth_base: Url::parse("https://github.com/").expect("github oauth base should parse"), - api_base: Url::parse("https://api.github.com/") - .expect("github api base should parse"), + oauth_base: Url::parse(&format!("{}/", host.web_url())) + .expect("GitHubHost web_url should parse as a URL"), + api_base: Url::parse(&format!("{}/", host.api_url())) + .expect("GitHubHost api_url should parse as a URL"), } } @@ -32,16 +34,42 @@ impl GithubEndpoints { #[cfg(test)] mod tests { + use fabro_types::GitHubHost; + use super::GithubEndpoints; #[test] - fn production_defaults_match_current_github_urls() { - let endpoints = GithubEndpoints::production_defaults(); + fn default_host_matches_current_github_urls() { + let endpoints = GithubEndpoints::from_host(&GitHubHost::default()); assert_eq!(endpoints.oauth_base.as_str(), "https://github.com/"); assert_eq!(endpoints.api_base.as_str(), "https://api.github.com/"); } + #[test] + fn enterprise_host_uses_its_web_origin_and_api_url() { + let host = GitHubHost::new("https://ghe.example.com", None).unwrap(); + let endpoints = GithubEndpoints::from_host(&host); + + assert_eq!(endpoints.oauth_base.as_str(), "https://ghe.example.com/"); + assert_eq!( + endpoints.api_base.as_str(), + "https://ghe.example.com/api/v3/" + ); + assert_eq!( + endpoints + .oauth_base + .join("login/oauth/authorize") + .unwrap() + .as_str(), + "https://ghe.example.com/login/oauth/authorize" + ); + assert_eq!( + endpoints.api_base.join("user").unwrap().as_str(), + "https://ghe.example.com/api/v3/user" + ); + } + #[test] fn with_bases_uses_custom_urls() { let endpoints = GithubEndpoints::with_bases( diff --git a/lib/apps/fabro-server/src/csp.rs b/lib/apps/fabro-server/src/csp.rs index efb16545c..6ba455045 100644 --- a/lib/apps/fabro-server/src/csp.rs +++ b/lib/apps/fabro-server/src/csp.rs @@ -4,24 +4,17 @@ //! `index.html` so any inline `