diff --git a/build.rs b/build.rs index bb6c431..c99019c 100644 --- a/build.rs +++ b/build.rs @@ -4,13 +4,22 @@ fn main() { // Required config vars - must be set either by Doppler or .env let required = ["SITE_HOST", "CONVEX_HTTP_URL", "KEYRING_SERVICE", "KEYRING_ACCOUNT"]; - + for var in required { let value = std::env::var(var) .unwrap_or_else(|_| panic!("{} must be set in environment or .env file", var)); println!("cargo:rustc-env={}={}", var, value); } + // Optional Cloudflare Access credentials (only needed for staging) + let optional = ["CF_ACCESS_CLIENT_ID", "CF_ACCESS_CLIENT_SECRET"]; + + for var in optional { + if let Ok(value) = std::env::var(var) { + println!("cargo:rustc-env={}={}", var, value); + } + } + println!("cargo:rerun-if-changed=.env"); } diff --git a/src/builds.rs b/src/builds.rs index ddac63e..65a8727 100644 --- a/src/builds.rs +++ b/src/builds.rs @@ -55,7 +55,7 @@ async fn get_temp_credentials( entrypoint: Option<&str>, api_key: &str, ) -> Result { - let client = reqwest::Client::new(); + let client = config::create_http_client()?; let api_host = config::get("api_host")?; let url = format!( @@ -107,7 +107,7 @@ async fn notify_upload_complete( build_id: &str, api_key: &str, ) -> Result<()> { - let client = reqwest::Client::new(); + let client = config::create_http_client()?; let api_host = config::get("api_host")?; let url = format!( diff --git a/src/config.rs b/src/config.rs index fdf13ab..01d5a16 100644 --- a/src/config.rs +++ b/src/config.rs @@ -20,13 +20,15 @@ struct Config { api_host: String, keyring_service: String, keyring_account: String, + cf_access_client_id: Option, + cf_access_client_secret: Option, } impl Config { fn load() -> Result { // Values are baked in at compile time via build.rs let mut site_host = env!("SITE_HOST").to_string(); - + // Ensure protocol is present if !site_host.starts_with("http") { site_host = format!("https://{}", site_host); @@ -37,6 +39,8 @@ impl Config { api_host: env!("CONVEX_HTTP_URL").to_string(), keyring_service: env!("KEYRING_SERVICE").to_string(), keyring_account: env!("KEYRING_ACCOUNT").to_string(), + cf_access_client_id: option_env!("CF_ACCESS_CLIENT_ID").map(|s| s.to_string()), + cf_access_client_secret: option_env!("CF_ACCESS_CLIENT_SECRET").map(|s| s.to_string()), }) } } @@ -64,6 +68,38 @@ pub fn keyring_config() -> Result { }) } +/// Create an HTTP client configured with Cloudflare Access headers if needed +pub fn create_http_client() -> Result { + let config = Config::load()?; + let mut client_builder = reqwest::Client::builder(); + + // Check if we're targeting staging and have CF credentials + let api_host = &config.api_host; + let needs_cf_headers = api_host + .trim_start_matches("https://") + .trim_start_matches("http://") + .ends_with("staging.wavedash.gg"); + + if needs_cf_headers { + if let (Some(client_id), Some(client_secret)) = + (&config.cf_access_client_id, &config.cf_access_client_secret) + { + let mut headers = reqwest::header::HeaderMap::new(); + headers.insert( + "CF-Access-Client-Id", + reqwest::header::HeaderValue::from_str(client_id)?, + ); + headers.insert( + "CF-Access-Client-Secret", + reqwest::header::HeaderValue::from_str(client_secret)?, + ); + client_builder = client_builder.default_headers(headers); + } + } + + Ok(client_builder.build()?) +} + #[derive(Debug, Deserialize)] pub struct GodotSection { pub version: String, diff --git a/src/dev/entrypoint.rs b/src/dev/entrypoint.rs index 6c5b1b3..cb6b68e 100644 --- a/src/dev/entrypoint.rs +++ b/src/dev/entrypoint.rs @@ -2,7 +2,6 @@ use std::fs; use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; -use reqwest::Client; use serde::Deserialize; use serde_json::Value; use walkdir::WalkDir; @@ -47,7 +46,7 @@ pub async fn fetch_entrypoint_params(engine: &str, html_path: &Path) -> Result