Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions user_scanner/user_scan/creator/unsplash.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import re
import html
import httpx
from user_scanner.core.result import Result
from user_scanner.core.orchestrator import make_request

def validate_unsplash(username: str) -> Result:
"""Validate a username on Unsplash."""
url = f"https://unsplash.com/@{username}"
show_url = f"https://unsplash.com/@{username}"

try:
# We pass headers={} to use httpx's default user-agent,
# as Unsplash blocks/redirects the default browser user-agent.
response = make_request(url, headers={}, follow_redirects=True)
response_text = response.text

# Verify status code 200 AND check unique Unsplash strings in the response body to prevent false positives
if response.status_code == 200 and "unsplash" in response_text.lower() and "page not found" not in response_text.lower():
extra = {}
title_match = re.search(r"<title>(.*?)</title>", response_text, re.IGNORECASE)
if title_match:
title = html.unescape(title_match.group(1).strip())
title_clean = title.split(" | ")[0]
match = re.search(r"^(.*?)\s*\((?:@" + re.escape(username) + r")\)", title_clean, re.IGNORECASE)
if match:
name = match.group(1).strip()
name = re.sub(r"'\s*s (?:Collections|Photos|Likes|Stats)$", "", name, flags=re.IGNORECASE)
name = re.sub(r"'\''s (?:Collections|Photos|Likes|Stats)$", "", name, flags=re.IGNORECASE)
extra["name"] = name
return Result.taken(extra=extra, url=show_url)
elif response.status_code == 404 or "page not found" in response_text.lower():
return Result.available(url=show_url)
else:
return Result.error(f"Unexpected status: {response.status_code}", url=show_url)
except httpx.TimeoutException:
return Result.skipped("Connection timed out")
except Exception as e:
return Result.error(e, url=show_url)
33 changes: 33 additions & 0 deletions user_scanner/user_scan/dev/hackerone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import re
import html
import httpx
from user_scanner.core.result import Result
from user_scanner.core import orchestrator

def validate_hackerone(username: str) -> Result:
"""Validate a username on HackerOne."""
url = f"https://hackerone.com/{username}"
show_url = f"https://hackerone.com/{username}"
try:
response = orchestrator.make_request(url, follow_redirects=True)
response_text = response.text

# Verify status code 200 AND check unique HackerOne strings in the response body to prevent false positives
if response.status_code == 200 and "hackerone" in response_text.lower() and f"hackerone.com/{username}" in response_text.lower():
extra = {}
# Extract user bio/description from OpenGraph metadata
bio_match = re.search(r'property="og:description"\s+content="([^"]+)"', response_text, re.IGNORECASE)
if not bio_match:
bio_match = re.search(r'content="([^"]+)"\s+property="og:description"', response_text, re.IGNORECASE)
if bio_match:
bio = html.unescape(bio_match.group(1).strip())
if bio and bio != "-":
extra["bio"] = bio
return Result.taken(extra=extra, url=show_url)
elif response.status_code == 404 or "page not found" in response_text.lower():
return Result.available(url=show_url)
return Result.error(f"Unexpected status: {response.status_code}", url=show_url)
except httpx.TimeoutException:
return Result.skipped("Connection timed out")
except Exception as e:
return Result.error(e, url=show_url)
31 changes: 31 additions & 0 deletions user_scanner/user_scan/dev/wix.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import re
import html
import httpx
from user_scanner.core.result import Result
from user_scanner.core import orchestrator

def validate_wix(username: str) -> Result:
"""Validate a username on Wix."""
url = f"https://{username}.wix.com"
show_url = f"https://{username}.wix.com"
try:
response = orchestrator.make_request(url, follow_redirects=True)
response_text = response.text

# Verify status code 200 AND check unique Wix strings in the response body to prevent false positives
if response.status_code == 200 and "wix" in response_text.lower():
extra = {}
title_match = re.search(r"<title>(.*?)</title>", response_text, re.IGNORECASE)
if title_match:
extra["title"] = html.unescape(title_match.group(1).strip())
return Result.taken(extra=extra, url=show_url)
elif response.status_code == 404:
return Result.available(url=show_url)
return Result.error(f"Unexpected status: {response.status_code}", url=show_url)
except httpx.ConnectError:
# If the domain doesn't resolve at all, it usually means the username/subdomain is available
return Result.available(url=show_url)
except httpx.TimeoutException:
return Result.skipped("Connection timed out")
except Exception as e:
return Result.error(e, url=show_url)
35 changes: 35 additions & 0 deletions user_scanner/user_scan/finance/tradingview.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import re
import html
import httpx
from user_scanner.core.result import Result
from user_scanner.core import orchestrator

def validate_tradingview(username: str) -> Result:
"""Validate a username on TradingView."""
url = f"https://www.tradingview.com/u/{username}/"
show_url = f"https://www.tradingview.com/u/{username}/"
try:
response = orchestrator.make_request(url, follow_redirects=True)
response_text = response.text

# Verify status code 200 AND check unique TradingView strings in the response body to prevent false positives
if response.status_code == 200 and "tradingview" in response_text.lower() and "page not found" not in response_text.lower():
extra = {}
title_match = re.search(r"<title>(.*?)</title>", response_text, re.IGNORECASE)
if title_match:
title = html.unescape(title_match.group(1).strip())
# TradingView format: {Name} — Trading Ideas and Scripts — TradingView
# or {Username} — Trading Ideas and Scripts — TradingView
title_parts = title.split(" — ")
if len(title_parts) > 0:
name = title_parts[0].strip()
if name.lower() != username.lower():
extra["name"] = name
return Result.taken(extra=extra, url=show_url)
elif response.status_code == 404 or "page not found" in response_text.lower():
return Result.available(url=show_url)
return Result.error(f"Unexpected status: {response.status_code}", url=show_url)
except httpx.TimeoutException:
return Result.skipped("Connection timed out")
except Exception as e:
return Result.error(e, url=show_url)
Loading