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,60 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+ async def _check(email: str) -> Result:
5
+ url = "https://api.render.com/graphql"
6
+
7
+ payload = {
8
+ "operationName": "signUp",
9
+ "variables": {
10
+ "signup": {
11
+ "email": email,
12
+ "githubId": "",
13
+ "name": "",
14
+ "githubToken": "",
15
+ "googleId": "",
16
+ "gitlabId": "",
17
+ "bitbucketId": "",
18
+ "inviteCode": "",
19
+ "password": "StandardPassword123!",
20
+ "newsletterOptIn": False,
21
+ "next": ""
22
+ }
23
+ },
24
+ "query": "mutation signUp($signup: SignupInput!) {\n signUp(signup: $signup) {\n idToken\n __typename\n }\n}\n"
25
+ }
26
+
27
+ headers = {
28
+ "User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
29
+ "Content-Type": "application/json",
30
+ "origin": "https://dashboard.render.com",
31
+ "referer": "https://dashboard.render.com/register",
32
+ "accept-language": "en-US,en;q=0.9"
33
+ }
34
+
35
+ async with httpx.AsyncClient(http2=True, timeout=4.0) as client:
36
+ try:
37
+ response = await client.post(url, json=payload, headers=headers)
38
+
39
+ if response.status_code == 429:
40
+ return Result.error("Rate limited, use '-d' flag to avoid bot detection")
41
+
42
+ data = response.json()
43
+ errors = data.get("errors", [])
44
+
45
+ if errors:
46
+ msg = errors[0].get("message", "")
47
+ if '"email":"exists"' in msg:
48
+ return Result.taken()
49
+ elif '"hcaptcha_token":"invalid"' in msg:
50
+ return Result.available()
51
+ else:
52
+ return Result.error(f"Render Error: {msg}")
53
+
54
+ return Result.error("Unexpected error, report it via GitHub issues")
55
+
56
+ except Exception as e:
57
+ return Result.error(e)
58
+
59
+ async def validate_render(email: str) -> Result:
60
+ return await _check(email)
@@ -0,0 +1,2 @@
1
+ # Automatically created by ruff.
2
+ *
@@ -0,0 +1 @@
1
+ Signature: 8a477f597d28d172789f06886806bc55
File without changes
@@ -0,0 +1,60 @@
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
+ "Accept-Language": "en-US,en;q=0.9",
10
+ "Referer": "https://www.last.fm/join",
11
+ "X-Requested-With": "XMLHttpRequest",
12
+ "Origin": "https://www.last.fm",
13
+ }
14
+
15
+ try:
16
+ async with httpx.AsyncClient(timeout=5.0, follow_redirects=True) as client:
17
+ await client.get("https://www.last.fm/join", headers=headers)
18
+ token = client.cookies.get("csrftoken")
19
+
20
+ if not token:
21
+ return Result.error("CSRF token not found")
22
+
23
+ headers["X-CSRFToken"] = token
24
+ payload = {
25
+ "csrfmiddlewaretoken": token,
26
+ "userName": "",
27
+ "email": email,
28
+ "password": "",
29
+ "passwordConf": ""
30
+ }
31
+
32
+ response = await client.post(
33
+ "https://www.last.fm/join/partial/validate",
34
+ headers=headers,
35
+ data=payload
36
+ )
37
+
38
+ if response.status_code != 200:
39
+ return Result.error(f"HTTP {response.status_code}")
40
+
41
+ data = response.json()
42
+ email_info = data.get("email", {})
43
+
44
+ if email_info.get("valid") is False and any("already registered" in str(msg).lower() for msg in email_info.get("error_messages", [])):
45
+ return Result.taken()
46
+
47
+ elif email_info.get("valid") is True:
48
+ return Result.available()
49
+
50
+ else:
51
+ return Result.error(data)
52
+
53
+ except httpx.TimeoutException:
54
+ return Result.error("Connection timed out")
55
+ except Exception as e:
56
+ return Result.error(e)
57
+
58
+
59
+ async def validate_lastfm(email: str) -> Result:
60
+ return await _check(email)
@@ -0,0 +1,87 @@
1
+ import httpx
2
+ import json
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
+ get_url = "https://www.spotify.com/in-en/signup"
10
+ get_headers = {
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,application/signed-exchange;v=b3;q=0.7",
13
+ 'Accept-Encoding': "identity",
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
+ 'sec-fetch-site': "same-origin",
19
+ 'sec-fetch-mode': "navigate",
20
+ 'sec-fetch-user': "?1",
21
+ 'sec-fetch-dest': "document",
22
+ 'referer': "https://www.spotify.com/us/signup",
23
+ 'accept-language': "en-US,en;q=0.9",
24
+ 'priority': "u=0, i"
25
+ }
26
+
27
+ await client.get(get_url, headers=get_headers)
28
+
29
+ post_url = "https://spclient.wg.spotify.com/signup/public/v2/account/validate"
30
+
31
+ payload = {
32
+ "fields": [
33
+ {
34
+ "field": "FIELD_EMAIL",
35
+ "value": email
36
+ }
37
+ ],
38
+ "client_info": {
39
+ "api_key": "a1e486e2729f46d6bb368d6b2bcda326",
40
+ "app_version": "v2",
41
+ "capabilities": [1],
42
+ "installation_id": "3740cfb5-c76f-4ae9-9a94-f0989d7ae5a4",
43
+ "platform": "www",
44
+ "client_id": ""
45
+ },
46
+ "tracking": {
47
+ "creation_flow": "",
48
+ "creation_point": "https://www.spotify.com/us/signup",
49
+ "referrer": "",
50
+ "origin_vertical": "",
51
+ "origin_surface": ""
52
+ }
53
+ }
54
+
55
+ post_headers = {
56
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
57
+ 'Accept-Encoding': "identity",
58
+ 'Content-Type': "application/json",
59
+ 'sec-ch-ua-platform': "\"Linux\"",
60
+ 'sec-ch-ua': "\"Not(A:Brand\";v=\"8\", \"Chromium\";v=\"144\", \"Google Chrome\";v=\"144\"",
61
+ 'sec-ch-ua-mobile': "?0",
62
+ 'origin': "https://www.spotify.com",
63
+ 'sec-fetch-site': "same-site",
64
+ 'sec-fetch-mode': "cors",
65
+ 'sec-fetch-dest': "empty",
66
+ 'referer': "https://www.spotify.com/",
67
+ 'accept-language': "en-US,en;q=0.9",
68
+ 'priority': "u=1, i"
69
+ }
70
+
71
+ response = await client.post(post_url, content=json.dumps(payload), headers=post_headers)
72
+
73
+ data = response.json()
74
+
75
+ if "error" in data and "already_exists" in data["error"]:
76
+ return Result.taken()
77
+ elif "success" in data:
78
+ return Result.available()
79
+
80
+ return Result.error(f"Unexpected error [{response.status_code}], report it via GitHub issues")
81
+
82
+ except Exception as e:
83
+ return Result.error(f"Exception: {e}")
84
+
85
+
86
+ async def validate_spotify(email: str) -> Result:
87
+ 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: str) -> Result:
5
+ headers = {
6
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
7
+ 'Accept': 'application/json',
8
+ 'Accept-Language': 'en-US,en;q=0.9',
9
+ 'Content-Type': 'application/x-www-form-urlencoded',
10
+ 'Origin': 'https://account.envato.com',
11
+ 'Referer': 'https://account.envato.com/sign_up',
12
+ }
13
+
14
+ payload = {'email': email}
15
+
16
+ try:
17
+ async with httpx.AsyncClient(timeout=10.0) as client:
18
+ response = await client.post(
19
+ 'https://account.envato.com/api/validate_email',
20
+ headers=headers,
21
+ data=payload
22
+ )
23
+
24
+ if 'Email is already in use' in response.text:
25
+ return Result.taken()
26
+
27
+ if response.status_code == 200:
28
+ return Result.available()
29
+
30
+ if "Page designed by Kotulsky" in response.text or response.status_code == 429:
31
+ return Result.error("Rate limit or Cloudflare challenge detected")
32
+
33
+ return Result.error(f"Unexpected response: {response.status_code}")
34
+
35
+ except httpx.TimeoutException:
36
+ return Result.error("Connection timed out")
37
+ except Exception as e:
38
+ return Result.error(str(e))
39
+
40
+ async def validate_envato(email: str) -> Result:
41
+ return await _check(email)
@@ -0,0 +1,46 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+ async def _check(email: str) -> Result:
5
+ headers = {
6
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
7
+ 'Accept': '*/*',
8
+ 'Accept-Language': 'fr,fr-FR;q=0.9,en;q=0.8',
9
+ 'X-Requested-With': 'XMLHttpRequest',
10
+ 'Origin': 'https://www.naturabuy.fr',
11
+ 'Referer': 'https://www.naturabuy.fr/register.php',
12
+ }
13
+
14
+ files = {
15
+ 'jsref': (None, 'email'),
16
+ 'jsvalue': (None, email),
17
+ 'registerMode': (None, 'full')
18
+ }
19
+
20
+ try:
21
+ async with httpx.AsyncClient(timeout=10.0) as client:
22
+ response = await client.post(
23
+ 'https://www.naturabuy.fr/includes/ajax/register.php',
24
+ headers=headers,
25
+ files=files
26
+ )
27
+
28
+ if response.status_code != 200:
29
+ return Result.error(f"Unexpected status: {response.status_code}")
30
+
31
+ data = response.json()
32
+
33
+ if data.get("free") is False:
34
+ return Result.taken()
35
+ elif data.get("free") is True:
36
+ return Result.available()
37
+
38
+ return Result.error("Unexpected response format")
39
+
40
+ except httpx.TimeoutException:
41
+ return Result.error("Connection timed out")
42
+ except Exception as e:
43
+ return Result.error(str(e))
44
+
45
+ async def validate_naturabuy(email: str) -> Result:
46
+ return await _check(email)
@@ -0,0 +1,49 @@
1
+ import httpx
2
+ from user_scanner.core.result import Result
3
+
4
+ async def _check(email: str) -> Result:
5
+ headers = {
6
+ 'User-Agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36",
7
+ 'Accept': 'application/json',
8
+ 'Referer': 'https://www.vivino.com/',
9
+ 'Accept-Language': 'en-US,en;q=0.9',
10
+ 'X-Requested-With': 'XMLHttpRequest',
11
+ 'Content-Type': 'application/json',
12
+ }
13
+
14
+ try:
15
+ async with httpx.AsyncClient(timeout=10.0) as client:
16
+ await client.get("https://www.vivino.com/", headers=headers)
17
+
18
+ payload = {
19
+ "email": email,
20
+ "password": "password123"
21
+ }
22
+
23
+ response = await client.post(
24
+ 'https://www.vivino.com/api/login',
25
+ headers=headers,
26
+ json=payload
27
+ )
28
+
29
+ if response.status_code == 429:
30
+ return Result.error("Rate limit exceeded")
31
+
32
+ data = response.json()
33
+ error_msg = data.get("error", "")
34
+
35
+ if error_msg == "The supplied email does not exist":
36
+ return Result.available()
37
+
38
+ if not error_msg or "password" in error_msg.lower():
39
+ return Result.taken()
40
+
41
+ return Result.error(f"Vivino Error: {error_msg}")
42
+
43
+ except httpx.TimeoutException:
44
+ return Result.error("Connection timed out")
45
+ except Exception as e:
46
+ return Result.error(str(e))
47
+
48
+ async def validate_vivino(email: str) -> Result:
49
+ return await _check(email)
@@ -15,10 +15,10 @@ async def _check(email):
15
15
  "origin": "https://mastodon.social"
16
16
  }
17
17
 
18
- async with httpx.AsyncClient(http2=True, headers=headers, follow_redirects=False) as client:
18
+ async with httpx.AsyncClient(http2=True, headers=headers, follow_redirects=True) as client:
19
19
  try:
20
20
  initial_resp = await client.get(signup_url)
21
- if initial_resp.status_code != 200:
21
+ if initial_resp.status_code not in [200, 302]:
22
22
  return Result.error(f"Failed to access signup page: {initial_resp.status_code}")
23
23
 
24
24
  token_match = re.search(
@@ -43,7 +43,9 @@ async def _check(email):
43
43
  res_status = response.status_code
44
44
  if "has already been taken" in res_text:
45
45
  return Result.taken()
46
- elif "has already been taken" not in res_text and res_status == 200:
46
+ elif "registration attempt has been blocked" in res_text:
47
+ return Result.error("Your IP has been flagged by mastodon, try after some time")
48
+ elif "has already been taken" not in res_text and res_status in [200, 302]:
47
49
  return Result.available()
48
50
  elif res_status == 429:
49
51
  return Result.error("Rate limited, use '-d' flag to avoid bot detection")
@@ -0,0 +1,65 @@
1
+ import re
2
+ from user_scanner.core.orchestrator import generic_validate
3
+ from user_scanner.core.result import Result
4
+
5
+
6
+ def validate_battlenet(user: str) -> Result:
7
+ """
8
+ Check username availability on Battle.net via Overwatch player search.
9
+
10
+ Battle.net uses BattleTags (Username#1234) but this validator checks
11
+ if the username portion exists in the Overwatch player database.
12
+
13
+ Note: This checks Overwatch profiles specifically. A username may exist
14
+ on Battle.net but not have an Overwatch profile, or vice versa.
15
+
16
+ API behavior:
17
+ - Returns JSON array with player data if username exists
18
+ - Returns empty array [] if username not found
19
+ """
20
+ # BattleTag username rules: 3-12 chars, letters/numbers, one optional #
21
+ # For this validator, we strip any #1234 discriminator if present
22
+ username = user.split('#')[0]
23
+
24
+ if not (3 <= len(username) <= 12):
25
+ return Result.error("Length must be 3-12 characters")
26
+
27
+ if not re.match(r'^[a-zA-Z][a-zA-Z0-9]*$', username):
28
+ return Result.error("Must start with letter, only letters and numbers allowed")
29
+
30
+ url = f"https://overwatch.blizzard.com/en-us/search/account-by-name/{username}"
31
+
32
+ headers = {
33
+ "User-Agent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Mobile Safari/537.36",
34
+ "Accept": "application/json",
35
+ "Accept-Encoding": "gzip, deflate, br, zstd",
36
+ }
37
+
38
+ def process(response):
39
+ if response.status_code != 200:
40
+ return Result.error(f"Unexpected status: {response.status_code}")
41
+
42
+ try:
43
+ data = response.json()
44
+ if isinstance(data, list) and len(data) == 0:
45
+ return Result.available()
46
+ elif isinstance(data, list) and len(data) > 0:
47
+ return Result.taken()
48
+ else:
49
+ return Result.error("Unexpected response format")
50
+ except Exception:
51
+ return Result.error("Failed to parse response")
52
+
53
+ return generic_validate(url, process, headers=headers, timeout=15.0, follow_redirects=True)
54
+
55
+
56
+ if __name__ == "__main__":
57
+ user = input("Username?: ").strip()
58
+ result = validate_battlenet(user)
59
+
60
+ if result == 1:
61
+ print("Available!")
62
+ elif result == 0:
63
+ print("Unavailable!")
64
+ else:
65
+ print(f"Error occurred! Reason: {result.get_reason()}")
File without changes
@@ -0,0 +1,42 @@
1
+ import difflib
2
+ import re
3
+
4
+ from user_scanner.core.orchestrator import generic_validate
5
+ from user_scanner.core.result import Result
6
+
7
+
8
+ def validate_vinted(user: str):
9
+ user = user.lower().strip()
10
+
11
+ url = f"https://www.vinted.pt/member/general/search?search_text={user}"
12
+
13
+ if not re.match(r"^[a-zA-Z0-9_.-]+$", user):
14
+ return Result.error(
15
+ "Usernames can only contain letters, numbers, underscores, periods and dashes"
16
+ )
17
+
18
+ if user.startswith(("_", "-", ".")) or user.endswith(("_", "-", ".")):
19
+ return Result.error("Cannot start/end with a special character")
20
+
21
+ def process(response):
22
+ if response.status_code != 200:
23
+ return Result.error("Invalid status code")
24
+
25
+ pattern = r"\"login\\\":\\\"([A-Za-z0-9_.-]+)"
26
+ search = re.findall(pattern, response.text)
27
+
28
+ if len(search) == 0:
29
+ return Result.available()
30
+ elif user not in search:
31
+ closest = difflib.get_close_matches(user, search, n=1)
32
+ msg = f"closest: {closest[0]}" if closest else None
33
+ return Result.available(msg)
34
+ else:
35
+ return Result.taken()
36
+
37
+ return generic_validate(url, process)
38
+
39
+
40
+ if __name__ == "__main__":
41
+ user = input("Username?: ").strip()
42
+ validate_vinted(user).show()
user_scanner/version.json CHANGED
@@ -1,4 +1,4 @@
1
1
  {
2
- "version": "1.1.0.1",
2
+ "version": "1.1.0.2",
3
3
  "version_type": "pypi"
4
4
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: user-scanner
3
- Version: 1.1.0.1
3
+ Version: 1.1.0.3
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
  ![User Scanner Logo](https://github.com/user-attachments/assets/49ec8d24-665b-4115-8525-01a8d0ca2ef4)
18
18
  <p align="center">
19
- <img src="https://img.shields.io/badge/Version-1.1.0.1-blueviolet?style=for-the-badge&logo=github" />
19
+ <img src="https://img.shields.io/badge/Version-1.1.0.3-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" />
@@ -26,8 +26,6 @@ Project-URL: Homepage, https://github.com/kaifcodec/user-scanner
26
26
 
27
27
  ---
28
28
 
29
- ### ⚠️ Email OSINT mode had not been implemented yet, still in progress
30
-
31
29
  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
30
 
33
31
  Perfect for fast, accurate and lightweight email OSINT
@@ -54,12 +52,28 @@ Perfect for finding a **unique username** across GitHub, Twitter, Reddit, Instag
54
52
  - ✅ **Bulk email scanning** from file support for checking multiple emails at once
55
53
  ---
56
54
 
57
- ## Installation
55
+ ## Virtual Environment (optional but recommended)
58
56
 
59
57
  ```bash
60
- pip install user-scanner
58
+ # create venv
59
+ python -m venv .venv
60
+ ````
61
+ ## Activate venv
62
+ ```bash
63
+ # Linux / macOS
64
+ source .venv/bin/activate
65
+
66
+ # Windows (PowerShell)
67
+ .venv\Scripts\Activate.ps1
61
68
  ```
69
+ ## Installation
70
+ ```bash
71
+ # upgrade pip
72
+ python -m pip install --upgrade pip
62
73
 
74
+ # install
75
+ pip install user-scanner
76
+ ```
63
77
  ---
64
78
 
65
79
  ## Important Flags
@@ -169,9 +183,11 @@ user-scanner -U
169
183
 
170
184
  - Note*: New modules are constantly getting added so this might have only limited, outdated output:
171
185
 
172
- <img width="1072" height="848" alt="user-scanner's main usage screenshot" src="https://github.com/user-attachments/assets/34e44ca6-e314-419e-9035-d951b493b47f" />
186
+ <img width="1080" height="656" alt="1000146096" src="https://github.com/user-attachments/assets/1101e2f8-18ea-45a4-9492-92e237ecc670" />
173
187
 
188
+ ---
174
189
 
190
+ <img width="1072" height="848" alt="user-scanner's main usage screenshot" src="https://github.com/user-attachments/assets/34e44ca6-e314-419e-9035-d951b493b47f" />
175
191
 
176
192
  ---
177
193
 
@@ -224,6 +240,16 @@ See [CONTRIBUTING.md](CONTRIBUTING.md) for examples.
224
240
 
225
241
  This project is licensed under the **MIT License**. See [LICENSE](LICENSE) for details.
226
242
 
243
+ ---
244
+
245
+ ## ⚠️ Disclaimer
246
+
247
+ This tool is provided for **educational purposes** and **authorized security research** only.
248
+
249
+ - **User Responsibility:** Users are solely responsible for ensuring their usage complies with all applicable laws and the Terms of Service (ToS) of any third-party providers.
250
+ - **Methodology:** The tool interacts only with **publicly accessible, unauthenticated web endpoints**. It does not bypass authentication, security controls, or access private user data.
251
+ - **No Profiling:** This software performs only basic **yes/no availability checks**. It does not collect, store, aggregate, or analyze user data, behavior, or identities.
252
+ - **Limitation of Liability:** The software is provided **“as is”**, without warranty of any kind. The developers assume no liability for misuse or any resulting damage or legal consequences.
227
253
 
228
254
  ---
229
255