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

[issue-2164] added '--tag' flag functionality #2169

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
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
63 changes: 63 additions & 0 deletions sherlock/resources/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -1256,6 +1256,69 @@
"urlMain": "https://launchpad.net/",
"username_claimed": "blue"
},
"LoLKr": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/kr/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "NS Callme#KR1"
},
"LoLEune": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/eune/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "NotPurple#EUNE"
},
"LoLEuw": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/euw/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "normalus bahuras#EUW"
},
"LoLNa": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/na/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "Sheiden#0001"
},
"LoLVn": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/vn/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "Shirou#2K5"
},
"LoLBr": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/br/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "frosty#KR3"
},
"LoLTr": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/tr/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "Hide on bush#MBM0"
},
"LoLJp": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/jp/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "Ninja of Ninjas#JP1"
},
"LoLOce": {
"errorType": "status_code",
"isTagRequired": true,
"url": "https://www.leagueofgraphs.com/summoner/oce/{}-<>",
"urlMain": "https://www.leagueofgraphs.com/",
"username_claimed": "Stop here#OCE"
},
"LeetCode": {
"errorType": "status_code",
"url": "https://leetcode.com/{}",
Expand Down
1 change: 1 addition & 0 deletions sherlock/resources/data.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"username_claimed": { "type": "string" },
"regexCheck": { "type": "string" },
"isNSFW": { "type": "boolean" },
"isTagRequired": { "type": "boolean"},
"headers": { "type": "object" },
"request_payload": { "type": "object" },
"__comment__": {
Expand Down
41 changes: 34 additions & 7 deletions sherlock/sherlock.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,16 @@ def get_response(request_future, error_type, social_network):
return response, error_context, exception_text


def interpolate_string(input_object, username):
def interpolate_string(input_object, username, has_tag):
if isinstance(input_object, str):
if has_tag and '#' in username:
username, tag = username.split('#')
input_object = input_object.replace("<>", tag)
return input_object.replace("{}", username)
elif isinstance(input_object, dict):
return {k: interpolate_string(v, username) for k, v in input_object.items()}
return {k: interpolate_string(v, username, has_tag) for k, v in input_object.items()}
elif isinstance(input_object, list):
return [interpolate_string(i, username) for i in input_object]
return [interpolate_string(i, username, has_tag) for i in input_object]
return input_object


Expand All @@ -168,6 +171,7 @@ def sherlock(
username,
site_data,
query_notify: QueryNotify,
has_tag: bool = False,
tor: bool = False,
unique_tor: bool = False,
proxy=None,
Expand Down Expand Up @@ -253,8 +257,13 @@ def sherlock(
# Override/append any extra headers required by a given site.
headers.update(net_info["headers"])

# if --tag flag is set but username doesn't contain tag, no need to make any requests
if has_tag and '#' not in username:
print("Flag --tag was set, but the tag wasn't provided. Please use "
"'username#tag' format")
return results_total
# URL of user on site (if it exists)
url = interpolate_string(net_info["url"], username.replace(' ', '%20'))
url = interpolate_string(net_info["url"], username.replace(' ', '%20'), has_tag)

# Don't make request if username is invalid for the site
regex_check = net_info.get("regexCheck")
Expand Down Expand Up @@ -288,15 +297,15 @@ def sherlock(
raise RuntimeError(f"Unsupported request_method for {url}")

if request_payload is not None:
request_payload = interpolate_string(request_payload, username)
request_payload = interpolate_string(request_payload, username, has_tag)

if url_probe is None:
# Probe URL is normal one seen by people out on the web.
url_probe = url
else:
# There is a special URL for probing existence separate
# from where the user profile normally can be found.
url_probe = interpolate_string(url_probe, username)
url_probe = interpolate_string(url_probe, username, has_tag)

if request is None:
if net_info["errorType"] == "status_code":
Expand Down Expand Up @@ -666,6 +675,15 @@ def main():
help="Include checking of NSFW sites from default list.",
)

parser.add_argument(
"--tag",
action="store_true",
dest="tag",
default=False,
help="Search for a user name including a user tag (e.g. League of Legends, Valorant). "
"Username has to be entered in format 'username#tag'."
)

args = parser.parse_args()

# If the user presses CTRL-C, exit gracefully without throwing errors
Expand Down Expand Up @@ -737,6 +755,11 @@ def main():
if not args.nsfw:
sites.remove_nsfw_sites(do_not_remove=args.site_list)

if args.tag:
sites.filter_websites_based_on_tag(args.site_list, tag_required=True)
else:
sites.filter_websites_based_on_tag(args.site_list, tag_required=False)

# Create original dictionary from SitesInformation() object.
# Eventually, the rest of the code will be updated to use the new object
# directly, but this will glue the two pieces together.
Expand All @@ -760,7 +783,10 @@ def main():
site_missing.append(f"'{site}'")

if site_missing:
print(f"Error: Desired sites not found: {', '.join(site_missing)}.")
if args.tag:
print(f"Error: '--tag' flag was set, but {', '.join(site_missing)} usernames don't have tags.")
else:
print(f"Error: Desired sites not found: {', '.join(site_missing)}.")

if not site_data:
sys.exit(1)
Expand All @@ -783,6 +809,7 @@ def main():
username,
site_data,
query_notify,
args.tag,
tor=args.tor,
unique_tor=args.unique_tor,
proxy=args.proxy,
Expand Down
36 changes: 31 additions & 5 deletions sherlock/sites.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class SiteInformation:
def __init__(self, name, url_home, url_username_format, username_claimed,
information, is_nsfw, username_unclaimed=secrets.token_urlsafe(10)):
information, is_nsfw, is_tag_required, username_unclaimed=secrets.token_urlsafe(10)):
"""Create Site Information Object.

Contains information about a specific website.
Expand Down Expand Up @@ -55,6 +55,7 @@ def __init__(self, name, url_home, url_username_format, username_claimed,
self.username_unclaimed = secrets.token_urlsafe(32)
self.information = information
self.is_nsfw = is_nsfw
self.is_tag_required = is_tag_required

return

Expand All @@ -67,7 +68,7 @@ def __str__(self):
Return Value:
Nicely formatted string to get information about this object.
"""

return f"{self.name} ({self.url_home})"


Expand Down Expand Up @@ -152,7 +153,7 @@ def __init__(self, data_file_path=None):
raise FileNotFoundError(f"Problem while attempting to access "
f"data file '{data_file_path}'."
)

site_data.pop('$schema', None)

self.sites = {}
Expand All @@ -167,7 +168,8 @@ def __init__(self, data_file_path=None):
site_data[site_name]["url"],
site_data[site_name]["username_claimed"],
site_data[site_name],
site_data[site_name].get("isNSFW",False)
site_data[site_name].get("isNSFW", False),
site_data[site_name].get("isTagRequired", False)

)
except KeyError as error:
Expand All @@ -179,6 +181,30 @@ def __init__(self, data_file_path=None):

return

def filter_websites_based_on_tag(self, site_list, tag_required):
"""
Filter websites based on '--tag' flag, if it's provided, the result is a list
of websites that have isTagRequired set to True, and if '--tag' is not provided,
the result is a list of all websites that don't have isTagRequired set to True.

Keyword Arguments:
self -- This object.
site_list -- sites provided with '--site' flag
tag_required -- boolean value, True if '--tag' flag is provided

Return Value:
None
"""
sites_requiring_tag = set(site for site in self.sites if self.sites[site].is_tag_required)
if not tag_required and sites_requiring_tag and site_list:
print("Some websites require a tag, but the tag flag is not set.")
filtered_sites = {}
for site in self.sites:
if (tag_required and site in sites_requiring_tag) or \
(not tag_required and site not in sites_requiring_tag):
filtered_sites[site] = self.sites[site]
self.sites = filtered_sites

def remove_nsfw_sites(self, do_not_remove: list = []):
"""
Remove NSFW sites from the sites, if isNSFW flag is true for site
Expand All @@ -194,7 +220,7 @@ def remove_nsfw_sites(self, do_not_remove: list = []):
for site in self.sites:
if self.sites[site].is_nsfw and site.casefold() not in do_not_remove:
continue
sites[site] = self.sites[site]
sites[site] = self.sites[site]
self.sites = sites

def site_name_list(self):
Expand Down