user-scanner 1.0.10.2__py3-none-any.whl → 1.1.0__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 (90) hide show
  1. user_scanner/__main__.py +241 -129
  2. user_scanner/core/email_orchestrator.py +78 -0
  3. user_scanner/core/formatter.py +27 -0
  4. user_scanner/core/helpers.py +194 -2
  5. user_scanner/core/orchestrator.py +24 -112
  6. user_scanner/core/result.py +38 -13
  7. user_scanner/email_scan/adult/pornhub.py +62 -0
  8. user_scanner/email_scan/adult/xnxx.py +46 -0
  9. user_scanner/email_scan/adult/xvideos.py +50 -0
  10. user_scanner/email_scan/dev/.ruff_cache/.gitignore +2 -0
  11. user_scanner/email_scan/dev/.ruff_cache/0.14.10/10328336453267387919 +0 -0
  12. user_scanner/email_scan/dev/.ruff_cache/CACHEDIR.TAG +1 -0
  13. user_scanner/email_scan/dev/bitbucket.py +33 -0
  14. user_scanner/email_scan/dev/github.py +72 -0
  15. user_scanner/email_scan/dev/huggingface.py +37 -0
  16. user_scanner/email_scan/shopping/__init__.py +0 -0
  17. user_scanner/email_scan/shopping/ebay.py.lock +97 -0
  18. user_scanner/email_scan/shopping/flipkart.py +52 -0
  19. user_scanner/email_scan/social/__init__.py +0 -0
  20. user_scanner/email_scan/social/facebook.py +96 -0
  21. user_scanner/email_scan/social/instagram.py +48 -0
  22. user_scanner/email_scan/social/mastodon.py +57 -0
  23. user_scanner/email_scan/social/x.py +41 -0
  24. user_scanner/user_scan/community/lemmy.py +30 -0
  25. user_scanner/user_scan/creator/__init__.py +0 -0
  26. user_scanner/user_scan/creator/gumroad.py +22 -0
  27. user_scanner/{creator → user_scan/creator}/producthunt.py +13 -4
  28. user_scanner/user_scan/donation/__init__.py +0 -0
  29. user_scanner/user_scan/gaming/__init__.py +0 -0
  30. user_scanner/{gaming → user_scan/gaming}/roblox.py +15 -5
  31. user_scanner/version.json +1 -1
  32. user_scanner-1.1.0.dist-info/METADATA +239 -0
  33. user_scanner-1.1.0.dist-info/RECORD +94 -0
  34. user_scanner/cli/printer.py +0 -117
  35. user_scanner/config.json +0 -1
  36. user_scanner-1.0.10.2.dist-info/METADATA +0 -172
  37. user_scanner-1.0.10.2.dist-info/RECORD +0 -72
  38. /user_scanner/{creator → email_scan}/__init__.py +0 -0
  39. /user_scanner/{donation → email_scan/adult}/__init__.py +0 -0
  40. /user_scanner/{gaming → email_scan/dev}/__init__.py +0 -0
  41. /user_scanner/{community → user_scan/community}/__init__.py +0 -0
  42. /user_scanner/{community → user_scan/community}/coderlegion.py +0 -0
  43. /user_scanner/{community → user_scan/community}/hackernews.py +0 -0
  44. /user_scanner/{community → user_scan/community}/stackoverflow.py +0 -0
  45. /user_scanner/{creator → user_scan/creator}/devto.py +0 -0
  46. /user_scanner/{creator → user_scan/creator}/hashnode.py +0 -0
  47. /user_scanner/{creator → user_scan/creator}/itch_io.py +0 -0
  48. /user_scanner/{creator → user_scan/creator}/kaggle.py +0 -0
  49. /user_scanner/{creator → user_scan/creator}/medium.py +0 -0
  50. /user_scanner/{creator → user_scan/creator}/patreon.py +0 -0
  51. /user_scanner/{creator → user_scan/creator}/substack.py +0 -0
  52. /user_scanner/{creator → user_scan/creator}/twitch.py +0 -0
  53. /user_scanner/{dev → user_scan/dev}/__init__.py +0 -0
  54. /user_scanner/{dev → user_scan/dev}/bitbucket.py +0 -0
  55. /user_scanner/{dev → user_scan/dev}/codeberg.py +0 -0
  56. /user_scanner/{dev → user_scan/dev}/cratesio.py +0 -0
  57. /user_scanner/{dev → user_scan/dev}/dockerhub.py +0 -0
  58. /user_scanner/{dev → user_scan/dev}/github.py +0 -0
  59. /user_scanner/{dev → user_scan/dev}/gitlab.py +0 -0
  60. /user_scanner/{dev → user_scan/dev}/huggingface.py +0 -0
  61. /user_scanner/{dev → user_scan/dev}/launchpad.py +0 -0
  62. /user_scanner/{dev → user_scan/dev}/leetcode.py +0 -0
  63. /user_scanner/{dev → user_scan/dev}/npmjs.py +0 -0
  64. /user_scanner/{dev → user_scan/dev}/replit.py +0 -0
  65. /user_scanner/{dev → user_scan/dev}/sourceforge.py +0 -0
  66. /user_scanner/{donation → user_scan/donation}/buymeacoffee.py +0 -0
  67. /user_scanner/{donation → user_scan/donation}/liberapay.py +0 -0
  68. /user_scanner/{gaming → user_scan/gaming}/chess_com.py +0 -0
  69. /user_scanner/{gaming → user_scan/gaming}/lichess.py +0 -0
  70. /user_scanner/{gaming → user_scan/gaming}/minecraft.py +0 -0
  71. /user_scanner/{gaming → user_scan/gaming}/monkeytype.py +0 -0
  72. /user_scanner/{gaming → user_scan/gaming}/osu.py +0 -0
  73. /user_scanner/{gaming → user_scan/gaming}/steam.py +0 -0
  74. /user_scanner/{social → user_scan/social}/__init__.py +0 -0
  75. /user_scanner/{social → user_scan/social}/bluesky.py +0 -0
  76. /user_scanner/{social → user_scan/social}/discord.py +0 -0
  77. /user_scanner/{social → user_scan/social}/instagram.py +0 -0
  78. /user_scanner/{social → user_scan/social}/mastodon.py +0 -0
  79. /user_scanner/{social → user_scan/social}/pinterest.py +0 -0
  80. /user_scanner/{social → user_scan/social}/reddit.py +0 -0
  81. /user_scanner/{social → user_scan/social}/snapchat.py +0 -0
  82. /user_scanner/{social → user_scan/social}/soundcloud.py +0 -0
  83. /user_scanner/{social → user_scan/social}/telegram.py +0 -0
  84. /user_scanner/{social → user_scan/social}/threads.py +0 -0
  85. /user_scanner/{social → user_scan/social}/tiktok.py +0 -0
  86. /user_scanner/{social → user_scan/social}/x.py +0 -0
  87. /user_scanner/{social → user_scan/social}/youtube.py +0 -0
  88. {user_scanner-1.0.10.2.dist-info → user_scanner-1.1.0.dist-info}/WHEEL +0 -0
  89. {user_scanner-1.0.10.2.dist-info → user_scanner-1.1.0.dist-info}/entry_points.txt +0 -0
  90. {user_scanner-1.0.10.2.dist-info → user_scanner-1.1.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,33 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+ async def _check(email: str) -> Result:
5
+ async with httpx.AsyncClient(http2=True) as client:
6
+ try:
7
+ url = "https://id.atlassian.com/rest/marketing-consent/config"
8
+ payload = {"email": email}
9
+ headers = {
10
+ 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36",
11
+ 'Content-Type': "application/json",
12
+ 'Origin': "https://id.atlassian.com",
13
+ 'Referer': f"https://id.atlassian.com/login?email={email}"
14
+ }
15
+
16
+ response = await client.post(url, json=payload, headers=headers)
17
+
18
+ if response.status_code != 200:
19
+ return Result.error(f"Status {response.status_code}")
20
+
21
+ data = response.json()
22
+ is_reg = data.get("implicitConsent")
23
+ if is_reg is True:
24
+ return Result.available()
25
+ elif is_reg is False:
26
+ return Result.taken()
27
+ else:
28
+ return Result.error(f"Unexpected error occured [{response.status_code}]")
29
+ except Exception as e:
30
+ return Result.error(f"Unexpected exception:{e}")
31
+
32
+ async def validate_bitbucket(email: str) -> Result:
33
+ return await _check(email)
@@ -0,0 +1,72 @@
1
+ import httpx
2
+ import re
3
+ from user_scanner.core.result import Result
4
+
5
+ async def _check(email: str) -> Result:
6
+ async with httpx.AsyncClient(http2=True, follow_redirects=True) as client:
7
+ try:
8
+ url1 = "https://github.com/signup"
9
+ headers1 = {
10
+ 'host': 'github.com',
11
+ 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
12
+ 'sec-ch-ua-mobile': '?0',
13
+ 'sec-ch-ua-platform': '"Linux"',
14
+ 'upgrade-insecure-requests': '1',
15
+ 'user-agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36',
16
+ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
17
+ 'sec-fetch-site': 'cross-site',
18
+ 'sec-fetch-mode': 'navigate',
19
+ 'sec-fetch-user': '?1',
20
+ 'sec-fetch-dest': 'document',
21
+ 'referer': 'https://www.google.com/',
22
+ 'accept-encoding': 'gzip, deflate, br, zstd',
23
+ 'accept-language': 'en-US,en;q=0.9',
24
+ 'priority': 'u=0, i'
25
+ }
26
+
27
+ res1 = await client.get(url1, headers=headers1)
28
+ html = res1.text
29
+
30
+ csrf_match = re.search(r'data-csrf="true"\s+value="([^"]+)"', html)
31
+
32
+ if not csrf_match:
33
+ return Result.error("Failed to extract GitHub authenticity_token")
34
+
35
+ csrf_token = csrf_match.group(1)
36
+
37
+ url2 = "https://github.com/email_validity_checks"
38
+ payload = {
39
+ 'authenticity_token': csrf_token,
40
+ 'value': email
41
+ }
42
+
43
+ headers2 = {
44
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
45
+ 'Accept-Encoding': "gzip, deflate, br, zstd",
46
+ 'sec-ch-ua-platform': '"Linux"',
47
+ 'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
48
+ 'sec-ch-ua-mobile': "?0",
49
+ 'origin': "https://github.com",
50
+ 'sec-fetch-site': "same-origin",
51
+ 'sec-fetch-mode': "cors",
52
+ 'sec-fetch-dest': "empty",
53
+ 'referer': "https://github.com/signup",
54
+ 'accept-language': "en-US,en;q=0.9",
55
+ 'priority': "u=1, i"
56
+ }
57
+
58
+ response = await client.post(url2, data=payload, headers=headers2)
59
+ body = response.text
60
+
61
+ if "already associated with an account" in body:
62
+ return Result.taken()
63
+ elif response.status_code == 200 and "Email is available" in body:
64
+ return Result.available()
65
+ else:
66
+ return Result.error(f"Unexpected status code: {response.status_code}, report this via GitHub issues")
67
+
68
+ except Exception as e:
69
+ return Result.error(f"unexpected exception: {e}")
70
+
71
+ async def validate_github(email: str) -> Result:
72
+ return await _check(email)
@@ -0,0 +1,37 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+
5
+ async def _check(email: str) -> Result:
6
+ url = "https://huggingface.co/api/check-user-email"
7
+ params = {'email': email}
8
+ headers = {
9
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
10
+ 'Accept-Encoding': "identity",
11
+ 'referer': "https://huggingface.co/join",
12
+ 'priority': "u=1, i"
13
+ }
14
+
15
+ async with httpx.AsyncClient(http2=True) as client:
16
+ try:
17
+ response = await client.get(url, params=params, headers=headers, timeout=5)
18
+
19
+ if response.status_code == 429:
20
+ return Result.error("Rate limited wait for few minutes")
21
+
22
+ if response.status_code == 400:
23
+ data = response.json()
24
+ if "already exists" in data.get("error", ""):
25
+ return Result.taken()
26
+
27
+ if response.status_code == 200:
28
+ return Result.available()
29
+
30
+ return Result.error(f"HTTP Error: {response.status_code}")
31
+
32
+ except Exception as e:
33
+ return Result.error(e)
34
+
35
+
36
+ async def validate_huggingface(email: str) -> Result:
37
+ return await _check(email)
File without changes
@@ -0,0 +1,97 @@
1
+ import httpx
2
+ import re
3
+ import asyncio
4
+ from user_scanner.core.result import Result
5
+
6
+ async def _check(email: str) -> Result:
7
+ async with httpx.AsyncClient(http2=True, follow_redirects=False) as client:
8
+ try:
9
+ # --- Step 1: GET landing page ---
10
+ url1 = "https://signin.ebay.com/signin/"
11
+ headers1 = {
12
+ 'host': 'signin.ebay.com',
13
+ 'sec-ch-ua': '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
14
+ 'sec-ch-ua-mobile': '?1',
15
+ 'sec-ch-ua-platform': '"Android"',
16
+ 'upgrade-insecure-requests': '1',
17
+ 'user-agent': 'Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36',
18
+ 'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
19
+ 'sec-fetch-site': 'cross-site',
20
+ 'sec-fetch-mode': 'navigate',
21
+ 'sec-fetch-user': '?1',
22
+ 'sec-fetch-dest': 'document',
23
+ 'referer': 'https://www.google.com/',
24
+ 'accept-encoding': 'gzip, deflate, br, zstd',
25
+ 'accept-language': 'en-US,en;q=0.9',
26
+ 'priority': 'u=0, i'
27
+ }
28
+
29
+ res1 = await client.get(url1, headers=headers1)
30
+ html = res1.text
31
+
32
+ # Type-safe extraction for mypy
33
+ srt_match = re.search(r'name=srt\s+id=srt\s+value=([^\s>]+)', html)
34
+ if not srt_match:
35
+ # Quoted fallback
36
+ srt_match = re.search(r'name="srt".*?value="([^"]+)"', html)
37
+
38
+ if not srt_match:
39
+ return Result.error("Failed to extract srt")
40
+
41
+ srt = srt_match.group(1)
42
+
43
+ # --- Step 2: Identification POST ---
44
+ url2 = "https://signin.ebay.com/signin/srv/identifer"
45
+
46
+ payload = {
47
+ 'identifier': email,
48
+ 'srt': srt,
49
+ 'webAuthNOptedInKeys': "",
50
+ 'webAuthNCredCheck': "true",
51
+ 'useCase': "AUTH",
52
+ 'flowType': "PSI"
53
+ }
54
+
55
+ headers2 = {
56
+ 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36",
57
+ 'Accept-Encoding': "gzip, deflate, br, zstd",
58
+ 'x-ebay-requested-with': "XMLHttpRequest",
59
+ 'sec-ch-ua-platform': '"Android"',
60
+ 'x-ebay-c-trackable-id': "01KFK31DZY0KKB2Y0HA1B00DWH",
61
+ 'sec-ch-ua': '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
62
+ 'sec-ch-ua-model': '"I2404"',
63
+ 'sec-ch-ua-mobile': "?1",
64
+ 'x-requested-with': "XMLHttpRequest",
65
+ 'sec-ch-ua-full-version': '"143.0.7499.192"',
66
+ 'sec-ch-ua-platform-version': '"15.0.0"',
67
+ 'origin': "https://signin.ebay.com",
68
+ 'sec-fetch-site': "same-origin",
69
+ 'sec-fetch-mode': "cors",
70
+ 'sec-fetch-dest': "empty",
71
+ 'referer': "https://signin.ebay.com/signin/",
72
+ 'accept-language': "en-US,en;q=0.9",
73
+ 'priority': "u=1, i"
74
+ }
75
+
76
+ # Optional: Short sleep to mimic human timing before POST
77
+ await asyncio.sleep(1)
78
+
79
+ response = await client.post(url2, data=payload, headers=headers2)
80
+
81
+ if response.status_code == 483:
82
+ return Result.error("Security challenge (483)")
83
+
84
+ data = response.json()
85
+
86
+ if data.get("signinErrorUpdate") is True and "couldn't find this eBay account" in str(data.get("errorMsg", "")):
87
+ return Result.available()
88
+ elif data.get("signinErrorUpdate") is False or "publicUserId" in data:
89
+ return Result.taken()
90
+ else:
91
+ return Result.error("unexpected.... Report it via github issues...")
92
+
93
+ except Exception as e:
94
+ return Result.error(f"unexpected exception: {e}")
95
+
96
+ async def validate_ebay(email: str) -> Result:
97
+ return await _check(email)
@@ -0,0 +1,52 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+ async def _check(email: str) -> Result:
5
+ url = "https://1.rome.api.flipkart.com/1/action/view"
6
+
7
+ headers = {
8
+ 'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36",
9
+ 'Content-Type': "application/json",
10
+ 'X-User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36 FKUA/msite/0.0.3/msite/Mobile channelType/undefined",
11
+ 'Origin': "https://www.flipkart.com",
12
+ 'Referer': "https://www.flipkart.com/"
13
+ }
14
+
15
+ payload = {
16
+ "actionRequestContext": {
17
+ "type": "LOGIN_IDENTITY_VERIFY",
18
+ "loginIdPrefix": "",
19
+ "loginId": email,
20
+ "clientQueryParamMap": {"ret": "/"},
21
+ "loginType": "EMAIL",
22
+ "verificationType": "PASSWORD",
23
+ "screenName": "LOGIN_V4_EMAIL",
24
+ "sourceContext": "DEFAULT"
25
+ }
26
+ }
27
+
28
+ async with httpx.AsyncClient(http2=True) as client:
29
+ try:
30
+ response = await client.post(url, json=payload, headers=headers)
31
+
32
+ if response.status_code == 429:
33
+ return Result.error("Rate limited wait for few minutes")
34
+
35
+ if response.status_code != 200:
36
+ return Result.error(f"HTTP Error: {response.status_code}")
37
+
38
+ response_text = response.text
39
+
40
+ if "Looks like you're new here!" in response_text:
41
+ return Result.available()
42
+
43
+ if "LOGIN_P_CHECK" in response_text or '"statusSuccess":true' in response_text:
44
+ return Result.taken()
45
+
46
+ return Result.taken()
47
+
48
+ except Exception as e:
49
+ return Result.error(e)
50
+
51
+ async def validate_flipkart(email: str) -> Result:
52
+ return await _check(email)
File without changes
@@ -0,0 +1,96 @@
1
+ import httpx
2
+ import re
3
+ from user_scanner.core.result import Result
4
+
5
+ async def _check(email: str) -> Result:
6
+ async with httpx.AsyncClient(http2=True, follow_redirects=False) as client:
7
+ try:
8
+ url1 = "https://m.facebook.com/login/"
9
+ headers1 = {
10
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
11
+ 'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
12
+ 'Accept-Encoding': "identity",
13
+ 'sec-ch-ua': '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
14
+ }
15
+ await client.get(url1, headers=headers1)
16
+
17
+ url2 = "https://www.facebook.com"
18
+ params2 = {'_rdr': ""}
19
+ headers2 = {
20
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
21
+ 'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7",
22
+ 'Accept-Encoding': "identity",
23
+ 'upgrade-insecure-requests': "1",
24
+ 'sec-fetch-site': "cross-site",
25
+ 'sec-fetch-mode': "navigate",
26
+ 'sec-fetch-user': "?1",
27
+ 'sec-fetch-dest': "document",
28
+ 'sec-ch-ua': '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
29
+ 'sec-ch-ua-mobile': "?0",
30
+ 'sec-ch-ua-platform': '"Linux"',
31
+ 'referer': "https://www.google.com/",
32
+ 'accept-language': "en-US,en;q=0.9",
33
+ 'priority': "u=0, i"
34
+ }
35
+ res2 = await client.get(url2, params=params2, headers=headers2)
36
+ html = res2.text
37
+
38
+ j_match = re.search(r'name="jazoest" value="(\d+)"', html)
39
+ l_match = re.search(r'name="lsd" value="([^"]+)"', html)
40
+
41
+ if not j_match or not l_match:
42
+ return Result.error("Failed to extract tokens (LSD/Jazoest)")
43
+
44
+ jazoest = j_match.group(1)
45
+ lsd = l_match.group(1)
46
+
47
+ url3 = "https://www.facebook.com/ajax/login/help/identify.php"
48
+ params3 = {'ctx': "recover"}
49
+
50
+ payload3 = {
51
+ 'jazoest': jazoest,
52
+ 'lsd': lsd,
53
+ 'email': email,
54
+ 'did_submit': "1",
55
+ '__user': "0",
56
+ '__a': "1",
57
+ '__req': "7"
58
+ }
59
+
60
+ headers3 = {
61
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
62
+ 'Accept-Encoding': "identity",
63
+ 'sec-ch-ua-full-version-list': '"Google Chrome";v="143.0.7499.192", "Chromium";v="143.0.7499.192", "Not A(Brand";v="24.0.0.0"',
64
+ 'sec-ch-ua-platform': '"Linux"',
65
+ 'sec-ch-ua': '"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"',
66
+ 'sec-ch-ua-model': '""',
67
+ 'sec-ch-ua-mobile': "?0",
68
+ 'x-asbd-id': "359341",
69
+ 'x-fb-lsd': lsd,
70
+ 'sec-ch-prefers-color-scheme': "dark",
71
+ 'sec-ch-ua-platform-version': '""',
72
+ 'origin': "https://www.facebook.com",
73
+ 'sec-fetch-site': "same-origin",
74
+ 'sec-fetch-mode': "cors",
75
+ 'sec-fetch-dest': "empty",
76
+ 'referer': "https://www.facebook.com/login/identify/?ctx=recover&ars=facebook_login&from_login_screen=0",
77
+ 'accept-language': "en-US,en;q=0.9",
78
+ 'priority': "u=1, i"
79
+ }
80
+
81
+ response = await client.post(url3, params=params3, data=payload3, headers=headers3)
82
+ body = response.text
83
+
84
+ if "redirectPageTo" in body and "ServerRedirect" in body:
85
+ return Result.taken()
86
+ elif "No search results" in body or "Your search did not return any results." in body:
87
+ return Result.available()
88
+ else:
89
+ return Result.error("Unexpected error, report it via GitHub issues")
90
+
91
+ except Exception as e:
92
+ return Result.error(f"Unexpected exception: {e}")
93
+
94
+ async def validate_facebook(email: str) -> Result:
95
+ return await _check(email)
96
+
@@ -0,0 +1,48 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+
5
+ async def _check(email):
6
+ USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36"
7
+ async with httpx.AsyncClient(headers={"user-agent": USER_AGENT}, http2=True) as client:
8
+ await client.get("https://www.instagram.com/")
9
+ csrf = client.cookies.get("csrftoken")
10
+
11
+ headers = {
12
+ "x-csrftoken": csrf,
13
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
14
+ 'Accept-Encoding': "identity",
15
+ 'sec-ch-ua-full-version-list': "\"Google Chrome\";v=\"143.0.7499.146\", \"Chromium\";v=\"143.0.7499.146\", \"Not A(Brand\";v=\"24.0.0.0\"",
16
+ 'sec-ch-ua-platform': "\"Linux\"",
17
+ 'sec-ch-ua': "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"",
18
+ 'sec-ch-ua-model': "\"\"",
19
+ 'sec-ch-ua-mobile': "?0",
20
+ 'x-ig-app-id': "936619743392459",
21
+ 'x-requested-with': "XMLHttpRequest",
22
+ 'x-instagram-ajax': "1031566424",
23
+ 'x-asbd-id': "359341",
24
+ 'x-ig-www-claim': "0",
25
+ 'sec-ch-ua-platform-version': "\"\"",
26
+ 'origin': "https://www.instagram.com",
27
+ 'referer': "https://www.instagram.com/accounts/password/reset/"
28
+ }
29
+
30
+ response = await client.post(
31
+ "https://www.instagram.com/api/v1/web/accounts/account_recovery_send_ajax/",
32
+ data={"email_or_username": email},
33
+ headers=headers
34
+ )
35
+
36
+ data = response.json()
37
+ status_val = data.get("status")
38
+ if status_val == "ok":
39
+ return Result.taken()
40
+ elif status_val == "fail":
41
+ return Result.available()
42
+ else:
43
+ return Result.error("Unexpected response body, report it on github")
44
+
45
+
46
+
47
+ async def validate_instagram(email: str) -> Result:
48
+ return await _check(email)
@@ -0,0 +1,57 @@
1
+ import httpx
2
+ import re
3
+ from user_scanner.core.result import Result
4
+
5
+
6
+ async def _check(email):
7
+ base_url = "https://mastodon.social"
8
+ signup_url = f"{base_url}/auth/sign_up"
9
+ post_url = f"{base_url}/auth"
10
+
11
+ headers = {
12
+ "user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36",
13
+ "accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
14
+ "referer": "https://mastodon.social/explore",
15
+ "origin": "https://mastodon.social"
16
+ }
17
+
18
+ async with httpx.AsyncClient(http2=True, headers=headers, follow_redirects=False) as client:
19
+ try:
20
+ initial_resp = await client.get(signup_url)
21
+ if initial_resp.status_code != 200:
22
+ return Result.error(f"Failed to access signup page: {initial_resp.status_code}")
23
+
24
+ token_match = re.search(
25
+ r'name="csrf-token" content="([^"]+)"', initial_resp.text)
26
+ if not token_match:
27
+ return Result.error("Could not find authenticity token")
28
+
29
+ csrf_token = token_match.group(1)
30
+
31
+ payload = {
32
+ "authenticity_token": csrf_token,
33
+ "user[account_attributes][username]": "no3motions_robot_020102",
34
+ "user[email]": email,
35
+ "user[password]": "Theleftalone@me",
36
+ "user[password_confirmation]": "Theleftalone@me",
37
+ "user[agreement]": "1",
38
+ "button": ""
39
+ }
40
+
41
+ response = await client.post(post_url, data=payload)
42
+ res_text = response.text
43
+ res_status = response.status_code
44
+ if "has already been taken" in res_text:
45
+ return Result.taken()
46
+ elif "has already been taken" not in res_text and res_status == 200:
47
+ return Result.available()
48
+ elif res_status == 429:
49
+ return Result.error("Rate limited, use '-d' flag to avoid bot detection")
50
+ else:
51
+ return Result.error("Unexpected error, report it via GitHub issues")
52
+ except Exception as e:
53
+ return Result.error(e)
54
+
55
+
56
+ async def validate_mastodon(email: str) -> Result:
57
+ return await _check(email)
@@ -0,0 +1,41 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+ async def _check(email):
5
+ url = "https://api.x.com/i/users/email_available.json"
6
+ params = {"email": email}
7
+ headers = {
8
+ "user-agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36",
9
+ "accept-encoding": "gzip, deflate, br, zstd",
10
+ "sec-ch-ua-platform": "\"Android\"",
11
+ "sec-ch-ua": "\"Google Chrome\";v=\"143\", \"Chromium\";v=\"143\", \"Not A(Brand\";v=\"24\"",
12
+ "x-twitter-client-language": "en",
13
+ "sec-ch-ua-mobile": "?1",
14
+ "x-twitter-active-user": "yes",
15
+ "origin": "https://x.com",
16
+ "priority": "u=1, i"
17
+ }
18
+
19
+ async with httpx.AsyncClient(http2=True) as client:
20
+ try:
21
+ response = await client.get(url, params=params, headers=headers)
22
+
23
+ if response.status_code == 429:
24
+ return Result.error("Rate limited wait for few minutes or use '-d' flag")
25
+
26
+ data = response.json()
27
+ taken_bool = data.get("taken")
28
+
29
+ if taken_bool is True:
30
+ return Result.taken()
31
+ elif taken_bool is False:
32
+ return Result.available()
33
+ else:
34
+ return Result.error("Unexpected error, report it via GitHub issues")
35
+
36
+ except Exception as e:
37
+ return Result.error(e)
38
+
39
+
40
+ async def validate_x(email: str) -> Result:
41
+ return await _check(email)
@@ -0,0 +1,30 @@
1
+ import re
2
+ from user_scanner.core.orchestrator import status_validate
3
+ from user_scanner.core.result import Result
4
+
5
+
6
+ def validate_lemmy(user: str) -> Result:
7
+ """Check username availability on Lemmy (lemmy.world instance)"""
8
+
9
+ # Lemmy username rules: 3-20 chars, alphanumeric and underscores only
10
+ if not (3 <= len(user) <= 20):
11
+ return Result.error("Length must be 3-20 characters")
12
+
13
+ if not re.match(r'^[a-zA-Z0-9_]+$', user):
14
+ return Result.error("Only letters, numbers, and underscores allowed")
15
+
16
+ url = f"https://lemmy.world/api/v3/user?username={user}"
17
+
18
+ return status_validate(url, [400, 404], 200, timeout=5.0)
19
+
20
+
21
+ if __name__ == "__main__":
22
+ user = input("Username?: ").strip()
23
+ result = validate_lemmy(user)
24
+
25
+ if result == 1:
26
+ print("Available!")
27
+ elif result == 0:
28
+ print("Unavailable!")
29
+ else:
30
+ print(f"Error occurred! Reason: {result.get_reason()}")
File without changes
@@ -0,0 +1,22 @@
1
+ import re
2
+ from user_scanner.core.orchestrator import status_validate, Result
3
+
4
+ def validate_gumroad(user: str) -> Result:
5
+ if not re.fullmatch(r"[a-z0-9]{3,20}", user):
6
+ return Result.error("Username must be between 3 and 20 lowercase alphanumeric characters")
7
+
8
+ url = f"https://{user}.gumroad.com/"
9
+ return status_validate(url, 404, 200, follow_redirects=True)
10
+
11
+
12
+ if __name__ == "__main__":
13
+ user = input("Username?: ").strip()
14
+ result = validate_gumroad(user)
15
+
16
+ if result == 1:
17
+ print("Available!")
18
+ elif result == 0:
19
+ print("Unavailable!")
20
+ else:
21
+ print(f"Error occurred! Reason: {result.get_reason()}")
22
+
@@ -1,7 +1,15 @@
1
- from user_scanner.core.orchestrator import status_validate
1
+ import re
2
+ from user_scanner.core.orchestrator import status_validate, Result
2
3
 
3
4
 
4
- def validate_producthunt(user):
5
+ def validate_producthunt(user: str) -> Result:
6
+ if not (2 <= len(user) <= 32):
7
+ return Result.error("Length must be 2-32 characters.")
8
+
9
+ # Rules: Letters, numbers, and underscores only.
10
+ if not re.match(r'^[a-zA-Z0-9_]+$', user):
11
+ return Result.error("Only use letters, numbers, and underscores.")
12
+
5
13
  url = f"https://www.producthunt.com/@{user}"
6
14
 
7
15
  headers = {
@@ -11,7 +19,8 @@ def validate_producthunt(user):
11
19
  'Accept-Language': "en-US,en;q=0.9",
12
20
  }
13
21
 
14
- status_validate(url, 404, 200, headers=headers, follow_redirects=True)
22
+ return status_validate(url, 404, 200, headers=headers, follow_redirects=True)
23
+
15
24
 
16
25
  if __name__ == "__main__":
17
26
  user = input("Username?: ").strip()
@@ -22,4 +31,4 @@ if __name__ == "__main__":
22
31
  elif result == 0:
23
32
  print("Unavailable!")
24
33
  else:
25
- print("Error occured!")
34
+ print(f"Error occurred! Reason: {result.get_reason()}")
File without changes
File without changes