Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Misc Changes #4

Merged
merged 11 commits into from
Sep 11, 2024
Prev Previous commit
Next Next commit
pull out an async function to check for a user at a site
Dr-Emann committed Sep 4, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
commit 11d893a6882f683759390aa8580987963edf7a77
24 changes: 9 additions & 15 deletions src/checker.rs
Original file line number Diff line number Diff line change
@@ -69,28 +69,22 @@ pub async fn check_username(
} = result;

let query_result: QueryResult = match result.response {
Err(e) => match e {
QueryError::InvalidUsernameError => QueryResult {
username: Arc::clone(&username),
site_name: Arc::clone(&site),
info: Arc::clone(&info),
site_url_user: url,
status: QueryStatus::Illegal,
http_status: None,
query_time: result.query_time,
context: Some(e.to_string()),
},
QueryError::RequestError => QueryResult {
Err(e) => {
let status = match e {
QueryError::InvalidUsernameError => QueryStatus::Illegal,
QueryError::RequestError | QueryError::RegexError(_) => QueryStatus::Unknown,
};
QueryResult {
username: Arc::clone(&username),
site_name: Arc::clone(&site),
info: Arc::clone(&info),
site_url_user: url,
status: QueryStatus::Unknown,
status,
http_status: None,
query_time: result.query_time,
context: Some(e.to_string()),
},
},
}
}
Ok(response) => {
let status_code = response.status().as_u16();
let resp_text = response.text().await?;
128 changes: 63 additions & 65 deletions src/query.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use fancy_regex::Regex;
use reqwest::Response;
use std::sync::Arc;
use std::time::Duration;
use std::{fmt, time::Instant};
@@ -15,6 +16,8 @@ pub enum QueryError {
InvalidUsernameError,
#[error("Request error")]
RequestError,
#[error(transparent)]
RegexError(#[from] fancy_regex::Error),
}

#[derive(Debug, PartialEq, Eq)]
@@ -60,84 +63,79 @@ pub fn add_result_to_channel(
timeout: Duration,
proxy: Option<Arc<str>>,
) -> color_eyre::Result<()> {
let encoded_username = &username.replace(" ", "%20");
let profile_url = info.url.interpolate(encoded_username);
let url_probe = match &info.url_probe {
// There is a special URL for probing existence separate
// from where the user profile normally can be found.
Some(url_probe) => url_probe.interpolate(encoded_username),
None => info.url.interpolate(encoded_username),
};

let request_body = info
.request_payload
.as_ref()
.map(|payload| payload.to_string().interpolate(&username));

tokio::spawn(async move {
// use regex to make sure the url and username are valid for the site
if let Some(regex) = &info.regex_check {
let re = Regex::new(regex)?;
let is_match = re.is_match(&username)?;
if !is_match {
// No need to do the check at the site: this username is not allowed.
let request_result = RequestResult {
username: Arc::clone(&username),
site: Arc::clone(&site),
info,
url: profile_url,
url_probe,
response: Err(QueryError::InvalidUsernameError),
query_time: Duration::from_secs(0),
};

sender.send(request_result).await?;
return Ok::<_, color_eyre::eyre::Report>(());
}
}

let allow_redirects = !matches!(info.error_type, ErrorType::ResponseUrl { .. });

let req_method = info.request_method.unwrap_or(match info.error_type {
// In most cases when we are detecting by status code,
// it is not necessary to get the entire body: we can
// detect fine with just the HEAD response.
ErrorType::StatusCode { .. } => RequestMethod::Head,
// Either this detect method needs the content associated
// with the GET response, or this specific website will
// not respond properly unless we request the whole page.
_ => RequestMethod::Get,
});
let encoded_username = &username.replace(" ", "%20");
let profile_url = info.url.interpolate(encoded_username);
let url_probe = match &info.url_probe {
// There is a special URL for probing existence separate
// from where the user profile normally can be found.
Some(url_probe) => url_probe.interpolate(encoded_username),
None => info.url.interpolate(encoded_username),
};

let start = Instant::now();
let resp = make_request(
&url_probe,
info.headers.clone(),
allow_redirects,
timeout,
req_method,
request_body,
proxy.as_deref(),
None,
)
.await;
let response =
check_user_at_site(&username, &url_probe, &info, timeout, proxy.as_deref()).await;
let duration = start.elapsed();

let request_result = RequestResult {
username: Arc::clone(&username),
site: Arc::clone(&site),
username,
site,
info,
url: profile_url.clone(),
url_probe,
response: resp.map_err(|_| QueryError::RequestError),
response,
query_time: duration,
};

// send to channel
sender.send(request_result).await?;

Ok(())
// send to channel, ignore if the receiver has been dropped
let _ = sender.send(request_result).await;
});

Ok(())
}

async fn check_user_at_site(
username: &str,
url_probe: &str,
info: &TargetInfo,
timeout: Duration,
proxy: Option<&str>,
) -> Result<Response, QueryError> {
let request_body = info
.request_payload
.as_ref()
.map(|payload| payload.to_string().interpolate(&username));

// use regex to make sure the url and username are valid for the site
if let Some(regex) = &info.regex_check {
let re = Regex::new(regex)?;
let is_match = re.is_match(&username).unwrap_or(false);
if !is_match {
return Err(QueryError::InvalidUsernameError);
}
}
let allow_redirects = !matches!(info.error_type, ErrorType::ResponseUrl { .. });
let req_method = info.request_method.unwrap_or(match info.error_type {
// In most cases when we are detecting by status code,
// it is not necessary to get the entire body: we can
// detect fine with just the HEAD response.
ErrorType::StatusCode { .. } => RequestMethod::Head,
// Either this detect method needs the content associated
// with the GET response, or this specific website will
// not respond properly unless we request the whole page.
_ => RequestMethod::Get,
});
make_request(
url_probe,
info.headers.clone(),
allow_redirects,
timeout,
req_method,
request_body,
proxy,
None,
)
.await
.map_err(|_| QueryError::RequestError)
}