Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion devel/site-list.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

# Removes schema-specific keywords for proper processing
social_networks = data.copy()
social_networks.pop('$schema', None)
social_networks.pop("$schema", None)

# Sort the social networks in alphanumeric order
social_networks = sorted(social_networks.items())
Expand Down
42 changes: 27 additions & 15 deletions devel/summarize_site_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@
import sys
from pathlib import Path


def summarize_junit_xml(xml_path: Path) -> str:
tree = ET.parse(xml_path)
root = tree.getroot()
suite = root.find('testsuite')
suite = root.find("testsuite")

pass_message: str = ":heavy_check_mark:   Pass"
fail_message: str = ":x:   Fail"
Expand All @@ -22,42 +23,53 @@ def summarize_junit_xml(xml_path: Path) -> str:
summary_lines.append("| Target | F+ Check | F- Check |")
summary_lines.append("|---|---|---|")

failures = int(suite.get('failures', 0))
failures = int(suite.get("failures", 0))
errors_detected: bool = False

results: dict[str, dict[str, str]] = {}

for testcase in suite.findall('testcase'):
test_name = testcase.get('name').split('[')[0]
site_name = testcase.get('name').split('[')[1].rstrip(']')
failure = testcase.find('failure')
error = testcase.find('error')
for testcase in suite.findall("testcase"):
test_name = testcase.get("name").split("[")[0]
site_name = testcase.get("name").split("[")[1].rstrip("]")
failure = testcase.find("failure")
error = testcase.find("error")

if site_name not in results:
results[site_name] = {}

if test_name == "test_false_neg":
results[site_name]['F- Check'] = pass_message if failure is None and error is None else fail_message
results[site_name]["F- Check"] = (
pass_message if failure is None and error is None else fail_message
)
elif test_name == "test_false_pos":
results[site_name]['F+ Check'] = pass_message if failure is None and error is None else fail_message
results[site_name]["F+ Check"] = (
pass_message if failure is None and error is None else fail_message
)

if error is not None:
errors_detected = True

for result in results:
summary_lines.append(f"| {result} | {results[result].get('F+ Check', 'Error!')} | {results[result].get('F- Check', 'Error!')} |")
summary_lines.append(
f"| {result} | {results[result].get('F+ Check', 'Error!')} | {results[result].get('F- Check', 'Error!')} |"
)

if failures > 0:
summary_lines.append("\n___\n" +
"\nFailures were detected on at least one updated target. Commits containing accuracy failures" +
" will often not be merged (unless a rationale is provided, such as false negatives due to regional differences).")
summary_lines.append(
"\n___\n"
+ "\nFailures were detected on at least one updated target. Commits containing accuracy failures"
+ " will often not be merged (unless a rationale is provided, such as false negatives due to regional differences)."
)

if errors_detected:
summary_lines.append("\n___\n" +
"\n**Errors were detected during validation. Please review the workflow logs.**")
summary_lines.append(
"\n___\n"
+ "\n**Errors were detected during validation. Please review the workflow logs.**"
)

return "\n".join(summary_lines)


if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: summarize_site_validation.py <junit-xml-file>")
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,7 @@ defusedxml = "^0.7.1"

[tool.poetry.scripts]
sherlock = 'sherlock_project.sherlock:main'

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
17 changes: 11 additions & 6 deletions sherlock_project/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
""" Sherlock Module
"""Sherlock Module

This module contains the main logic to search for usernames at social
networks.
Expand All @@ -15,16 +15,21 @@ def get_version() -> str:
try:
return pkg_version("sherlock_project")
except PackageNotFoundError:
pyproject_path: pathlib.Path = pathlib.Path(__file__).resolve().parent.parent / "pyproject.toml"
pyproject_path: pathlib.Path = (
pathlib.Path(__file__).resolve().parent.parent / "pyproject.toml"
)
with pyproject_path.open("rb") as f:
pyproject_data = tomli.load(f)
return pyproject_data["tool"]["poetry"]["version"]


# This variable is only used to check for ImportErrors induced by users running as script rather than as module or package
import_error_test_var = None

__shortname__ = "Sherlock"
__longname__ = "Sherlock: Find Usernames Across Social Networks"
__version__ = get_version()
__shortname__ = "Sherlock"
__longname__ = "Sherlock: Find Usernames Across Social Networks"
__version__ = get_version()

forge_api_latest_release = "https://api.github.com/repos/sherlock-project/sherlock/releases/latest"
forge_api_latest_release = (
"https://api.github.com/repos/sherlock-project/sherlock/releases/latest"
)
5 changes: 4 additions & 1 deletion sherlock_project/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@
python_version = sys.version.split()[0]

if sys.version_info < (3, 9):
print(f"Sherlock requires Python 3.9+\nYou are using Python {python_version}, which is not supported by Sherlock.")
print(
f"Sherlock requires Python 3.9+\nYou are using Python {python_version}, which is not supported by Sherlock."
)
sys.exit(1)

from sherlock_project import sherlock

sherlock.main()
145 changes: 101 additions & 44 deletions sherlock_project/notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
This module defines the objects for notifying the caller about the
results of queries.
"""

from sherlock_project.result import QueryStatus
from colorama import Fore, Style
import webbrowser
Expand Down Expand Up @@ -155,13 +156,21 @@ def start(self, message):

title = "Checking username"

print(Style.BRIGHT + Fore.GREEN + "[" +
Fore.YELLOW + "*" +
Fore.GREEN + f"] {title}" +
Fore.WHITE + f" {message}" +
Fore.GREEN + " on:")
print(
Style.BRIGHT
+ Fore.GREEN
+ "["
+ Fore.YELLOW
+ "*"
+ Fore.GREEN
+ f"] {title}"
+ Fore.WHITE
+ f" {message}"
+ Fore.GREEN
+ " on:"
)
# An empty line between first line and the result(more clear output)
print('\r')
print("\r")

return

Expand Down Expand Up @@ -201,52 +210,92 @@ def update(self, result):
# Output to the terminal is desired.
if result.status == QueryStatus.CLAIMED:
self.countResults()
print(Style.BRIGHT + Fore.WHITE + "[" +
Fore.GREEN + "+" +
Fore.WHITE + "]" +
response_time_text +
Fore.GREEN +
f" {self.result.site_name}: " +
Style.RESET_ALL +
f"{self.result.site_url_user}")
print(
Style.BRIGHT
+ Fore.WHITE
+ "["
+ Fore.GREEN
+ "+"
+ Fore.WHITE
+ "]"
+ response_time_text
+ Fore.GREEN
+ f" {self.result.site_name}: "
+ Style.RESET_ALL
+ f"{self.result.site_url_user}"
)
if self.browse:
webbrowser.open(self.result.site_url_user, 2)

elif result.status == QueryStatus.AVAILABLE:
if self.print_all:
print(Style.BRIGHT + Fore.WHITE + "[" +
Fore.RED + "-" +
Fore.WHITE + "]" +
response_time_text +
Fore.GREEN + f" {self.result.site_name}:" +
Fore.YELLOW + " Not Found!")
print(
Style.BRIGHT
+ Fore.WHITE
+ "["
+ Fore.RED
+ "-"
+ Fore.WHITE
+ "]"
+ response_time_text
+ Fore.GREEN
+ f" {self.result.site_name}:"
+ Fore.YELLOW
+ " Not Found!"
)

elif result.status == QueryStatus.UNKNOWN:
if self.print_all:
print(Style.BRIGHT + Fore.WHITE + "[" +
Fore.RED + "-" +
Fore.WHITE + "]" +
Fore.GREEN + f" {self.result.site_name}:" +
Fore.RED + f" {self.result.context}" +
Fore.YELLOW + " ")
print(
Style.BRIGHT
+ Fore.WHITE
+ "["
+ Fore.RED
+ "-"
+ Fore.WHITE
+ "]"
+ Fore.GREEN
+ f" {self.result.site_name}:"
+ Fore.RED
+ f" {self.result.context}"
+ Fore.YELLOW
+ " "
)

elif result.status == QueryStatus.ILLEGAL:
if self.print_all:
msg = "Illegal Username Format For This Site!"
print(Style.BRIGHT + Fore.WHITE + "[" +
Fore.RED + "-" +
Fore.WHITE + "]" +
Fore.GREEN + f" {self.result.site_name}:" +
Fore.YELLOW + f" {msg}")

print(
Style.BRIGHT
+ Fore.WHITE
+ "["
+ Fore.RED
+ "-"
+ Fore.WHITE
+ "]"
+ Fore.GREEN
+ f" {self.result.site_name}:"
+ Fore.YELLOW
+ f" {msg}"
)

elif result.status == QueryStatus.WAF:
if self.print_all:
print(Style.BRIGHT + Fore.WHITE + "[" +
Fore.RED + "-" +
Fore.WHITE + "]" +
Fore.GREEN + f" {self.result.site_name}:" +
Fore.RED + " Blocked by bot detection" +
Fore.YELLOW + " (proxy may help)")
print(
Style.BRIGHT
+ Fore.WHITE
+ "["
+ Fore.RED
+ "-"
+ Fore.WHITE
+ "]"
+ Fore.GREEN
+ f" {self.result.site_name}:"
+ Fore.RED
+ " Blocked by bot detection"
+ Fore.YELLOW
+ " (proxy may help)"
)

else:
# It should be impossible to ever get here...
Expand All @@ -267,12 +316,20 @@ def finish(self, message="The processing has been finished."):
"""
NumberOfResults = self.countResults() - 1

print(Style.BRIGHT + Fore.GREEN + "[" +
Fore.YELLOW + "*" +
Fore.GREEN + "] Search completed with" +
Fore.WHITE + f" {NumberOfResults} " +
Fore.GREEN + "results" + Style.RESET_ALL
)
print(
Style.BRIGHT
+ Fore.GREEN
+ "["
+ Fore.YELLOW
+ "*"
+ Fore.GREEN
+ "] Search completed with"
+ Fore.WHITE
+ f" {NumberOfResults} "
+ Fore.GREEN
+ "results"
+ Style.RESET_ALL
)

def __str__(self):
"""Convert Object To String.
Expand Down
31 changes: 18 additions & 13 deletions sherlock_project/result.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

This module defines various objects for recording the results of queries.
"""

from enum import Enum


Expand All @@ -10,11 +11,12 @@ class QueryStatus(Enum):

Describes status of query about a given username.
"""
CLAIMED = "Claimed" # Username Detected
AVAILABLE = "Available" # Username Not Detected
UNKNOWN = "Unknown" # Error Occurred While Trying To Detect Username
ILLEGAL = "Illegal" # Username Not Allowable For This Site
WAF = "WAF" # Request blocked by WAF (i.e. Cloudflare)

CLAIMED = "Claimed" # Username Detected
AVAILABLE = "Available" # Username Not Detected
UNKNOWN = "Unknown" # Error Occurred While Trying To Detect Username
ILLEGAL = "Illegal" # Username Not Allowable For This Site
WAF = "WAF" # Request blocked by WAF (i.e. Cloudflare)

def __str__(self):
"""Convert Object To String.
Expand All @@ -27,13 +29,16 @@ def __str__(self):
"""
return self.value

class QueryResult():

class QueryResult:
"""Query Result Object.

Describes result of query about a given username.
"""
def __init__(self, username, site_name, site_url_user, status,
query_time=None, context=None):

def __init__(
self, username, site_name, site_url_user, status, query_time=None, context=None
):
"""Create Query Result Object.

Contains information about a specific method of detecting usernames on
Expand Down Expand Up @@ -62,12 +67,12 @@ def __init__(self, username, site_name, site_url_user, status,
Nothing.
"""

self.username = username
self.site_name = site_name
self.username = username
self.site_name = site_name
self.site_url_user = site_url_user
self.status = status
self.query_time = query_time
self.context = context
self.status = status
self.query_time = query_time
self.context = context

return

Expand Down
Loading