mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 17:58:55 +00:00
source
This commit is contained in:
1 parent
c0627eee28
commit
6bd31c7075
4 files changed
+130
-146
No files matched your search
+2
-22
@@ -7,7 +7,6 @@ use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::fmt::Formatter;
|
||||
|
||||
use actix_helpers::extractors::get_request_origin_uri::get_request_origin_uri;
|
||||
use actix_web::error::ResponseError;
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::{web, HttpRequest, HttpResponse};
|
||||
@@ -23,7 +22,7 @@ use sqlx::MySqlPool;
|
||||
use tokens::tokens::user_sessions::UserSessionToken;
|
||||
use user_input_common::check_for_slurs::contains_slurs;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
use crate::http_server::requests::get_request_signup_source::get_request_signup_source;
|
||||
use crate::http_server::session::http::http_user_session_manager::HttpUserSessionManager;
|
||||
use crate::http_server::validations::is_reserved_username::is_reserved_username;
|
||||
use crate::http_server::validations::validate_passwords::validate_passwords;
|
||||
@@ -185,26 +184,7 @@ pub async fn create_account_handler(
|
||||
|
||||
let ip_address = get_request_ip(&http_request);
|
||||
|
||||
let maybe_origin = get_request_origin_uri(&http_request);
|
||||
|
||||
let mut maybe_source = None;
|
||||
|
||||
match maybe_origin {
|
||||
Ok(Some(uri)) => {
|
||||
if let Some(host) = uri.host() {
|
||||
if host.contains("storyteller") {
|
||||
maybe_source = Some("storyteller");
|
||||
} else if host.contains("fakeyou") {
|
||||
maybe_source = Some("fakeyou");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fail open for now.
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
warn!("Origin header error: {:?}", err);
|
||||
}
|
||||
}
|
||||
let maybe_source = get_request_signup_source(&http_request);
|
||||
|
||||
let create_account_result = create_account_from_email_and_password(
|
||||
&mysql_pool,
|
||||
|
||||
+4
-1
@@ -15,6 +15,7 @@ use mysql_queries::queries::users::user::lookup_user_for_login_result::UserRecor
|
||||
use mysql_queries::utils::transactor::Transactor;
|
||||
use sqlx::pool::PoolConnection;
|
||||
use sqlx::{Acquire, MySql};
|
||||
use crate::http_server::requests::get_request_signup_source::get_request_signup_source;
|
||||
|
||||
pub struct CreateArgs<'a> {
|
||||
pub http_request: &'a HttpRequest,
|
||||
@@ -42,6 +43,8 @@ pub async fn handle_creating_user_account(
|
||||
let ip_address = get_request_ip(&args.http_request);
|
||||
let user_email_gravatar_hash = email_to_gravatar(&args.user_email_address);
|
||||
|
||||
let mut maybe_source = get_request_signup_source(&args.http_request);
|
||||
|
||||
let mut maybe_user_token = None;
|
||||
let mut maybe_user_display_name = None;
|
||||
|
||||
@@ -61,7 +64,7 @@ pub async fn handle_creating_user_account(
|
||||
email_confirmed_by_google: args.claims.email_verified(),
|
||||
maybe_feature_flags: user_feature_flags.as_deref(),
|
||||
ip_address: &ip_address,
|
||||
maybe_source: None, // TODO: Add source
|
||||
maybe_source,
|
||||
},
|
||||
Transactor::for_transaction(&mut transaction),
|
||||
).await;
|
||||
|
||||
+104
-46
@@ -1,6 +1,7 @@
|
||||
use actix_helpers::extractors::get_request_origin_uri::get_request_origin_uri;
|
||||
use actix_web::http::header::HOST;
|
||||
use actix_web::HttpRequest;
|
||||
use log::info;
|
||||
use log::{info, warn};
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum DomainBranding {
|
||||
@@ -9,7 +10,36 @@ pub enum DomainBranding {
|
||||
}
|
||||
|
||||
pub fn get_request_domain_branding(http_request: &HttpRequest) -> Option<DomainBranding> {
|
||||
// NB: http_request.uri() does not include the hostname - it only includes the path (!)
|
||||
// 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(branding) = match_possible_hostname(uri.host()) {
|
||||
info!("Origin header: {:?} Branding for hostname: {:?}", uri, branding);
|
||||
return Some(branding);
|
||||
}
|
||||
}
|
||||
// Fail open for now.
|
||||
Ok(None) => {}
|
||||
Err(err) => {
|
||||
warn!("Origin header error: {:?}", err);
|
||||
}
|
||||
}
|
||||
|
||||
// NB: The "HOST" header contains the hostname. The `http_request.uri()` method we tried
|
||||
// before does not include the hostname at all - it only includes the path (!), which is
|
||||
// why we use "HOST" header instead.
|
||||
let maybe_host_header = http_request.headers()
|
||||
.get(HOST)
|
||||
.map(|header| header.to_str().ok())
|
||||
@@ -20,14 +50,6 @@ pub fn get_request_domain_branding(http_request: &HttpRequest) -> Option<DomainB
|
||||
return Some(branding);
|
||||
}
|
||||
|
||||
// NB: This may not actually work against real requests. It fails in local dev. See above comment.
|
||||
let maybe_hostname = http_request.uri().host();
|
||||
|
||||
if let Some(branding) = match_possible_hostname(maybe_hostname) {
|
||||
info!("URI hostname: {:?} Branding for hostname: {:?}", maybe_hostname, branding);
|
||||
return Some(branding);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
@@ -47,7 +69,43 @@ fn match_possible_hostname(maybe_hostname: Option<&str>) -> Option<DomainBrandin
|
||||
mod tests {
|
||||
use actix_web::test::TestRequest;
|
||||
|
||||
use crate::http_server::requests::get_request_domain_branding::{DomainBranding, get_request_domain_branding};
|
||||
use crate::http_server::requests::get_request_domain_branding::{get_request_domain_branding, DomainBranding};
|
||||
|
||||
mod origin_header {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fakeyou_dot_com() {
|
||||
let request = TestRequest::get()
|
||||
.insert_header(("origin", "https://fakeyou.com"))
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::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_domain_branding(&request), Some(DomainBranding::FakeYou));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storyteller_dot_ai() {
|
||||
let request = TestRequest::get()
|
||||
.insert_header(("origin", "https://storyteller.ai"))
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::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_domain_branding(&request), Some(DomainBranding::Storyteller));
|
||||
}
|
||||
}
|
||||
|
||||
mod host_header {
|
||||
use super::*;
|
||||
@@ -85,39 +143,39 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
mod uri {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fakeyou_dot_com() {
|
||||
let request = TestRequest::get()
|
||||
.uri("https://fakeyou.com")
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::FakeYou));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_dot_fakeyou_dot_com() {
|
||||
let request = TestRequest::get()
|
||||
.uri("https://api.fakeyou.com")
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::FakeYou));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn storyteller_dot_ai() {
|
||||
let request = TestRequest::get()
|
||||
.uri("https://storyteller.ai")
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::Storyteller));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn api_dot_storyteller_dot_ai() {
|
||||
let request = TestRequest::get()
|
||||
.uri("https://api.storyteller.ai")
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::Storyteller));
|
||||
}
|
||||
}
|
||||
// mod uri {
|
||||
// use super::*;
|
||||
//
|
||||
// #[test]
|
||||
// fn fakeyou_dot_com() {
|
||||
// let request = TestRequest::get()
|
||||
// .uri("https://fakeyou.com")
|
||||
// .to_http_request();
|
||||
// assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::FakeYou));
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn api_dot_fakeyou_dot_com() {
|
||||
// let request = TestRequest::get()
|
||||
// .uri("https://api.fakeyou.com")
|
||||
// .to_http_request();
|
||||
// assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::FakeYou));
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn storyteller_dot_ai() {
|
||||
// let request = TestRequest::get()
|
||||
// .uri("https://storyteller.ai")
|
||||
// .to_http_request();
|
||||
// assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::Storyteller));
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn api_dot_storyteller_dot_ai() {
|
||||
// let request = TestRequest::get()
|
||||
// .uri("https://api.storyteller.ai")
|
||||
// .to_http_request();
|
||||
// assert_eq!(get_request_domain_branding(&request), Some(DomainBranding::Storyteller));
|
||||
// }
|
||||
// }
|
||||
}
|
||||
+20
-77
@@ -1,3 +1,4 @@
|
||||
use actix_http::header::HOST;
|
||||
use actix_helpers::extractors::get_request_origin_uri::get_request_origin_uri;
|
||||
use actix_web::HttpRequest;
|
||||
use log::warn;
|
||||
@@ -9,6 +10,17 @@ const STORYTELLER : &str = "storyteller";
|
||||
/// 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 {
|
||||
@@ -28,6 +40,10 @@ pub fn get_request_signup_source(http_request: &HttpRequest) -> Option<&'static
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -42,7 +58,7 @@ mod tests {
|
||||
#[test]
|
||||
fn fakeyou_dot_com() {
|
||||
let request = TestRequest::get()
|
||||
.insert_header(("origin", "fakeyou.com"))
|
||||
.insert_header(("origin", "https://fakeyou.com"))
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_signup_source(&request), Some("fakeyou"));
|
||||
}
|
||||
@@ -50,7 +66,7 @@ mod tests {
|
||||
#[test]
|
||||
fn api_dot_fakeyou_dot_com() {
|
||||
let request = TestRequest::get()
|
||||
.insert_header(("origin", "api.fakeyou.com"))
|
||||
.insert_header(("origin", "https://api.fakeyou.com"))
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_signup_source(&request), Some("fakeyou"));
|
||||
}
|
||||
@@ -58,7 +74,7 @@ mod tests {
|
||||
#[test]
|
||||
fn storyteller_dot_ai() {
|
||||
let request = TestRequest::get()
|
||||
.insert_header(("origin", "storyteller.ai"))
|
||||
.insert_header(("origin", "https://storyteller.ai"))
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_signup_source(&request), Some("storyteller"));
|
||||
}
|
||||
@@ -66,80 +82,7 @@ mod tests {
|
||||
#[test]
|
||||
fn api_dot_storyteller_dot_ai() {
|
||||
let request = TestRequest::get()
|
||||
.insert_header(("origin", "api.storyteller.ai"))
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_signup_source(&request), Some("storyteller"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mod host_header {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fakeyou_dot_com() {
|
||||
let request = TestRequest::get()
|
||||
.insert_header(("host", "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(("host", "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(("host", "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(("host", "api.storyteller.ai"))
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_signup_source(&request), Some("storyteller"));
|
||||
}
|
||||
}
|
||||
|
||||
mod uri {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn fakeyou_dot_com() {
|
||||
let request = TestRequest::get()
|
||||
.uri("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()
|
||||
.uri("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()
|
||||
.uri("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()
|
||||
.uri("https://api.storyteller.ai")
|
||||
.insert_header(("origin", "https://api.storyteller.ai"))
|
||||
.to_http_request();
|
||||
assert_eq!(get_request_signup_source(&request), Some("storyteller"));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user