Skip to content

Commit 6eb193a

Browse files
authored
Add files via upload
1 parent 0a58fdf commit 6eb193a

File tree

4 files changed

+973
-0
lines changed

4 files changed

+973
-0
lines changed

namecheck.py

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
import sys
2+
import os
3+
import json
4+
import aiohttp
5+
import asyncio
6+
import time
7+
import requests
8+
import urllib.parse
9+
from pathlib import Path
10+
from termcolor import colored
11+
12+
13+
def read_json(filename):
14+
"""read json file to dict"""
15+
data = {}
16+
try:
17+
with open(filename) as f:
18+
data = json.load(f)
19+
except FileNotFoundError:
20+
pass
21+
return data
22+
23+
24+
def bool_to_color(flag: bool):
25+
"""return color refered to flag"""
26+
if flag:
27+
return 'cyan'
28+
return 'red'
29+
30+
31+
def user_exist_status(response_status, response_text, pattern_ok, pattern_nok):
32+
"""
33+
asyncio:
34+
response.status_code -> response.status
35+
response.text -> await response.text()
36+
"""
37+
if pattern_ok:
38+
if (response_status == 200) and pattern_ok in response_text:
39+
user_exist = True
40+
else:
41+
user_exist = False
42+
elif pattern_nok:
43+
if (response_status == 200) and pattern_nok in response_text:
44+
user_exist = False
45+
else:
46+
user_exist = True
47+
else:
48+
if (response_status == 200):
49+
user_exist = True
50+
else:
51+
user_exist = False
52+
return user_exist
53+
54+
55+
async def request_user_exist(session, key, url, pattern_ok, pattern_nok, allow_redirects, custom_user_agent):
56+
"""make asyncio request"""
57+
try:
58+
if custom_user_agent:
59+
user_agent = 'Mozilla/5.0 (Linux; Android 9; SM-A305GT) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.58 Mobile Safari/537.36'
60+
headers = {"User-Agent": user_agent}
61+
else:
62+
headers = None
63+
async with session.get(url, headers=headers, allow_redirects=allow_redirects, timeout=10) as response:
64+
response_status = response.status
65+
if pattern_ok or pattern_nok:
66+
response_text = await response.text()
67+
else:
68+
response_text = ''
69+
user_exist = user_exist_status(response_status, response_text, pattern_ok, pattern_nok)
70+
# print(colored('[*] done for url: {}'.format(url), 'green') + colored(' (allow_redirects={})'.format(allow_redirects), bool_to_color(allow_redirects)))
71+
return (key, url, user_exist)
72+
73+
except UnicodeDecodeError as err:
74+
# print(colored('[x] error catched: {}'.format(err), 'red'))
75+
return (key, url, None)
76+
77+
except aiohttp.client_exceptions.ClientConnectorCertificateError as err:
78+
# print(colored('[x] error catched: {}'.format(err), 'red'))
79+
return (key, url, None)
80+
81+
except aiohttp.client_exceptions.ClientConnectorError as err:
82+
# print(colored('[x] error catched: {}'.format(err), 'red'))
83+
return (key, url, None)
84+
85+
except asyncio.exceptions.TimeoutError as err:
86+
# print(colored('[x] error catched: {}'.format(err), 'red'))
87+
return (key, url, None)
88+
89+
90+
async def main(namecheck_urls, username):
91+
"""create ascyncio tasks"""
92+
async with aiohttp.ClientSession() as session:
93+
tasks = []
94+
for index, (key, item) in enumerate(namecheck_urls.items()):
95+
url_encoded_username = urllib.parse.quote(username.encode('utf8'))
96+
url = item['url'].format(username=url_encoded_username)
97+
pattern_ok = item['pattern_ok'].format(username=username)
98+
pattern_nok = item['pattern_nok'].format(username=username)
99+
allow_redirects = item.get('allow_redirects', True)
100+
custom_user_agent = item.get('custom_user_agent', False)
101+
tasks.append(asyncio.ensure_future(request_user_exist(session, key, url, pattern_ok, pattern_nok, allow_redirects, custom_user_agent)))
102+
return await asyncio.gather(*tasks)
103+
104+
105+
def filter_urls(namecheck_urls: dict, to_filter: list):
106+
"""to_filter: list or tuple of urls"""
107+
namecheck_urls = {key:value for key, value in namecheck_urls.items() if key in to_filter}
108+
return namecheck_urls
109+
110+
111+
def run_main(namecheck_urls: dict, username: str):
112+
"""
113+
fix for <RuntimeError: Event loop is closed> error:
114+
https://stackoverflow.com/questions/45600579/asyncio-event-loop-is-closed-when-getting-loop
115+
"""
116+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
117+
response_values = asyncio.run(main(namecheck_urls, username))
118+
return response_values
119+
120+
121+
if __name__ == "__main__":
122+
# *********** setup ***********
123+
os.chdir(str(Path(sys.argv[0]).parent))
124+
os.system('color')
125+
start_time = time.time()
126+
127+
# *********** username ***********
128+
args = sys.argv[1:]
129+
if not args:
130+
print('[*] usage:')
131+
print(colored(' python namecheck.py <username>', 'yellow'))
132+
sys.exit()
133+
username = args[0]
134+
print('[*] username: {}'.format(colored(username, 'yellow')))
135+
136+
# *********** collect urls ***********
137+
namecheck_urls = read_json('namecheck_urls.json')
138+
# namecheck_urls = filter_urls(namecheck_urls, ['Hackernoon'])
139+
140+
# *********** main ***********
141+
response_values = run_main(namecheck_urls, username)
142+
print('\n------------------------------------------------------------')
143+
for index, (key, url, user_exist) in enumerate(response_values):
144+
if user_exist is None:
145+
color = 'red' # error
146+
elif user_exist:
147+
color = 'green'
148+
else:
149+
color = 'yellow'
150+
print(colored('{:02}) {}'.format(index+1, (key, url, user_exist)), color))
151+
print("\n[*] total time: {} [s]".format(round(time.time() - start_time, 4)))
152+
153+
154+
"""
155+
useful:
156+
https://www.twilio.com/blog/asynchronous-http-requests-in-python-with-aiohttp
157+
https://stackoverflow.com/questions/32456881/getting-values-from-functions-that-run-as-asyncio-tasks
158+
https://docs.python.org/3/library/asyncio-task.html
159+
https://bbc.github.io/cloudfit-public-docs/asyncio/asyncio-part-2.html
160+
https://docs.aiohttp.org/en/stable/client_reference.html
161+
https://docs.aiohttp.org/en/v0.20.0/client.html
162+
163+
info/todo:
164+
-item should only contain pattern_ok or pattern_nok, not both of them
165+
-todo: check out if ascyncio request is with or without redirects - we can set parameter
166+
-todo: add allow_redirects parameter - done
167+
-default requests user_agent: requests.utils.default_headers()
168+
-TikTok warning, while using custom user-agent: Can not load response cookies: Illegal key 'httponly,msToken'
169+
-https://user-agents.net/
170+
-import webbrowser; webbrowser.open(url)
171+
-data visualization possibilites:
172+
-tkinter gui
173+
-html file & browser view
174+
-jupyter -> qgrid
175+
-plotly -> table
176+
-todo: make some options
177+
-todo: get supported domains - get from json
178+
-todo: set domains - pass as argument to check function
179+
180+
errors:
181+
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'XXXXXXX_XXXXXXX.contently.com'. (_ssl.c:1129)
182+
aiohttp.client_exceptions.ClientConnectorCertificateError: Cannot connect to host XXXXXXX_XXXXXXX.contently.com:443 ssl:True [SSLCertVerificationError: (1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'XXXXXXX_XXXXXXX.contently.com'. (_ssl.c:1129)")]
183+
https://stackoverflow.com/questions/63347818/aiohttp-client-exceptions-clientconnectorerror-cannot-connect-to-host-stackover
184+
185+
aiohttp.client_exceptions.ClientConnectorError: Cannot connect to host blip.fm:443 ssl:default [The semaphore timeout period has expired]
186+
187+
[x] error catched: Cannot connect to host XXXXXXX_XXXXXXX.tumblr.com:443 ssl:True [SSLCertVerificationError: (1, "[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: Hostname mismatch, certificate is not valid for 'XXXXXXX_XXXXXXX.tumblr.com'. (_ssl.c:1129)")]
188+
occurs when url contains uderscore (_)
189+
"""

namecheck_gui.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
import sys
2+
import os
3+
import time
4+
import random
5+
import webbrowser
6+
from tkinter import (
7+
Tk,
8+
Frame,
9+
Widget,
10+
Label,
11+
Button,
12+
font,
13+
YES,
14+
NO,
15+
TOP,
16+
BOTTOM,
17+
LEFT,
18+
RIGHT,
19+
BOTH,
20+
X,
21+
Y,
22+
)
23+
from pathlib import Path
24+
from termcolor import colored
25+
import namecheck # my package
26+
27+
28+
class NamecheckGUI(Frame):
29+
"""NamecheckGUI
30+
title - username; displayed in top label
31+
data - list of tuples in form -> (key, url, user_exist)
32+
items_in_row - number of labels in row
33+
"""
34+
def __init__(self, master, title, data, items_in_row=5):
35+
super().__init__(master)
36+
self.title = title
37+
self.items_in_row = items_in_row
38+
self.wrapped_data = [data[n:n+self.items_in_row] for n in range(0, len(data), self.items_in_row)]
39+
self.master.protocol("WM_DELETE_WINDOW", self.on_closing)
40+
self.master.geometry("{}x{}".format(650, 500)) # width x height
41+
# self.master.resizable(width=True, height=True)
42+
self.master.wm_title("namecheck")
43+
self.pack()
44+
self.run_gui()
45+
46+
def run_gui(self):
47+
"""create widgets & run gui"""
48+
# *********** title label ***********
49+
self.title_label = Label(self.master, text=self.title, fg="black", bg='white', relief="groove")
50+
self.title_label.pack(expand=NO, fill=BOTH, side=TOP)
51+
52+
# *********** main clickable labels ***********
53+
self.wrapper_frame = Frame(self.master)
54+
self.wrapper_frame.pack(expand=YES, fill=BOTH, side=TOP)
55+
for row_index, row in enumerate(self.wrapped_data):
56+
row_frame = Frame(self.wrapper_frame)
57+
row_frame.pack(expand=YES, fill=BOTH, side=TOP)
58+
for col_index, (key, url, user_exist) in enumerate(row):
59+
color = self.color_mapping(user_exist)
60+
# relief arguments: "flat", "raised", "sunken", "ridge", "solid", "groove"
61+
link_label = Label(row_frame, text=key, fg="blue", bg=color, relief="groove", cursor="hand2")
62+
link_label.pack(expand=YES, fill=BOTH, side=LEFT)
63+
"""
64+
bind events: https://python-course.eu/tkinter/events-and-binds-in-tkinter.php
65+
when using event like <ButtonRelease> or <Button> without specifying button number (1, 2 or 3)
66+
all of the mouse buttons are binded. To specify use <ButtonRelease-1>, <ButtonRelease-2>, and <ButtonRelease-3>
67+
68+
<Double-Button-1> -bind double mouse left button
69+
<ButtonRelease-2> -bind single mouse middle click & release
70+
"""
71+
# link_label.bind("<Button-1>", lambda event, url=url: self.click_callback(url))
72+
link_label.bind("<Double-Button-1>", lambda event, url=url: self.click_callback(url))
73+
link_label.bind("<ButtonRelease-2>", lambda event, url=url: self.click_callback(url))
74+
link_label.bind("<Enter>", lambda event, text=url: self.on_start_hover(text))
75+
link_label.bind("<Leave>", lambda event: self.on_end_hover())
76+
77+
# *********** label with destination url ***********
78+
self.info_label = Label(self.master, text='', fg="black", bg='white', relief="groove")
79+
self.info_label.pack(expand=NO, fill=BOTH, side=TOP)
80+
81+
# *********** lift, get focus ***********
82+
self.master.update()
83+
self.master.attributes("-topmost", True)
84+
self.master.lift() # move window to the top
85+
self.master.focus_force()
86+
return None
87+
88+
def color_mapping(self, flag):
89+
"""labels color mapping
90+
lightgreen: #90EE90
91+
lightgrey: #8E9899
92+
lightred: #F47B7F
93+
https://www.color-name.com/neutral-cyan.color
94+
"""
95+
if flag == True:
96+
color = '#90EE90' # lightgreen
97+
elif flag == False:
98+
color = '#8E9899' # lightgrey
99+
elif flag == None:
100+
color = '#F47B7F' # lightred
101+
else:
102+
color = 'white'
103+
return color
104+
105+
def on_start_hover(self, text):
106+
"""on mouse start hover cell (label)"""
107+
self.info_label.config(text=text)
108+
109+
def on_end_hover(self):
110+
"""on mouse end hover cell (label)"""
111+
self.info_label.config(text='')
112+
113+
def click_callback(self, url):
114+
"""open url in browser"""
115+
webbrowser.open_new(url)
116+
117+
def on_closing(self):
118+
"""handle application closing"""
119+
self.master.destroy()
120+
self.master.quit()
121+
122+
123+
def example_namecheck_response():
124+
"""for debug"""
125+
response_values = [('Website{}'.format(x), random.choice(['https://www.google.com', 'https://www.wykop.pl/']), random.choice([True, False, None])) for x in range(28)]
126+
return response_values
127+
128+
129+
if __name__ == "__main__":
130+
# *********** setup ***********
131+
os.chdir(str(Path(sys.argv[0]).parent))
132+
os.system('color')
133+
start_time = time.time()
134+
135+
# *********** username ***********
136+
args = sys.argv[1:]
137+
if not args:
138+
print('[*] usage:')
139+
print(colored(' python namecheck_gui.py <username>', 'yellow'))
140+
sys.exit()
141+
username = args[0]
142+
print('[*] username: {}'.format(colored(username, 'yellow')))
143+
144+
# *********** collect urls ***********
145+
namecheck_urls = namecheck.read_json('namecheck_urls.json')
146+
# namecheck_urls = namecheck.filter_urls(namecheck_urls, ['Slack', 'Spotify'])
147+
148+
# *********** main ***********
149+
response_values = namecheck.run_main(namecheck_urls, username)
150+
# response_values = example_namecheck_response()
151+
print("\n[*] total time: {} [s]".format(round(time.time() - start_time, 4)))
152+
gui = NamecheckGUI(master=Tk(), title=username, data=response_values)
153+
gui.mainloop()
154+

0 commit comments

Comments
 (0)