From 9ea44e4aa665c0f0fdb1fc13a43a04ebc7b5cabe Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Sun, 1 Feb 2026 01:50:02 -0500 Subject: [PATCH] update signup source --- .../src/requests/get_request_signup_source.rs | 117 ------------------ .../get_request_signup_source_enum.rs | 50 +++++++- crates/lib/actix_artcraft/src/requests/mod.rs | 1 - .../user_creation_case.rs | 9 ++ 4 files changed, 53 insertions(+), 124 deletions(-) delete mode 100644 crates/lib/actix_artcraft/src/requests/get_request_signup_source.rs diff --git a/crates/lib/actix_artcraft/src/requests/get_request_signup_source.rs b/crates/lib/actix_artcraft/src/requests/get_request_signup_source.rs deleted file mode 100644 index 247fb19ecb..0000000000 --- a/crates/lib/actix_artcraft/src/requests/get_request_signup_source.rs +++ /dev/null @@ -1,117 +0,0 @@ -use actix_helpers::extractors::get_request_origin_uri::get_request_origin_uri; -use actix_web::HttpRequest; -use log::warn; - -const ARTCRAFT : &str = "artcraft"; -const FAKEYOU : &str = "fakeyou"; -const STORYTELLER : &str = "storyteller"; - -/// This is for the users table `maybe_source` field which is populated during account creation. -/// While we could back this with an enum, there may be a motivation to use this VARCHAR(255) field -/// for more robust payloads and user tracking in the future. -pub fn get_request_signup_source(http_request: &HttpRequest) -> Option<&'static str> { - // NB: "Origin" vs "Referrer" - // - // Basically: - // - "In order to preserve privacy, any browser request can decide to omit the Referer header." - // - "The Origin header is similar to the Referer header, but does not disclose the path, and may be null." - // - "Origin" is sent on cross-origin, same-origin (except GET and HEAD requests - typically). - // - // Reading: - // - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin - // - https://stackoverflow.com/a/71040145 - // - let maybe_origin = get_request_origin_uri(&http_request); - - match maybe_origin { - Ok(Some(uri)) => { - if let Some(host) = uri.host() { - if host.contains(ARTCRAFT) { - return Some(ARTCRAFT); - } else if host.contains(STORYTELLER) { - return Some(STORYTELLER); - } else if host.contains(FAKEYOU) { - return Some(FAKEYOU); - } - } - } - // Fail open for now. - Ok(None) => {} - Err(err) => { - warn!("Origin header error: {:?}", err); - } - } - - // NB: We don't want to check the "Host" header because we might have misconfigured - // a future frontend to talk to some other API gateway and might be improperly and - // silently misattributing signup statistics. - - None -} - - -#[cfg(test)] -mod tests { - use actix_web::test::TestRequest; - - mod origin_header_str { - use super::*; - use crate::requests::get_request_signup_source::get_request_signup_source; - - #[test] - fn artcraft_dot_ai() { - let request = TestRequest::get() - .insert_header(("origin", "https://artcraft.ai")) - .to_http_request(); - assert_eq!(get_request_signup_source(&request), Some("artcraft")); - } - - #[test] - fn get_artcraft_dot_com() { - let request = TestRequest::get() - .insert_header(("origin", "https://getartcraft.com")) - .to_http_request(); - assert_eq!(get_request_signup_source(&request), Some("artcraft")); - } - - #[test] - fn api_dot_get_artcraft_dot_com() { - let request = TestRequest::get() - .insert_header(("origin", "https://api.getartcraft.com")) - .to_http_request(); - assert_eq!(get_request_signup_source(&request), Some("artcraft")); - } - - #[test] - fn fakeyou_dot_com() { - let request = TestRequest::get() - .insert_header(("origin", "https://fakeyou.com")) - .to_http_request(); - assert_eq!(get_request_signup_source(&request), Some("fakeyou")); - } - - #[test] - fn api_dot_fakeyou_dot_com() { - let request = TestRequest::get() - .insert_header(("origin", "https://api.fakeyou.com")) - .to_http_request(); - assert_eq!(get_request_signup_source(&request), Some("fakeyou")); - } - - #[test] - fn storyteller_dot_ai() { - let request = TestRequest::get() - .insert_header(("origin", "https://storyteller.ai")) - .to_http_request(); - assert_eq!(get_request_signup_source(&request), Some("storyteller")); - } - - #[test] - fn api_dot_storyteller_dot_ai() { - let request = TestRequest::get() - .insert_header(("origin", "https://api.storyteller.ai")) - .to_http_request(); - assert_eq!(get_request_signup_source(&request), Some("storyteller")); - } - } -} diff --git a/crates/lib/actix_artcraft/src/requests/get_request_signup_source_enum.rs b/crates/lib/actix_artcraft/src/requests/get_request_signup_source_enum.rs index 2d1bfaadf8..55bccfe413 100644 --- a/crates/lib/actix_artcraft/src/requests/get_request_signup_source_enum.rs +++ b/crates/lib/actix_artcraft/src/requests/get_request_signup_source_enum.rs @@ -1,10 +1,48 @@ -use crate::requests::get_request_signup_source::get_request_signup_source; +use actix_helpers::extractors::get_request_origin_uri::get_request_origin_uri; use actix_web::HttpRequest; use enums::by_table::users::user_signup_source::UserSignupSource; +use log::warn; pub fn get_request_signup_source_enum(http_request: &HttpRequest) -> Option { - get_request_signup_source(http_request) - .and_then(|source_str| UserSignupSource::from_str(source_str).ok()) + // NB: "Origin" vs "Referrer" + // + // Basically: + // - "In order to preserve privacy, any browser request can decide to omit the Referer header." + // - "The Origin header is similar to the Referer header, but does not disclose the path, and may be null." + // - "Origin" is sent on cross-origin, same-origin (except GET and HEAD requests - typically). + // + // Reading: + // - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Origin + // - https://stackoverflow.com/a/71040145 + // + let maybe_origin = get_request_origin_uri(&http_request); + + match maybe_origin { + Ok(Some(uri)) => { + if let Some(host) = uri.host() { + if host.contains("getartcraft.com") { + return Some(UserSignupSource::ArtCraftGetWeb); + } else if host.contains("artcraft.ai") { + return Some(UserSignupSource::ArtCraftAiWeb); + } else if host.contains("storyteller") { + return Some(UserSignupSource::Storyteller); + } else if host.contains("fakeyou") { + return Some(UserSignupSource::FakeYou); + } + } + } + // Fail open for now. + Ok(None) => {} + Err(err) => { + warn!("Origin header error: {:?}", err); + } + } + + // NB: We don't want to check the "Host" header because we might have misconfigured + // a future frontend to talk to some other API gateway and might be improperly and + // silently misattributing signup statistics. + + None } #[cfg(test)] @@ -21,7 +59,7 @@ mod tests { let request = TestRequest::get() .insert_header(("origin", "https://artcraft.ai")) .to_http_request(); - assert_eq!(get_request_signup_source_enum(&request), Some(UserSignupSource::ArtCraft)); + assert_eq!(get_request_signup_source_enum(&request), Some(UserSignupSource::ArtCraftAiWeb)); } #[test] @@ -29,7 +67,7 @@ mod tests { let request = TestRequest::get() .insert_header(("origin", "https://getartcraft.com")) .to_http_request(); - assert_eq!(get_request_signup_source_enum(&request), Some(UserSignupSource::ArtCraft)); + assert_eq!(get_request_signup_source_enum(&request), Some(UserSignupSource::ArtCraftGetWeb)); } #[test] @@ -37,7 +75,7 @@ mod tests { let request = TestRequest::get() .insert_header(("origin", "https://api.getartcraft.com")) .to_http_request(); - assert_eq!(get_request_signup_source_enum(&request), Some(UserSignupSource::ArtCraft)); + assert_eq!(get_request_signup_source_enum(&request), Some(UserSignupSource::ArtCraftGetWeb)); } #[test] diff --git a/crates/lib/actix_artcraft/src/requests/mod.rs b/crates/lib/actix_artcraft/src/requests/mod.rs index 022f6662f6..3f35271b30 100644 --- a/crates/lib/actix_artcraft/src/requests/mod.rs +++ b/crates/lib/actix_artcraft/src/requests/mod.rs @@ -1,2 +1 @@ -pub mod get_request_signup_source; pub mod get_request_signup_source_enum; \ No newline at end of file diff --git a/crates/service/plugins/billing_artcraft/src/endpoints/checkout_with_user_signup/user_creation_case.rs b/crates/service/plugins/billing_artcraft/src/endpoints/checkout_with_user_signup/user_creation_case.rs index 321f02a37d..ba8831765d 100644 --- a/crates/service/plugins/billing_artcraft/src/endpoints/checkout_with_user_signup/user_creation_case.rs +++ b/crates/service/plugins/billing_artcraft/src/endpoints/checkout_with_user_signup/user_creation_case.rs @@ -6,6 +6,7 @@ use crate::utils::create_checkout::create_subscription_checkout_session::{create use actix_artcraft::requests::get_request_signup_source_enum::get_request_signup_source_enum; use actix_web::HttpRequest; use enums::by_table::users::user_feature_flag::UserFeatureFlag; +use enums::by_table::users::user_signup_source::UserSignupSource; use http_server_common::request::get_request_ip::get_request_ip; use log::{error, info, warn}; use mysql_queries::queries::users::user::create::create_account_error::CreateAccountError; @@ -37,8 +38,16 @@ pub (super) async fn user_creation_case( })?; let ip_address = get_request_ip(&http_request); + let maybe_source = get_request_signup_source_enum(&http_request); + // NB: Adjust the signup source to the Stripe onboarding equivalent. + let maybe_source = match maybe_source { + Some(UserSignupSource::ArtCraftAiWeb) => Some(UserSignupSource::ArtCraftAiStripe), + Some(UserSignupSource::ArtCraftGetWeb) => Some(UserSignupSource::ArtCraftGetStripe), + _ => maybe_source, + }; + // NB: Not sure if these lock important functionality, so we're keeping this let user_feature_flags = vec![ UserFeatureFlag::Studio,