chore: omit ip from usercheck decision requests

This commit is contained in:
Michael H.
2026-08-26 12:28:25 +02:00
parent 715f4954cf
commit 36f9dbb47a
2 changed files with 11 additions and 26 deletions
+7 -14
View File
@@ -24,7 +24,6 @@ use crate::util::error::ApiContext as _;
use crate::util::error::Context; use crate::util::error::Context;
use crate::util::ext::get_image_ext; use crate::util::ext::get_image_ext;
use crate::util::img::upload_image_optimized; use crate::util::img::upload_image_optimized;
use crate::util::ip::client_ip;
use crate::util::neverbounce::{check_email, email_check_error_generic}; use crate::util::neverbounce::{check_email, email_check_error_generic};
use crate::util::usercheck::{ use crate::util::usercheck::{
DecisionAction, check_email_gate, gate_block_error, DecisionAction, check_email_gate, gate_block_error,
@@ -1545,7 +1544,7 @@ pub async fn create_oauth_account(
}; };
if let Some(email) = &user.email { if let Some(email) = &user.email {
ensure_email_passes_gate(&req, email) ensure_email_passes_gate(email)
.await .await
.wrap_api_err("validating email passes the signup gate")?; .wrap_api_err("validating email passes the signup gate")?;
} }
@@ -1903,11 +1902,8 @@ impl From<NewAccount> for AccountRegisterFlow {
} }
/// Runs the UserCheck gate, which covers both password and OAuth signups. /// Runs the UserCheck gate, which covers both password and OAuth signups.
async fn ensure_email_passes_gate( async fn ensure_email_passes_gate(email: &str) -> Result<(), ApiError> {
req: &HttpRequest, let action = check_email_gate(email)
email: &str,
) -> Result<(), ApiError> {
let action = check_email_gate(email, client_ip(req).as_deref())
.await .await
.wrap_request_err("checking email address")?; .wrap_request_err("checking email address")?;
@@ -1918,11 +1914,8 @@ async fn ensure_email_passes_gate(
Ok(()) Ok(())
} }
async fn ensure_email_is_usable( async fn ensure_email_is_usable(email: &str) -> Result<(), ApiError> {
req: &HttpRequest, ensure_email_passes_gate(email).await?;
email: &str,
) -> Result<(), ApiError> {
ensure_email_passes_gate(req, email).await?;
let result = check_email(email) let result = check_email(email)
.await .await
@@ -2151,7 +2144,7 @@ pub async fn create_account_with_password(
))); )));
} }
ensure_email_is_usable(&req, &new_account.email) ensure_email_is_usable(&new_account.email)
.await .await
.wrap_api_err("validating email is usable")?; .wrap_api_err("validating email is usable")?;
@@ -3136,7 +3129,7 @@ pub async fn set_email(
))); )));
} }
ensure_email_is_usable(&req, &email_address.email) ensure_email_is_usable(&email_address.email)
.await .await
.wrap_api_err("validating email is usable")?; .wrap_api_err("validating email is usable")?;
+4 -12
View File
@@ -76,8 +76,6 @@ struct ResponseMeta {
#[derive(Serialize)] #[derive(Serialize)]
struct DecisionRequest<'a> { struct DecisionRequest<'a> {
email: &'a str, email: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
ip: Option<&'a str>,
} }
/// Asks the configured UserCheck gate whether a signup should proceed. /// Asks the configured UserCheck gate whether a signup should proceed.
@@ -87,10 +85,7 @@ struct DecisionRequest<'a> {
/// signup, while anything else is an error that rejects the signup. /// signup, while anything else is an error that rejects the signup.
/// `Challenge` resolves to `Allow` because these flows have no step-up /// `Challenge` resolves to `Allow` because these flows have no step-up
/// mechanism past the captcha that already ran. /// mechanism past the captcha that already ran.
pub async fn check_email_gate( pub async fn check_email_gate(email: &str) -> eyre::Result<DecisionAction> {
email: &str,
ip: Option<&str>,
) -> eyre::Result<DecisionAction> {
if ENV.USERCHECK_API_KEY.is_empty() || ENV.USERCHECK_GATE_ID.is_empty() { if ENV.USERCHECK_API_KEY.is_empty() || ENV.USERCHECK_GATE_ID.is_empty() {
debug!( debug!(
action = "allow", action = "allow",
@@ -100,7 +95,7 @@ pub async fn check_email_gate(
} }
let decision_time_start = Instant::now(); let decision_time_start = Instant::now();
let response = request_decision(email, ip).await; let response = request_decision(email).await;
let decision_time = decision_time_start.elapsed(); let decision_time = decision_time_start.elapsed();
let response = match response { let response = match response {
@@ -180,10 +175,7 @@ pub fn gate_block_error() -> eyre::Error {
) )
} }
async fn request_decision( async fn request_decision(email: &str) -> reqwest::Result<DecisionResponse> {
email: &str,
ip: Option<&str>,
) -> reqwest::Result<DecisionResponse> {
HTTP_CLIENT HTTP_CLIENT
.post(format!( .post(format!(
"{}/v0/gates/{}/decisions", "{}/v0/gates/{}/decisions",
@@ -192,7 +184,7 @@ async fn request_decision(
)) ))
.bearer_auth(&ENV.USERCHECK_API_KEY) .bearer_auth(&ENV.USERCHECK_API_KEY)
.timeout(TIMEOUT) .timeout(TIMEOUT)
.json(&DecisionRequest { email, ip }) .json(&DecisionRequest { email })
.send() .send()
.await? .await?
.error_for_status()? .error_for_status()?