use clap::Parser;
use color_eyre::Result;
use sherlock::{
get_data::{get_default_data, get_json_data},
output::save_results,
sherlock::check_username,
sherlock_target_manifest::SherlockTargetManifest,
utils::create_username_variants,
};
#[derive(Parser)]
#[command(version, about, long_about = None)]
#[command(name = "sherlock")]
#[command(author = "Johannes Naylor <jonaylor89@gmail.com>")]
#[command(version = "0.1.0")]
#[command(about = "Hunt down social media accounts by username", long_about = None)]
struct Cli {
#[clap(name = "usernames", required = true)]
usernames: Vec<String>,
#[clap(short, long, alias = "debug")]
verbose: bool,
#[clap(short, long = "output")]
output_file: Option<String>,
#[clap(short = 'f', long, alias = "output-folder")]
output_folder: Option<String>,
#[clap(short, long, alias = "csv")]
csv: bool,
#[clap(long)]
xlsx: bool,
#[clap(short, long)]
site_list: Vec<String>,
#[clap(short, long, alias = "proxy")]
proxy: Option<String>,
#[clap(short, long)]
dump_response: bool,
#[clap(
short,
long = "json",
default_value = "https://raw.githubusercontent.com/sherlock-project/sherlock/master/sherlock_project/resources/data.json"
)]
json_file: String,
#[clap(short, long, alias = "timeout", default_value_t = 60)]
timeout: u64,
#[clap(long, alias = "print-all")]
print_all: bool,
#[clap(long, alias = "print-found", default_value_t = true)]
print_found: bool,
#[clap(short, long, alias = "browse")]
browse: bool,
#[clap(short, long)]
local: bool,
#[clap(long, alias = "nsfw", default_value_t = true)]
nsfw: bool,
}
#[tokio::main]
async fn main() -> Result<()> {
color_eyre::install()?;
let cli = Cli::parse();
let json_str = match cli.local {
true => get_default_data(),
false => get_json_data(cli.json_file).await?,
};
let deserializer = &mut serde_json::Deserializer::from_str(&json_str);
let initial_data: SherlockTargetManifest = serde_path_to_error::deserialize(deserializer)
.inspect_err(|err| {
println!("[!!!] error path [{}]", err.path());
})?;
let targets = match cli.nsfw {
true => initial_data.targets,
false => initial_data
.targets
.into_iter()
.filter(|(_, info)| !info.is_nsfw.unwrap_or(false))
.collect(),
};
let filtered_targets = match cli.site_list.is_empty() {
true => targets,
false => targets
.into_iter()
.filter(|(site, _)| cli.site_list.contains(site))
.collect(),
};
let username_variants = create_username_variants(&cli.usernames);
for username in username_variants {
let results = check_username(
&username,
filtered_targets.clone(),
cli.timeout,
cli.proxy.as_ref(),
cli.print_all,
cli.print_found,
cli.dump_response,
cli.browse,
)
.await?;
save_results(
&username,
results,
cli.output_file.as_ref(),
cli.output_folder.as_ref(),
cli.csv,
cli.xlsx,
cli.print_all,
cli.print_found,
)?;
}
Ok(())
}