user-scanner 1.1.0__tar.gz → 1.1.0.1__tar.gz
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.
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/PKG-INFO +3 -3
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/README.md +2 -2
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/pyproject.toml +1 -1
- user_scanner-1.1.0.1/user_scanner/config.json +1 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/core/result.py +29 -21
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/adult/pornhub.py +1 -1
- user_scanner-1.1.0.1/user_scanner/email_scan/community/stackoverflow.py +40 -0
- user_scanner-1.1.0.1/user_scanner/email_scan/creator/gumroad.py +82 -0
- user_scanner-1.1.0.1/user_scanner/email_scan/creator/patreon.py +58 -0
- user_scanner-1.1.0.1/user_scanner/email_scan/gaming/chess_com.py +47 -0
- user_scanner-1.1.0.1/user_scanner/user_scan/donation/__init__.py +0 -0
- user_scanner-1.1.0.1/user_scanner/user_scan/gaming/__init__.py +0 -0
- user_scanner-1.1.0.1/user_scanner/utils/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/version.json +1 -1
- user_scanner-1.1.0/user_scanner/email_scan/dev/.ruff_cache/.gitignore +0 -2
- user_scanner-1.1.0/user_scanner/email_scan/dev/.ruff_cache/0.14.10/10328336453267387919 +0 -0
- user_scanner-1.1.0/user_scanner/email_scan/dev/.ruff_cache/CACHEDIR.TAG +0 -1
- user_scanner-1.1.0/user_scanner/email_scan/shopping/ebay.py.lock +0 -97
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/LICENSE +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/__main__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/cli/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/cli/banner.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/core/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/core/email_orchestrator.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/core/formatter.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/core/helpers.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/core/orchestrator.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/core/version.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/adult/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/adult/xnxx.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/adult/xvideos.py +0 -0
- {user_scanner-1.1.0/user_scanner/email_scan/dev → user_scanner-1.1.0.1/user_scanner/email_scan/community}/__init__.py +0 -0
- {user_scanner-1.1.0/user_scanner/email_scan/shopping → user_scanner-1.1.0.1/user_scanner/email_scan/creator}/__init__.py +0 -0
- {user_scanner-1.1.0/user_scanner/email_scan/social → user_scanner-1.1.0.1/user_scanner/email_scan/dev}/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/dev/bitbucket.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/dev/github.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/dev/huggingface.py +0 -0
- {user_scanner-1.1.0/user_scanner/user_scan/creator → user_scanner-1.1.0.1/user_scanner/email_scan/gaming}/__init__.py +0 -0
- {user_scanner-1.1.0/user_scanner/user_scan/donation → user_scanner-1.1.0.1/user_scanner/email_scan/shopping}/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/shopping/flipkart.py +0 -0
- {user_scanner-1.1.0/user_scanner/user_scan/gaming → user_scanner-1.1.0.1/user_scanner/email_scan/social}/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/social/facebook.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/social/instagram.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/social/mastodon.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/email_scan/social/x.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/community/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/community/coderlegion.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/community/hackernews.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/community/lemmy.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/community/stackoverflow.py +0 -0
- {user_scanner-1.1.0/user_scanner/utils → user_scanner-1.1.0.1/user_scanner/user_scan/creator}/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/devto.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/gumroad.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/hashnode.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/itch_io.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/kaggle.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/medium.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/patreon.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/producthunt.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/substack.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/creator/twitch.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/bitbucket.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/codeberg.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/cratesio.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/dockerhub.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/github.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/gitlab.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/huggingface.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/launchpad.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/leetcode.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/npmjs.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/replit.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/dev/sourceforge.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/donation/buymeacoffee.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/donation/liberapay.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/gaming/chess_com.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/gaming/lichess.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/gaming/minecraft.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/gaming/monkeytype.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/gaming/osu.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/gaming/roblox.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/gaming/steam.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/__init__.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/bluesky.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/discord.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/instagram.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/mastodon.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/pinterest.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/reddit.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/snapchat.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/soundcloud.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/telegram.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/threads.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/tiktok.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/x.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/social/youtube.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/utils/update.py +0 -0
- {user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/utils/updater_logic.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: user-scanner
|
|
3
|
-
Version: 1.1.0
|
|
3
|
+
Version: 1.1.0.1
|
|
4
4
|
Summary: Check username availability across multiple popular platforms
|
|
5
5
|
Keywords: username,checker,availability,social,tech,python,user-scanner
|
|
6
6
|
Author-email: Kaif <kafcodec@gmail.com>
|
|
@@ -16,7 +16,7 @@ Project-URL: Homepage, https://github.com/kaifcodec/user-scanner
|
|
|
16
16
|
|
|
17
17
|

|
|
18
18
|
<p align="center">
|
|
19
|
-
<img src="https://img.shields.io/badge/Version-1.0.
|
|
19
|
+
<img src="https://img.shields.io/badge/Version-1.1.0.1-blueviolet?style=for-the-badge&logo=github" />
|
|
20
20
|
<img src="https://img.shields.io/github/issues/kaifcodec/user-scanner?style=for-the-badge&logo=github" />
|
|
21
21
|
<img src="https://img.shields.io/badge/Tested%20on-Termux-black?style=for-the-badge&logo=termux" />
|
|
22
22
|
<img src="https://img.shields.io/badge/Tested%20on-Windows-cyan?style=for-the-badge&logo=Windows" />
|
|
@@ -28,7 +28,7 @@ Project-URL: Homepage, https://github.com/kaifcodec/user-scanner
|
|
|
28
28
|
|
|
29
29
|
### ⚠️ Email OSINT mode had not been implemented yet, still in progress
|
|
30
30
|
|
|
31
|
-
A powerful *Email OSINT tool* that checks if a specific email is registered on various sites, combined with *username scanning* — 2-in-1
|
|
31
|
+
A powerful *Email OSINT tool* that checks if a specific email is registered on various sites, combined with *username scanning* for branding or OSINT — 2-in-1 tool.
|
|
32
32
|
|
|
33
33
|
Perfect for fast, accurate and lightweight email OSINT
|
|
34
34
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
<p align="center">
|
|
5
|
-
<img src="https://img.shields.io/badge/Version-1.0.
|
|
5
|
+
<img src="https://img.shields.io/badge/Version-1.1.0.1-blueviolet?style=for-the-badge&logo=github" />
|
|
6
6
|
<img src="https://img.shields.io/github/issues/kaifcodec/user-scanner?style=for-the-badge&logo=github" />
|
|
7
7
|
<img src="https://img.shields.io/badge/Tested%20on-Termux-black?style=for-the-badge&logo=termux" />
|
|
8
8
|
<img src="https://img.shields.io/badge/Tested%20on-Windows-cyan?style=for-the-badge&logo=Windows" />
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
### ⚠️ Email OSINT mode had not been implemented yet, still in progress
|
|
16
16
|
|
|
17
|
-
A powerful *Email OSINT tool* that checks if a specific email is registered on various sites, combined with *username scanning* — 2-in-1
|
|
17
|
+
A powerful *Email OSINT tool* that checks if a specific email is registered on various sites, combined with *username scanning* for branding or OSINT — 2-in-1 tool.
|
|
18
18
|
|
|
19
19
|
Perfect for fast, accurate and lightweight email OSINT
|
|
20
20
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"auto_update_status": true}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from enum import Enum
|
|
2
|
+
|
|
2
3
|
from colorama import Fore, Style
|
|
3
4
|
|
|
4
5
|
DEBUG_MSG = """Result {{
|
|
@@ -53,7 +54,7 @@ class Result:
|
|
|
53
54
|
self.username = None
|
|
54
55
|
self.site_name = None
|
|
55
56
|
self.category = None
|
|
56
|
-
self.is_email = False
|
|
57
|
+
self.is_email = False
|
|
57
58
|
self.update(**kwargs)
|
|
58
59
|
|
|
59
60
|
def update(self, **kwargs):
|
|
@@ -62,12 +63,12 @@ class Result:
|
|
|
62
63
|
setattr(self, field, kwargs[field])
|
|
63
64
|
|
|
64
65
|
@classmethod
|
|
65
|
-
def taken(cls, **kwargs):
|
|
66
|
-
return cls(Status.TAKEN, **kwargs)
|
|
66
|
+
def taken(cls, reason: str | Exception | None = None, **kwargs):
|
|
67
|
+
return cls(Status.TAKEN, reason, **kwargs)
|
|
67
68
|
|
|
68
69
|
@classmethod
|
|
69
|
-
def available(cls, **kwargs):
|
|
70
|
-
return cls(Status.AVAILABLE, **kwargs)
|
|
70
|
+
def available(cls, reason: str | Exception | None = None, **kwargs):
|
|
71
|
+
return cls(Status.AVAILABLE, reason, **kwargs)
|
|
71
72
|
|
|
72
73
|
@classmethod
|
|
73
74
|
def error(cls, reason: str | Exception | None = None, **kwargs):
|
|
@@ -79,7 +80,7 @@ class Result:
|
|
|
79
80
|
status = Status(i)
|
|
80
81
|
except ValueError:
|
|
81
82
|
return cls(Status.ERROR, "Invalid status. Please contact maintainers.")
|
|
82
|
-
return cls(status,
|
|
83
|
+
return cls(status, reason)
|
|
83
84
|
|
|
84
85
|
def to_number(self) -> int:
|
|
85
86
|
return self.status.value
|
|
@@ -102,7 +103,7 @@ class Result:
|
|
|
102
103
|
"username": self.username,
|
|
103
104
|
"site_name": self.site_name,
|
|
104
105
|
"category": self.category,
|
|
105
|
-
"is_email": self.is_email
|
|
106
|
+
"is_email": self.is_email,
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
def debug(self) -> str:
|
|
@@ -111,7 +112,7 @@ class Result:
|
|
|
111
112
|
def to_json(self) -> str:
|
|
112
113
|
msg = JSON_TEMPLATE.format(**self.as_dict())
|
|
113
114
|
if self.is_email:
|
|
114
|
-
msg = msg.replace(
|
|
115
|
+
msg = msg.replace('\t"username":', '\t"email":')
|
|
115
116
|
return msg
|
|
116
117
|
|
|
117
118
|
def to_csv(self) -> str:
|
|
@@ -129,22 +130,29 @@ class Result:
|
|
|
129
130
|
return self.to_number() == other
|
|
130
131
|
return NotImplemented
|
|
131
132
|
|
|
133
|
+
def get_output_color(self) -> str:
|
|
134
|
+
if self == Status.ERROR:
|
|
135
|
+
return Fore.YELLOW
|
|
136
|
+
elif self.is_email:
|
|
137
|
+
return Fore.GREEN if self == Status.TAKEN else Fore.RED
|
|
138
|
+
else:
|
|
139
|
+
return Fore.GREEN if self == Status.AVAILABLE else Fore.RED
|
|
140
|
+
|
|
141
|
+
def get_output_icon(self) -> str:
|
|
142
|
+
if self == Status.ERROR:
|
|
143
|
+
return "[!]"
|
|
144
|
+
elif self.is_email:
|
|
145
|
+
return "[✔]" if self == Status.TAKEN else "[✘]"
|
|
146
|
+
else:
|
|
147
|
+
return "[✔]" if self == Status.AVAILABLE else "[✘]"
|
|
148
|
+
|
|
132
149
|
def get_console_output(self) -> str:
|
|
133
150
|
site_name = self.site_name
|
|
134
151
|
username = self.username
|
|
135
152
|
status_text = self.status.to_label(self.is_email)
|
|
136
153
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
icon = "[✔]" if self == Status.TAKEN else "[✘]"
|
|
140
|
-
else:
|
|
141
|
-
color = Fore.GREEN if self == Status.AVAILABLE else Fore.RED
|
|
142
|
-
icon = "[✔]" if self == Status.AVAILABLE else "[✘]"
|
|
143
|
-
|
|
144
|
-
if self == Status.AVAILABLE or self == Status.TAKEN:
|
|
145
|
-
return f" {color}{icon} {site_name} ({username}): {status_text}{Style.RESET_ALL}"
|
|
146
|
-
elif self == Status.ERROR:
|
|
147
|
-
reason = f" ({self.get_reason()})" if self.has_reason() else ""
|
|
148
|
-
return f" {Fore.YELLOW}[!] {site_name} ({username}): {status_text}{reason}{Style.RESET_ALL}"
|
|
154
|
+
color = self.get_output_color()
|
|
155
|
+
icon = self.get_output_icon()
|
|
149
156
|
|
|
150
|
-
|
|
157
|
+
reason = f" ({self.get_reason()})" if self.has_reason() else ""
|
|
158
|
+
return f" {color}{icon} {site_name} ({username}): {status_text}{reason}{Style.RESET_ALL}"
|
|
@@ -14,7 +14,7 @@ async def _check(email: str) -> Result:
|
|
|
14
14
|
"content-type": "application/x-www-form-urlencoded; charset=UTF-8"
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
async with httpx.AsyncClient(http2=True, follow_redirects=True, timeout=
|
|
17
|
+
async with httpx.AsyncClient(http2=True, follow_redirects=True, timeout=3) as client:
|
|
18
18
|
try:
|
|
19
19
|
landing_resp = await client.get(base_url, headers=headers)
|
|
20
20
|
token_match = re.search(r'var\s+token\s*=\s*"([^"]+)"', landing_resp.text)
|
|
@@ -0,0 +1,40 @@
|
|
|
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=False, follow_redirects=True) as client:
|
|
6
|
+
try:
|
|
7
|
+
url = "https://stackoverflow.com/users/login"
|
|
8
|
+
|
|
9
|
+
payload = {
|
|
10
|
+
'ssrc': "login",
|
|
11
|
+
'email': email,
|
|
12
|
+
'password': "Password109-grt",
|
|
13
|
+
'oauth_version': "",
|
|
14
|
+
'oauth_server': ""
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
headers = {
|
|
18
|
+
'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
|
|
19
|
+
'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",
|
|
20
|
+
'Accept-Encoding': "identity",
|
|
21
|
+
'sec-ch-ua-platform': '"Linux"',
|
|
22
|
+
'origin': "https://stackoverflow.com",
|
|
23
|
+
'referer': "https://stackoverflow.com/users/login"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
response = await client.post(url, data=payload, headers=headers)
|
|
27
|
+
body = response.text
|
|
28
|
+
|
|
29
|
+
if "No user found with matching email" in body:
|
|
30
|
+
return Result.available()
|
|
31
|
+
elif "The email or password is incorrect" in body:
|
|
32
|
+
return Result.taken()
|
|
33
|
+
else:
|
|
34
|
+
return Result.error("Unexpected response body")
|
|
35
|
+
|
|
36
|
+
except Exception as e:
|
|
37
|
+
return Result.error(f"unexpected exception: {e}")
|
|
38
|
+
|
|
39
|
+
async def validate_stackoverflow(email: str) -> Result:
|
|
40
|
+
return await _check(email)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import httpx
|
|
2
|
+
import re
|
|
3
|
+
from user_scanner.core.result import Result
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
async def _check(email: str) -> Result:
|
|
7
|
+
async with httpx.AsyncClient(http2=False, follow_redirects=True) as client:
|
|
8
|
+
try:
|
|
9
|
+
url1 = "https://gumroad.com/users/forgot_password/new"
|
|
10
|
+
headers1 = {
|
|
11
|
+
'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
|
|
12
|
+
'Accept': "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8",
|
|
13
|
+
'Accept-Encoding': "gzip, deflate, br, zstd",
|
|
14
|
+
'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
|
|
15
|
+
'sec-ch-ua-mobile': "?0",
|
|
16
|
+
'sec-ch-ua-platform': '"Linux"',
|
|
17
|
+
'upgrade-insecure-requests': "1",
|
|
18
|
+
'referer': "https://www.google.com/",
|
|
19
|
+
'accept-language': "en-US,en;q=0.9"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
res1 = await client.get(url1, headers=headers1)
|
|
23
|
+
html = res1.text
|
|
24
|
+
|
|
25
|
+
csrf_match = re.search(
|
|
26
|
+
r'authenticity_token":"([^&]+)"', html)
|
|
27
|
+
if not csrf_match:
|
|
28
|
+
csrf_match = re.search(
|
|
29
|
+
r'name="csrf-token" content="([^"]+)"', html)
|
|
30
|
+
|
|
31
|
+
if not csrf_match:
|
|
32
|
+
return Result.error("Failed to extract CSRF token")
|
|
33
|
+
|
|
34
|
+
csrf_token = csrf_match.group(1)
|
|
35
|
+
|
|
36
|
+
url2 = "https://gumroad.com/users/forgot_password"
|
|
37
|
+
|
|
38
|
+
payload = {
|
|
39
|
+
"user": {
|
|
40
|
+
"email": email
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
headers2 = {
|
|
45
|
+
'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
|
|
46
|
+
'Accept': "text/html, application/xhtml+xml",
|
|
47
|
+
'Accept-Encoding': "gzip, deflate, br, zstd",
|
|
48
|
+
'Content-Type': "application/json",
|
|
49
|
+
'sec-ch-ua-platform': '"Linux"',
|
|
50
|
+
'x-csrf-token': csrf_token,
|
|
51
|
+
'sec-ch-ua': '"Not(A:Brand";v="8", "Chromium";v="144", "Google Chrome";v="144"',
|
|
52
|
+
'x-inertia': "true",
|
|
53
|
+
'sec-ch-ua-mobile': "?0",
|
|
54
|
+
'x-requested-with': "XMLHttpRequest",
|
|
55
|
+
'origin': "https://gumroad.com",
|
|
56
|
+
'sec-fetch-site': "same-origin",
|
|
57
|
+
'sec-fetch-mode': "cors",
|
|
58
|
+
'sec-fetch-dest': "empty",
|
|
59
|
+
'referer': "https://gumroad.com/users/forgot_password/new",
|
|
60
|
+
'accept-language': "en-US,en;q=0.9",
|
|
61
|
+
'priority': "u=1, i"
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
response = await client.post(url2, json=payload, headers=headers2)
|
|
65
|
+
|
|
66
|
+
data = response.json()
|
|
67
|
+
flash_msg = data.get("props", {}).get(
|
|
68
|
+
"flash", {}).get("message", "")
|
|
69
|
+
|
|
70
|
+
if "An account does not exist" in flash_msg:
|
|
71
|
+
return Result.available()
|
|
72
|
+
elif "An account does not exist" not in flash_msg:
|
|
73
|
+
return Result.taken()
|
|
74
|
+
else:
|
|
75
|
+
return Result.error(f"Unexpected status: {response.status_code}")
|
|
76
|
+
|
|
77
|
+
except Exception as e:
|
|
78
|
+
return Result.error(f"unexpected exception: {e}")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
async def validate_gumroad(email: str) -> Result:
|
|
82
|
+
return await _check(email)
|
|
@@ -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
|
+
async with httpx.AsyncClient(http2=False) as client:
|
|
7
|
+
try:
|
|
8
|
+
url = "https://www.patreon.com/api/auth"
|
|
9
|
+
|
|
10
|
+
params = {
|
|
11
|
+
'include': "user.null",
|
|
12
|
+
'fields[user]': "[]",
|
|
13
|
+
'json-api-version': "1.0",
|
|
14
|
+
'json-api-use-default-includes': "false"
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
payload = "{\"data\":{\"type\":\"genericPatreonApi\",\"attributes\":{\"patreon_auth\":{\"email\":\"" + email + \
|
|
18
|
+
"\",\"allow_account_creation\":false},\"auth_context\":\"auth\",\"ru\":\"https://www.patreon.com/home\"},\"relationships\":{}}}"
|
|
19
|
+
|
|
20
|
+
headers = {
|
|
21
|
+
'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36",
|
|
22
|
+
'Accept-Encoding': "identity",
|
|
23
|
+
'content-type': "application/vnd.api+json",
|
|
24
|
+
'origin': "https://www.patreon.com"
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
response = await client.post(
|
|
28
|
+
url,
|
|
29
|
+
params=params,
|
|
30
|
+
content=payload,
|
|
31
|
+
headers=headers
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if response.status_code != 200:
|
|
35
|
+
return Result.error(f"Status {response.status_code}")
|
|
36
|
+
|
|
37
|
+
data = response.json()
|
|
38
|
+
next_step = data.get("data", {}).get(
|
|
39
|
+
"attributes", {}).get("next_auth_step")
|
|
40
|
+
|
|
41
|
+
if next_step == "password":
|
|
42
|
+
return Result.taken()
|
|
43
|
+
elif next_step == "signup":
|
|
44
|
+
return Result.available()
|
|
45
|
+
else:
|
|
46
|
+
return Result.error("Unexpected auth step")
|
|
47
|
+
|
|
48
|
+
except Exception as e:
|
|
49
|
+
return Result.error(f"unexpected exception: {e}")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def validate_patreon(email: str) -> Result:
|
|
53
|
+
return await _check(email)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
@@ -0,0 +1,47 @@
|
|
|
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://www.chess.com/rpc/chesscom.authentication.v1.EmailValidationService/Validate"
|
|
8
|
+
|
|
9
|
+
payload = {
|
|
10
|
+
"email": email
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
headers = {
|
|
14
|
+
'User-Agent': "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Mobile Safari/537.36",
|
|
15
|
+
'Accept': "application/json, text/plain, */*",
|
|
16
|
+
'Accept-Encoding': "identity",
|
|
17
|
+
'Content-Type': "application/json",
|
|
18
|
+
'sec-ch-ua-platform': '"Android"',
|
|
19
|
+
'accept-language': "en_US",
|
|
20
|
+
'connect-protocol-version': "1",
|
|
21
|
+
'origin': "https://www.chess.com",
|
|
22
|
+
'sec-fetch-site': "same-origin",
|
|
23
|
+
'sec-fetch-mode': "cors",
|
|
24
|
+
'referer': "https://www.chess.com/register",
|
|
25
|
+
'priority': "u=1, i"
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
response = await client.post(url, json=payload, headers=headers)
|
|
29
|
+
|
|
30
|
+
if response.status_code != 200:
|
|
31
|
+
return Result.error(f"Status {response.status_code}, report is via GitHub issues")
|
|
32
|
+
|
|
33
|
+
data = response.json()
|
|
34
|
+
status = data.get("status")
|
|
35
|
+
|
|
36
|
+
if status == "EMAIL_STATUS_TAKEN":
|
|
37
|
+
return Result.taken()
|
|
38
|
+
elif status == "EMAIL_STATUS_AVAILABLE":
|
|
39
|
+
return Result.available()
|
|
40
|
+
else:
|
|
41
|
+
return Result.error(f"Unknown status: {status}, report is via GitHub issues")
|
|
42
|
+
|
|
43
|
+
except Exception as e:
|
|
44
|
+
return Result.error(f"unexpected exception: {e}")
|
|
45
|
+
|
|
46
|
+
async def validate_chess_com(email: str) -> Result:
|
|
47
|
+
return await _check(email)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
Signature: 8a477f597d28d172789f06886806bc55
|
|
@@ -1,97 +0,0 @@
|
|
|
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)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{user_scanner-1.1.0 → user_scanner-1.1.0.1}/user_scanner/user_scan/community/stackoverflow.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|