Skip to content

Commit a061d86

Browse files
authored
Merge pull request #224 from kaifcodec/add/email-osint-modules
add: 5 new email_scan modules
2 parents a937667 + 5fcfc72 commit a061d86

5 files changed

Lines changed: 343 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import httpx
2+
import json
3+
import urllib.parse
4+
from user_scanner.core.result import Result
5+
6+
7+
async def _check(email: str) -> Result:
8+
show_url = "https://hackthebox.com"
9+
register_url = "https://account.hackthebox.com/register"
10+
api_url = "https://account.hackthebox.com/api/v1/user/email/verify"
11+
12+
headers = {
13+
'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Mobile Safari/537.36",
14+
'Accept': "application/json",
15+
'Accept-Encoding': "identity",
16+
'Content-Type': "application/json",
17+
'sec-ch-ua-platform': '"Android"',
18+
'sec-ch-ua': '"Not:A-Brand";v="99\", \"Google Chrome\";v=\"145\", \"Chromium\";v=\"145"',
19+
'sec-ch-ua-mobile': "?1",
20+
'x-requested-with': "XMLHttpRequest",
21+
'origin': "https://account.hackthebox.com",
22+
'sec-fetch-site': "same-origin",
23+
'sec-fetch-mode': "cors",
24+
'sec-fetch-dest': "empty",
25+
'referer': "https://account.hackthebox.com/register",
26+
'accept-language': "en-US,en;q=0.9",
27+
'priority': "u=1, i"
28+
}
29+
30+
try:
31+
async with httpx.AsyncClient(timeout=15.0, follow_redirects=True) as client:
32+
r_init = await client.get(register_url, headers={'User-Agent': headers['User-Agent']})
33+
34+
if r_init.status_code == 403:
35+
return Result.error("Caught by WAF or IP Block (403) during Handshake")
36+
37+
xsrf_token_encoded = client.cookies.get("XSRF-TOKEN")
38+
if not xsrf_token_encoded:
39+
return Result.error("Failed to extract XSRF-TOKEN from HackTheBox")
40+
41+
xsrf_token = urllib.parse.unquote(xsrf_token_encoded)
42+
headers['x-xsrf-token'] = xsrf_token
43+
44+
payload = {"email": email}
45+
response = await client.post(api_url, content=json.dumps(payload), headers=headers)
46+
47+
status = response.status_code
48+
49+
if status == 403:
50+
return Result.error("Caught by WAF or IP Block (403) during Validation")
51+
52+
if status == 422:
53+
resp_data = response.json()
54+
if "cannot use this email address" in str(resp_data):
55+
return Result.taken(url=show_url)
56+
return Result.error(f"Validation error: {resp_data.get('message')}")
57+
58+
if status in [200, 204]:
59+
return Result.available(url=show_url)
60+
61+
if status == 429:
62+
return Result.error("Rate limited by HackTheBox")
63+
64+
return Result.error(f"Unexpected status code: {status}")
65+
66+
except httpx.ConnectTimeout:
67+
return Result.error("Connection timed out! maybe region blocks")
68+
except Exception as e:
69+
return Result.error(e)
70+
71+
72+
async def validate_hackthebox(email: str) -> Result:
73+
return await _check(email)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import httpx
2+
import json
3+
from user_scanner.core.result import Result
4+
5+
async def _check(email: str) -> Result:
6+
show_url = "https://anilist.co"
7+
url = "https://anilist.co/graphql"
8+
9+
payload = {
10+
"query": "mutation($email:String){ResetPassword(email:$email)}",
11+
"variables": {
12+
"email": email
13+
}
14+
}
15+
16+
headers = {
17+
'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36",
18+
'Accept': "application/json",
19+
'Content-Type': "application/json",
20+
'schema': "internal",
21+
'origin': "https://anilist.co",
22+
'referer': "https://anilist.co/forgot-password",
23+
'accept-language': "en-US,en;q=0.9"
24+
}
25+
26+
try:
27+
async with httpx.AsyncClient(timeout=7.0) as client:
28+
response = await client.post(url, content=json.dumps(payload), headers=headers)
29+
30+
if response.status_code == 429:
31+
return Result.error("Rate limited wait for few minutes")
32+
33+
data = response.json()
34+
errors = data.get("errors", [])
35+
36+
if not errors:
37+
return Result.error("Unexpected response body structure (No errors returned)")
38+
39+
error_msg = errors[0].get("message", "").lower()
40+
41+
if "unauthorized" in error_msg:
42+
return Result.taken(url=show_url)
43+
44+
elif "validation" in error_msg:
45+
validation = errors[0].get("validation", {})
46+
email_errors = validation.get("email", [])
47+
if any("invalid" in e.lower() for e in email_errors):
48+
return Result.available(url=show_url)
49+
50+
return Result.error("Unexpected validation error message")
51+
52+
else:
53+
return Result.error(f"Unexpected error type: {error_msg}, report it via GitHub issues")
54+
55+
except httpx.ConnectTimeout:
56+
return Result.error("Connection timed out! maybe region blocks")
57+
except httpx.ReadTimeout:
58+
return Result.error("Server took too long to respond (Read Timeout)")
59+
except Exception as e:
60+
return Result.error(e)
61+
62+
async def validate_anilist(email: str) -> Result:
63+
return await _check(email)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import httpx
2+
from user_scanner.core.result import Result
3+
4+
async def _check(email: str) -> Result:
5+
show_url = "https://myanimelist.net"
6+
url = "https://myanimelist.net/signup/email/validate"
7+
8+
payload = {
9+
'email': email
10+
}
11+
12+
headers = {
13+
'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Mobile Safari/537.36",
14+
'Accept': "application/json, text/plain, */*",
15+
'Accept-Encoding': "identity",
16+
'sec-ch-ua-platform': '"Android"',
17+
'x-requested-with': "XMLHttpRequest",
18+
'origin': "https://myanimelist.net",
19+
'sec-fetch-site': "same-origin",
20+
'sec-fetch-mode': "cors",
21+
'sec-fetch-dest': "empty",
22+
'referer': "https://myanimelist.net/register.php?",
23+
'accept-language': "en-US,en;q=0.9",
24+
'priority': "u=1, i"
25+
}
26+
27+
try:
28+
async with httpx.AsyncClient(timeout=7.0) as client:
29+
response = await client.post(url, data=payload, headers=headers)
30+
31+
if response.status_code == 403:
32+
return Result.error("Caught by WAF or IP Block (403)")
33+
34+
if response.status_code == 429:
35+
return Result.error("Rate limited wait for few minutes")
36+
37+
if response.status_code != 200:
38+
return Result.error(f"HTTP Error: {response.status_code}")
39+
40+
data = response.json()
41+
errors = data.get("errors", [])
42+
resp_data = data.get("data")
43+
44+
if errors and any("already have an account" in err.get("message", "") for err in errors):
45+
return Result.taken(url=show_url)
46+
47+
elif isinstance(resp_data, list) and len(resp_data) == 0:
48+
return Result.available(url=show_url)
49+
50+
else:
51+
return Result.error("Unexpected response body structure, report it via GitHub issues")
52+
53+
except httpx.ConnectTimeout:
54+
return Result.error("Connection timed out! maybe region blocks")
55+
except httpx.ReadTimeout:
56+
return Result.error("Server took too long to respond (Read Timeout)")
57+
except Exception as e:
58+
return Result.error(e)
59+
60+
async def validate_myanimelist(email: str) -> Result:
61+
return await _check(email)
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import httpx
2+
from user_scanner.core.result import Result
3+
4+
5+
async def _check(email: str) -> Result:
6+
show_url = "https://neocities.org"
7+
url = "https://neocities.org/create_validate"
8+
9+
payload = {
10+
'field': "email",
11+
'value': email,
12+
'is_education': "false"
13+
}
14+
15+
headers = {
16+
'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Mobile Safari/537.36",
17+
'Accept': "application/json, text/plain, */*",
18+
'Accept-Encoding': "identity",
19+
'sec-ch-ua-platform': '"Android"',
20+
'x-requested-with': "XMLHttpRequest",
21+
'origin': "https://neocities.org",
22+
'referer': "https://neocities.org/",
23+
'accept-language': "en-US,en;q=0.9"
24+
}
25+
26+
try:
27+
async with httpx.AsyncClient(timeout=10.0) as client:
28+
response = await client.post(url, data=payload, headers=headers)
29+
30+
if response.status_code == 403:
31+
return Result.error("Caught by WAF or IP Block (403)")
32+
33+
if response.status_code == 429:
34+
return Result.error("Rate limited wait for few minutes")
35+
36+
if response.status_code != 200:
37+
return Result.error(f"HTTP Error: {response.status_code}")
38+
39+
data = response.json()
40+
41+
if "error" in data:
42+
if "already exists" in data["error"]:
43+
return Result.taken(url=show_url)
44+
return Result.error(f"Neocities error: {data['error']}")
45+
46+
if data.get("result") == "ok":
47+
return Result.available(url=show_url)
48+
49+
return Result.error("Unexpected response body structure, report it via GitHub issues")
50+
51+
except httpx.ConnectTimeout:
52+
return Result.error("Connection timed out! maybe region blocks")
53+
except Exception as e:
54+
return Result.error(e)
55+
56+
57+
async def validate_neocities(email: str) -> Result:
58+
return await _check(email)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import httpx
2+
import json
3+
from user_scanner.core.result import Result
4+
5+
6+
async def _check(email: str) -> Result:
7+
show_url = "https://www.deezer.com"
8+
gw_url = "https://www.deezer.com/ajax/gw-light.php"
9+
10+
headers = {
11+
'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Mobile Safari/537.36",
12+
'Accept-Encoding': "identity",
13+
'Content-Type': "text/plain;charset=UTF-8",
14+
'Origin': "https://account.deezer.com",
15+
'Referer': "https://account.deezer.com/"
16+
}
17+
18+
try:
19+
async with httpx.AsyncClient(timeout=10.0, follow_redirects=True) as client:
20+
handshake_params = {
21+
'method': "deezer.getUserData",
22+
'input': "3",
23+
'api_version': "1.0",
24+
'api_token': ""
25+
}
26+
handshake_payload = {"APP_NAME": "Deezer"}
27+
28+
r_handshake = await client.post(
29+
gw_url,
30+
params=handshake_params,
31+
content=json.dumps(handshake_payload),
32+
headers=headers
33+
)
34+
35+
if r_handshake.status_code == 403:
36+
return Result.error("Caught by WAF or IP Block (403) during Handshake")
37+
38+
handshake_data = r_handshake.json()
39+
api_token = handshake_data.get("results", {}).get("checkForm")
40+
41+
if not api_token:
42+
return Result.error("Failed to retrieve api_token (checkForm) from Deezer")
43+
44+
validate_params = {
45+
'method': "user_checkRegisterConstraints",
46+
'input': "3",
47+
'api_version': "1.0",
48+
'api_token': api_token
49+
}
50+
51+
validate_payload = {
52+
"APP_NAME": "Deezer",
53+
"EMAIL": email
54+
}
55+
56+
response = await client.post(
57+
gw_url,
58+
params=validate_params,
59+
content=json.dumps(validate_payload),
60+
headers=headers
61+
)
62+
63+
if response.status_code == 403:
64+
return Result.error("Caught by WAF or IP Block (403) during Validation")
65+
66+
if response.status_code != 200:
67+
return Result.error(f"HTTP Error: {response.status_code}")
68+
69+
data = response.json()
70+
errors = data.get("results", {}).get("errors", {})
71+
72+
if errors.get("email", {}).get("error") == "email_already_used":
73+
return Result.taken(url=show_url)
74+
75+
elif "country" in errors and "email" not in errors:
76+
return Result.available(url=show_url)
77+
78+
else:
79+
return Result.error("Unexpected response body structure, report it via GitHub issues")
80+
81+
except httpx.ConnectTimeout:
82+
return Result.error("Connection timed out! maybe region blocks")
83+
except Exception as e:
84+
return Result.error(e)
85+
86+
87+
async def validate_deezer(email: str) -> Result:
88+
return await _check(email)

0 commit comments

Comments
 (0)