user-scanner 1.1.0.1__py3-none-any.whl → 1.1.0.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. user_scanner/.ruff_cache/.gitignore +2 -0
  2. user_scanner/.ruff_cache/0.14.10/12603567674167520802 +0 -0
  3. user_scanner/.ruff_cache/0.14.10/12688104075811904861 +0 -0
  4. user_scanner/.ruff_cache/0.14.10/15694509833576274574 +0 -0
  5. user_scanner/.ruff_cache/0.14.10/301008395129872757 +0 -0
  6. user_scanner/.ruff_cache/0.14.10/4908403194175060721 +0 -0
  7. user_scanner/.ruff_cache/0.14.10/572980360641624523 +0 -0
  8. user_scanner/.ruff_cache/0.14.10/5935143038219898089 +0 -0
  9. user_scanner/.ruff_cache/CACHEDIR.TAG +1 -0
  10. user_scanner/__main__.py +2 -2
  11. user_scanner/config.json +3 -1
  12. user_scanner/core/email_orchestrator.py +17 -17
  13. user_scanner/core/orchestrator.py +6 -3
  14. user_scanner/core/result.py +10 -2
  15. user_scanner/email_scan/adult/sexvid.py +43 -0
  16. user_scanner/email_scan/community/.ruff_cache/.gitignore +2 -0
  17. user_scanner/email_scan/community/.ruff_cache/0.14.10/3933329632096143294 +0 -0
  18. user_scanner/email_scan/community/.ruff_cache/CACHEDIR.TAG +1 -0
  19. user_scanner/email_scan/community/quora.py +112 -0
  20. user_scanner/email_scan/dev/.ruff_cache/.gitignore +2 -0
  21. user_scanner/email_scan/dev/.ruff_cache/0.14.10/10328336453267387919 +0 -0
  22. user_scanner/email_scan/dev/.ruff_cache/CACHEDIR.TAG +1 -0
  23. user_scanner/email_scan/dev/__init__.py +1 -0
  24. user_scanner/email_scan/dev/bitbucket.py +2 -0
  25. user_scanner/email_scan/dev/codecademy.py +49 -0
  26. user_scanner/email_scan/dev/codepen.py +54 -0
  27. user_scanner/email_scan/dev/devrant.py +49 -0
  28. user_scanner/email_scan/dev/github.py +2 -0
  29. user_scanner/email_scan/dev/replit.py +51 -0
  30. user_scanner/email_scan/dev/wordpress.py +52 -0
  31. user_scanner/email_scan/hosting/.ruff_cache/.gitignore +2 -0
  32. user_scanner/email_scan/hosting/.ruff_cache/0.14.10/6358275293999347997 +0 -0
  33. user_scanner/email_scan/hosting/.ruff_cache/CACHEDIR.TAG +1 -0
  34. user_scanner/email_scan/hosting/__init__.py +0 -0
  35. user_scanner/email_scan/hosting/render.py +60 -0
  36. user_scanner/email_scan/music/.ruff_cache/.gitignore +2 -0
  37. user_scanner/email_scan/music/.ruff_cache/0.14.10/14677874048998292530 +0 -0
  38. user_scanner/email_scan/music/.ruff_cache/0.14.10/7544735312652879689 +0 -0
  39. user_scanner/email_scan/music/.ruff_cache/CACHEDIR.TAG +1 -0
  40. user_scanner/email_scan/music/__init__.py +0 -0
  41. user_scanner/email_scan/music/lastfm.py +60 -0
  42. user_scanner/email_scan/music/spotify.py +87 -0
  43. user_scanner/email_scan/shopping/envato.py +41 -0
  44. user_scanner/email_scan/shopping/naturabuy.py +46 -0
  45. user_scanner/email_scan/shopping/vivino.py +49 -0
  46. user_scanner/email_scan/social/mastodon.py +5 -3
  47. user_scanner/user_scan/gaming/battlenet.py +65 -0
  48. user_scanner/user_scan/shopping/__init__.py +0 -0
  49. user_scanner/user_scan/shopping/vinted.py +42 -0
  50. user_scanner/version.json +1 -1
  51. {user_scanner-1.1.0.1.dist-info → user_scanner-1.1.0.3.dist-info}/METADATA +33 -7
  52. {user_scanner-1.1.0.1.dist-info → user_scanner-1.1.0.3.dist-info}/RECORD +55 -15
  53. {user_scanner-1.1.0.1.dist-info → user_scanner-1.1.0.3.dist-info}/WHEEL +0 -0
  54. {user_scanner-1.1.0.1.dist-info → user_scanner-1.1.0.3.dist-info}/entry_points.txt +0 -0
  55. {user_scanner-1.1.0.1.dist-info → user_scanner-1.1.0.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,2 @@
1
+ # Automatically created by ruff.
2
+ *
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
user_scanner/__main__.py CHANGED
@@ -196,7 +196,7 @@ def main():
196
196
  print(f"{R}[✘] Error: No valid emails found in {args.email_file}{X}")
197
197
  sys.exit(1)
198
198
 
199
- print(f"{C}[+] Loaded {len(valid_emails)} emails from {args.email_file}{X}")
199
+ print(f"{C}[+] Loaded {len(valid_emails)} {'email' if len(valid_emails) == 1 else 'emails'} from {args.email_file}{X}")
200
200
  is_email = True
201
201
  targets = valid_emails
202
202
  except FileNotFoundError:
@@ -213,7 +213,7 @@ def main():
213
213
  if not usernames:
214
214
  print(f"{R}[✘] Error: No valid usernames found in {args.username_file}{X}")
215
215
  sys.exit(1)
216
- print(f"{C}[+] Loaded {len(usernames)} usernames from {args.username_file}{X}")
216
+ print(f"{C}[+] Loaded {len(usernames)} {'username' if len(usernames) == 1 else 'usernames'} from {args.username_file}{X}")
217
217
  is_email = False
218
218
  targets = usernames
219
219
  except FileNotFoundError:
user_scanner/config.json CHANGED
@@ -1 +1,3 @@
1
- {"auto_update_status": true}
1
+ {
2
+ "auto_update_status": true
3
+ }
@@ -1,10 +1,11 @@
1
1
  import asyncio
2
2
  from pathlib import Path
3
- from typing import List
4
3
  from types import ModuleType
4
+ from typing import List
5
+
5
6
  from colorama import Fore, Style
6
7
 
7
- from user_scanner.core.helpers import load_categories, load_modules, find_category
8
+ from user_scanner.core.helpers import find_category, load_categories, load_modules
8
9
  from user_scanner.core.result import Result
9
10
 
10
11
  # Concurrency control
@@ -13,11 +14,21 @@ MAX_CONCURRENT_REQUESTS = 15
13
14
 
14
15
  async def _async_worker(module: ModuleType, email: str, sem: asyncio.Semaphore) -> Result:
15
16
  async with sem:
16
- module_name = module.__name__.split('.')[-1]
17
+ module_name = module.__name__.split(".")[-1]
17
18
  func_name = f"validate_{module_name}"
19
+ actual_cat = find_category(module) or "Email"
20
+
21
+ params = {
22
+ "site_name": module_name.capitalize(),
23
+ "username": email,
24
+ "category": actual_cat,
25
+ "is_email": True,
26
+ }
18
27
 
19
28
  if not hasattr(module, func_name):
20
- return Result.error(f"Function {func_name} not found")
29
+ return (
30
+ Result.error(f"Function {func_name} not found").update(**params).show()
31
+ )
21
32
 
22
33
  func = getattr(module, func_name)
23
34
 
@@ -27,21 +38,10 @@ async def _async_worker(module: ModuleType, email: str, sem: asyncio.Semaphore)
27
38
  except Exception as e:
28
39
  result = Result.error(e)
29
40
 
30
- # Use helper to get actual dir name for the Result object
31
- actual_cat = find_category(module) or "Email"
32
-
33
- result.update(
34
- site_name=module_name.capitalize(),
35
- username=email,
36
- category=actual_cat,
37
- is_email=True
38
- )
39
-
40
- print(result.get_console_output())
41
- return result
41
+ return result.update(**params).show()
42
42
 
43
43
 
44
- async def _run_batch(modules: List[ModuleType], email:str) -> List[Result]:
44
+ async def _run_batch(modules: List[ModuleType], email: str) -> List[Result]:
45
45
  sem = asyncio.Semaphore(MAX_CONCURRENT_REQUESTS)
46
46
  tasks = []
47
47
  for module in modules:
@@ -15,7 +15,11 @@ def _worker_single(module: ModuleType, username: str) -> Result:
15
15
  site_name = get_site_name(module)
16
16
 
17
17
  if not func:
18
- return Result.error(f"{site_name} has no validate_ function", site_name=site_name, username=username)
18
+ return Result.error(
19
+ f"{site_name} has no validate_ function",
20
+ site_name=site_name,
21
+ username=username,
22
+ )
19
23
 
20
24
  try:
21
25
  result: Result = func(username)
@@ -48,8 +52,7 @@ def run_user_category(category_path: Path, username: str) -> List[Result]:
48
52
  for result in exec_map:
49
53
  result.update(category=category_name)
50
54
  results.append(result)
51
-
52
- print(result.get_console_output())
55
+ result.show()
53
56
 
54
57
  return results
55
58
 
@@ -61,6 +61,7 @@ class Result:
61
61
  for field in ("username", "site_name", "category", "is_email"):
62
62
  if field in kwargs and kwargs[field] is not None:
63
63
  setattr(self, field, kwargs[field])
64
+ return self
64
65
 
65
66
  @classmethod
66
67
  def taken(cls, reason: str | Exception | None = None, **kwargs):
@@ -148,11 +149,18 @@ class Result:
148
149
 
149
150
  def get_console_output(self) -> str:
150
151
  site_name = self.site_name
151
- username = self.username
152
152
  status_text = self.status.to_label(self.is_email)
153
+ username = ""
154
+ if self.username:
155
+ username = f"({self.username})"
153
156
 
154
157
  color = self.get_output_color()
155
158
  icon = self.get_output_icon()
156
159
 
157
160
  reason = f" ({self.get_reason()})" if self.has_reason() else ""
158
- return f" {color}{icon} {site_name} ({username}): {status_text}{reason}{Style.RESET_ALL}"
161
+ return f" {color}{icon} {site_name} {username}: {status_text}{reason}{Style.RESET_ALL}"
162
+
163
+ def show(self):
164
+ """Prints the console output and returns itself for chaining"""
165
+ print(self.get_console_output())
166
+ return self
@@ -0,0 +1,43 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+ async def _check(email: str) -> Result:
5
+ url = "https://www.sexvid.pro/reset-password/"
6
+
7
+ payload = {
8
+ 'action': "restore_password",
9
+ 'mode': "async",
10
+ 'format': "json",
11
+ 'email_link': "https://www.sexvid.pro/signup.php",
12
+ 'email': email,
13
+ 'code': "xxxxx"
14
+ }
15
+
16
+ headers = {
17
+ 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36",
18
+ 'Accept': "*/*",
19
+ 'X-Requested-With': "XMLHttpRequest",
20
+ 'Origin': "https://www.sexvid.pro",
21
+ 'Referer': "https://www.sexvid.pro/reset-password/",
22
+ 'Content-Type': "application/x-www-form-urlencoded"
23
+ }
24
+
25
+ async with httpx.AsyncClient(http2=False, timeout=5.0) as client:
26
+ try:
27
+ response = await client.post(url, data=payload, headers=headers)
28
+ res_text = response.text
29
+
30
+ if "doesnt_exist" in res_text or "No user with such email exists" in res_text:
31
+ return Result.available()
32
+ elif "A new generated password has been sent" in res_text or "status\":\"success" in res_text:
33
+ return Result.taken()
34
+ elif response.status_code == 429:
35
+ return Result.error("Rate-limited")
36
+ else:
37
+ return Result.error(f"[{response.status_code}] Unexpected response body, report it via GitHub issues")
38
+
39
+ except Exception as e:
40
+ return Result.error(e)
41
+
42
+ async def validate_sexvid(email: str) -> Result:
43
+ return await _check(email)
@@ -0,0 +1,2 @@
1
+ # Automatically created by ruff.
2
+ *
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
@@ -0,0 +1,112 @@
1
+ import asyncio
2
+ import json
3
+ import re
4
+ import os
5
+ import shutil
6
+ from user_scanner.core.result import Result
7
+
8
+
9
+ async def _check(email: str) -> Result:
10
+ if not shutil.which("curl"):
11
+ return Result.error("curl is not installed, install it to use Quora validation")
12
+
13
+ cookie_path = f"quora_cookie_{os.getpid()}.txt"
14
+ base_url = "https://www.quora.com/"
15
+ gql_url = "https://www.quora.com/graphql/gql_para_POST"
16
+
17
+ headers = {
18
+ 'host': 'www.quora.com',
19
+ 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
20
+ 'sec-ch-ua-mobile': '?1',
21
+ 'sec-ch-ua-platform': '"Android"',
22
+ 'upgrade-insecure-requests': '1',
23
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36',
24
+ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8',
25
+ 'referer': 'https://www.google.com/',
26
+ 'accept-language': 'en-US,en;q=0.9',
27
+ }
28
+
29
+ async def run_curl(url, current_headers, post_data=None, url_params=None):
30
+ cmd = ["curl", "-s", "-k", "-L", "--http2", "--max-time",
31
+ "5", "-c", cookie_path, "-b", cookie_path]
32
+ for k, v in current_headers.items():
33
+ cmd.extend(["-H", f"{k}: {v}"])
34
+ if url_params:
35
+ import urllib.parse
36
+ url += "?" + urllib.parse.urlencode(url_params)
37
+ if post_data:
38
+ cmd.extend(["-X", "POST", "--data-raw", json.dumps(post_data)])
39
+ cmd.append(url)
40
+
41
+ process = await asyncio.create_subprocess_exec(
42
+ *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE
43
+ )
44
+ try:
45
+ stdout, _ = await asyncio.wait_for(process.communicate(), timeout=5)
46
+ return stdout.decode('utf-8', errors='ignore')
47
+ except asyncio.TimeoutError:
48
+ try:
49
+ process.kill()
50
+ except Exception:
51
+ pass
52
+ return ""
53
+
54
+ try:
55
+ html = await run_curl(base_url, headers)
56
+ if not html:
57
+ if os.path.exists(cookie_path):
58
+ os.remove(cookie_path)
59
+ return Result.error("Connection timed out")
60
+
61
+ formkey_match = re.search(r'\"formkey\":\s*\"([a-f0-9]{32})\"', html)
62
+ if not formkey_match:
63
+ if os.path.exists(cookie_path):
64
+ os.remove(cookie_path)
65
+ return Result.error("Quora blocked the request (Bot detection/403)")
66
+
67
+ formkey = formkey_match.group(1)
68
+
69
+ gql_headers = headers.copy()
70
+ gql_headers.update({
71
+ 'content-type': 'application/json',
72
+ 'quora-formkey': formkey,
73
+ 'quora-canary-revision': 'false',
74
+ 'origin': 'https://www.quora.com',
75
+ 'referer': 'https://www.quora.com/',
76
+ 'priority': 'u=1, i'
77
+ })
78
+
79
+ payload = {
80
+ "queryName": "SignupEmailForm_validateEmail_Query",
81
+ "variables": {"email": email},
82
+ "extensions": {
83
+ "hash": "1db80096407be846d5581fe1b42b12fd05e0b40a5d3095ed40a0b4bd28f49fe7"
84
+ }
85
+ }
86
+
87
+ response_text = await run_curl(gql_url, gql_headers, post_data=payload, url_params={'q': "SignupEmailForm_validateEmail_Query"})
88
+
89
+ if os.path.exists(cookie_path):
90
+ os.remove(cookie_path)
91
+
92
+ if not response_text.strip():
93
+ return Result.error("Quora timed out or returned empty body")
94
+
95
+ data = json.loads(response_text)
96
+ status = data.get("data", {}).get("validateEmail")
97
+
98
+ if status == "IN_USE":
99
+ return Result.taken()
100
+ elif status == "OK":
101
+ return Result.available()
102
+ else:
103
+ return Result.error(f"Unexpected status: {status}")
104
+
105
+ except Exception as e:
106
+ if os.path.exists(cookie_path):
107
+ os.remove(cookie_path)
108
+ return Result.error(e)
109
+
110
+
111
+ async def validate_quora(email: str) -> Result:
112
+ return await _check(email)
@@ -0,0 +1,2 @@
1
+ # Automatically created by ruff.
2
+ *
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
@@ -0,0 +1 @@
1
+
@@ -1,6 +1,7 @@
1
1
  import httpx
2
2
  from user_scanner.core.result import Result
3
3
 
4
+
4
5
  async def _check(email: str) -> Result:
5
6
  async with httpx.AsyncClient(http2=True) as client:
6
7
  try:
@@ -29,5 +30,6 @@ async def _check(email: str) -> Result:
29
30
  except Exception as e:
30
31
  return Result.error(f"Unexpected exception:{e}")
31
32
 
33
+
32
34
  async def validate_bitbucket(email: str) -> Result:
33
35
  return await _check(email)
@@ -0,0 +1,49 @@
1
+ import httpx
2
+ import re
3
+ from user_scanner.core.result import Result
4
+
5
+
6
+ async def _check(email: str) -> Result:
7
+ headers = {
8
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
9
+ 'Accept': 'application/json',
10
+ 'Accept-Language': 'en-US,en;q=0.9',
11
+ 'Referer': 'https://www.codecademy.com/register?redirect=%2F',
12
+ 'Content-Type': 'application/json',
13
+ 'Origin': 'https://www.codecademy.com',
14
+ }
15
+
16
+ try:
17
+ async with httpx.AsyncClient(timeout=4.0, follow_redirects=True) as client:
18
+ init_res = await client.get("https://www.codecademy.com/register", headers=headers)
19
+
20
+ csrf_match = re.search(
21
+ r'name="csrf-token" content="([^"]+)"', init_res.text)
22
+ if not csrf_match:
23
+ return Result.error("Could not find CSRF token")
24
+
25
+ headers["X-CSRF-Token"] = csrf_match.group(1)
26
+
27
+ payload = {"user": {"email": email}}
28
+
29
+ response = await client.post(
30
+ 'https://www.codecademy.com/register/validate',
31
+ headers=headers,
32
+ json=payload
33
+ )
34
+
35
+ if response.status_code == 400 and 'has already been taken' in response.text:
36
+ return Result.taken()
37
+ elif response.status_code == 200:
38
+ return Result.available()
39
+
40
+ return Result.error(f"Unexpected response: {response.status_code}")
41
+
42
+ except httpx.TimeoutException:
43
+ return Result.error("Connection timed out")
44
+ except Exception as e:
45
+ return Result.error(str(e))
46
+
47
+
48
+ async def validate_codecademy(email: str) -> Result:
49
+ return await _check(email)
@@ -0,0 +1,54 @@
1
+ import httpx
2
+ import re
3
+ from user_scanner.core.result import Result
4
+
5
+
6
+ async def _check(email: str) -> Result:
7
+ headers = {
8
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
9
+ 'Accept': '*/*',
10
+ 'Accept-Language': 'en-US,en;q=0.9',
11
+ 'Referer': 'https://codepen.io/accounts/signup/user/free',
12
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
13
+ 'X-Requested-With': 'XMLHttpRequest',
14
+ 'Origin': 'https://codepen.io',
15
+ }
16
+
17
+ try:
18
+ async with httpx.AsyncClient(timeout=10.0, follow_redirects=True) as client:
19
+ init_res = await client.get("https://codepen.io/accounts/signup/user/free", headers=headers)
20
+
21
+ csrf_match = re.search(
22
+ r'name="csrf-token" content="([^"]+)"', init_res.text)
23
+ if not csrf_match:
24
+ return Result.error("Could not find CSRF token")
25
+
26
+ headers["X-CSRF-Token"] = csrf_match.group(1)
27
+
28
+ payload = {
29
+ 'attribute': 'email',
30
+ 'value': email,
31
+ 'context': 'user'
32
+ }
33
+
34
+ response = await client.post(
35
+ 'https://codepen.io/accounts/duplicate_check',
36
+ headers=headers,
37
+ data=payload
38
+ )
39
+
40
+ if "That Email is already taken." in response.text:
41
+ return Result.taken()
42
+ elif response.status_code == 200:
43
+ return Result.available()
44
+
45
+ return Result.error(f"Unexpected response: {response.status_code}")
46
+
47
+ except httpx.TimeoutException:
48
+ return Result.error("Connection timed out")
49
+ except Exception as e:
50
+ return Result.error(str(e))
51
+
52
+
53
+ async def validate_codepen(email: str) -> Result:
54
+ return await _check(email)
@@ -0,0 +1,49 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+
5
+ async def _check(email: str) -> Result:
6
+ headers = {
7
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
8
+ 'Accept': 'application/json, text/javascript, */*; q=0.01',
9
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
10
+ 'X-Requested-With': 'XMLHttpRequest',
11
+ 'Origin': 'https://devrant.com',
12
+ 'Referer': 'https://devrant.com/feed/top/month?login=1',
13
+ }
14
+
15
+ payload = {
16
+ 'app': '3',
17
+ 'type': '1',
18
+ 'email': email,
19
+ 'username': '',
20
+ 'password': '',
21
+ 'guid': '',
22
+ 'plat': '3',
23
+ 'sid': '',
24
+ 'seid': ''
25
+ }
26
+
27
+ try:
28
+ async with httpx.AsyncClient(timeout=10.0) as client:
29
+ response = await client.post('https://devrant.com/api/users', headers=headers, data=payload)
30
+
31
+ if response.status_code != 200:
32
+ return Result.error(f"Unexpected status code: {response.status_code}")
33
+
34
+ data = response.json()
35
+ error_msg = data.get('error', '')
36
+
37
+ if error_msg == 'The email specified is already registered to an account.':
38
+ return Result.taken()
39
+
40
+ return Result.available()
41
+
42
+ except httpx.TimeoutException:
43
+ return Result.error("Connection timed out")
44
+ except Exception as e:
45
+ return Result.error(str(e))
46
+
47
+
48
+ async def validate_devrant(email: str) -> Result:
49
+ return await _check(email)
@@ -2,6 +2,7 @@ import httpx
2
2
  import re
3
3
  from user_scanner.core.result import Result
4
4
 
5
+
5
6
  async def _check(email: str) -> Result:
6
7
  async with httpx.AsyncClient(http2=True, follow_redirects=True) as client:
7
8
  try:
@@ -68,5 +69,6 @@ async def _check(email: str) -> Result:
68
69
  except Exception as e:
69
70
  return Result.error(f"unexpected exception: {e}")
70
71
 
72
+
71
73
  async def validate_github(email: str) -> Result:
72
74
  return await _check(email)
@@ -0,0 +1,51 @@
1
+ import httpx
2
+ import json
3
+ from user_scanner.core.result import Result
4
+
5
+ async def _check(email: str) -> Result:
6
+ url = "https://replit.com/data/user/exists"
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/144.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=\"8\", \"Chromium\";v=\"144\", \"Google Chrome\";v=\"144\"",
19
+ 'sec-ch-ua-mobile': "?1",
20
+ 'x-requested-with': "XMLHttpRequest",
21
+ 'origin': "https://replit.com",
22
+ 'sec-fetch-site': "same-origin",
23
+ 'sec-fetch-mode': "cors",
24
+ 'sec-fetch-dest': "empty",
25
+ 'referer': "https://replit.com/signup",
26
+ 'accept-language': "en-US,en;q=0.9",
27
+ 'priority': "u=1, i"
28
+ }
29
+
30
+ async with httpx.AsyncClient(http2=False, timeout=5.0) as client:
31
+ try:
32
+ response = await client.post(url, content=json.dumps(payload), headers=headers)
33
+
34
+ if response.status_code == 403:
35
+ return Result.error("403 Forbidden")
36
+
37
+ data = response.json()
38
+ exists = data.get("exists")
39
+
40
+ if exists is True:
41
+ return Result.taken()
42
+ if exists is False:
43
+ return Result.available()
44
+
45
+ return Result.error("Unexpected response format")
46
+
47
+ except Exception as e:
48
+ return Result.error(str(e))
49
+
50
+ async def validate_replit(email: str) -> Result:
51
+ return await _check(email)
@@ -0,0 +1,52 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+
5
+ async def _check(email: str) -> Result:
6
+ url = f"https://public-api.wordpress.com/rest/v1.1/users/{email}/auth-options"
7
+
8
+ params = {
9
+ 'http_envelope': "1"
10
+ }
11
+
12
+ headers = {
13
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
14
+ 'Accept': "application/json",
15
+ 'sec-ch-ua-platform': '"Linux"',
16
+ 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
17
+ 'sec-ch-ua-mobile': "?0",
18
+ 'sec-fetch-site': "same-origin",
19
+ 'sec-fetch-mode': "cors",
20
+ 'sec-fetch-dest': "empty",
21
+ 'referer': "https://public-api.wordpress.com/wp-admin/rest-proxy/?v=2.0",
22
+ 'accept-language': "en-US,en;q=0.9",
23
+ }
24
+
25
+ try:
26
+ async with httpx.AsyncClient(timeout=5.0) as client:
27
+ response = await client.get(url, params=params, headers=headers)
28
+
29
+ if response.status_code != 200:
30
+ return Result.error(f"WordPress API returned status {response.status_code}")
31
+
32
+ data = response.json()
33
+
34
+ inner_code = data.get("code")
35
+ body = data.get("body", {})
36
+
37
+ if inner_code == 200:
38
+ return Result.taken()
39
+ elif inner_code == 404 and body.get("error") == "unknown_user":
40
+ return Result.available()
41
+ else:
42
+ error_msg = body.get("message", "Unknown API response")
43
+ return Result.error(f"WordPress Error: {error_msg}")
44
+
45
+ except httpx.TimeoutException:
46
+ return Result.error("Connection timed out")
47
+ except Exception as e:
48
+ return Result.error(str(e))
49
+
50
+
51
+ async def validate_wordpress(email: str) -> Result:
52
+ return await _check(email)
@@ -0,0 +1,2 @@
1
+ # Automatically created by ruff.
2
+ *
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
File without changes