From abf3f1444b42165181c1b14e3827d089c768f2a2 Mon Sep 17 00:00:00 2001 From: Dev Vishnu Date: Wed, 27 Aug 2025 00:19:00 +0530 Subject: [PATCH 1/3] Added the Url scan --- backend/scripts/security/url_scan.py | 80 ++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 backend/scripts/security/url_scan.py diff --git a/backend/scripts/security/url_scan.py b/backend/scripts/security/url_scan.py new file mode 100644 index 00000000..ed635367 --- /dev/null +++ b/backend/scripts/security/url_scan.py @@ -0,0 +1,80 @@ +import os +import sys +import argparse +import requests +import base64 +import time + + +def scan_url(url: str) -> str: + report = [] + report.append(f"šŸ”Ž Scanning URL: {url}") + + + if url.startswith("https://"): + report.append("āœ… Uses HTTPS (secure protocol).") + else: + report.append("āš ļø Does not use HTTPS (insecure protocol).") + + + if "@" in url or url.count("//") > 1: + report.append("🚨 Suspicious URL structure detected.") + else: + report.append("āœ… URL structure looks normal.") + + + api_key = os.getenv("VT_API_KEY", "") + if not api_key: + report.append("āš ļø VirusTotal check skipped (no API key set).") + return "\n".join(report) + + try: + headers = {"x-apikey": api_key} + + + vt_url = "https://www.virustotal.com/api/v3/urls" + response = requests.post(vt_url, headers=headers, data={"url": url}, timeout=10) + + if response.status_code == 200: + url_id = response.json()["data"]["id"] + + + time.sleep(2) + + + analysis_url = f"https://www.virustotal.com/api/v3/analyses/{url_id}" + analysis_response = requests.get(analysis_url, headers=headers, timeout=10) + + if analysis_response.status_code == 200: + stats = analysis_response.json()["data"]["attributes"]["stats"] + malicious = stats.get("malicious", 0) + suspicious = stats.get("suspicious", 0) + + if malicious > 0 or suspicious > 0: + report.append(f"🚨 VirusTotal: {malicious} malicious, {suspicious} suspicious detections.") + else: + report.append("āœ… VirusTotal: No malicious detections found.") + else: + report.append(f"āš ļø Failed to fetch VirusTotal report (HTTP {analysis_response.status_code}).") + else: + report.append(f"āš ļø Failed to submit URL to VirusTotal (HTTP {response.status_code}).") + + except requests.exceptions.RequestException as e: + report.append(f"āš ļø VirusTotal check error: {e}") + + return "\n".join(report) + + +def main(): + parser = argparse.ArgumentParser(description="URL Scanner Utility") + parser.add_argument("command", choices=["scan"], help="Action to perform") + parser.add_argument("url", help="URL to scan") + args = parser.parse_args() + + if args.command == "scan": + result = scan_url(args.url) + print(result) + + +if __name__ == "__main__": + main() From 7e0798a89da3f55eab9fc67292cc9f4de886b3f3 Mon Sep 17 00:00:00 2001 From: Dev Vishnu Date: Thu, 28 Aug 2025 23:03:32 +0530 Subject: [PATCH 2/3] Added dotenv support and updated url_scan.py --- .gitignore | 5 +++++ backend/scripts/security/url_scan.py | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index 0a197900..d8ecedc4 100644 --- a/.gitignore +++ b/.gitignore @@ -172,3 +172,8 @@ cython_debug/ # PyPI configuration file .pypirc + +# Compression tool logs/config +compress_config.json +compression_log.json +.env diff --git a/backend/scripts/security/url_scan.py b/backend/scripts/security/url_scan.py index ed635367..0431167e 100644 --- a/backend/scripts/security/url_scan.py +++ b/backend/scripts/security/url_scan.py @@ -5,6 +5,12 @@ import base64 import time +from dotenv import load_dotenv +from pathlib import Path +env_path = Path(__file__).resolve().parent / ".env" +load_dotenv(dotenv_path=env_path) +api_key = os.getenv("VT_API_KEY") +print("Loaded API Key:", api_key[:10] + "..." if api_key else "Not found") def scan_url(url: str) -> str: report = [] From a8f610401023032fea9bc845bb296035681a7f86 Mon Sep 17 00:00:00 2001 From: Dev Vishnu Date: Thu, 28 Aug 2025 23:31:51 +0530 Subject: [PATCH 3/3] Enhance URL scanner: improved HTTPS and WHOIS handling --- backend/scripts/security/url_scan.py | 160 ++++++++++++++++----------- 1 file changed, 96 insertions(+), 64 deletions(-) diff --git a/backend/scripts/security/url_scan.py b/backend/scripts/security/url_scan.py index 0431167e..bca6e52a 100644 --- a/backend/scripts/security/url_scan.py +++ b/backend/scripts/security/url_scan.py @@ -1,86 +1,118 @@ -import os import sys -import argparse +import re +import socket +import whois +import os import requests -import base64 -import time - from dotenv import load_dotenv -from pathlib import Path -env_path = Path(__file__).resolve().parent / ".env" -load_dotenv(dotenv_path=env_path) -api_key = os.getenv("VT_API_KEY") -print("Loaded API Key:", api_key[:10] + "..." if api_key else "Not found") - -def scan_url(url: str) -> str: - report = [] - report.append(f"šŸ”Ž Scanning URL: {url}") - - - if url.startswith("https://"): - report.append("āœ… Uses HTTPS (secure protocol).") - else: - report.append("āš ļø Does not use HTTPS (insecure protocol).") +from urllib.parse import urlparse - - if "@" in url or url.count("//") > 1: - report.append("🚨 Suspicious URL structure detected.") - else: - report.append("āœ… URL structure looks normal.") +load_dotenv() +VT_API_KEY = os.getenv("VT_API_KEY") - - api_key = os.getenv("VT_API_KEY", "") - if not api_key: - report.append("āš ļø VirusTotal check skipped (no API key set).") - return "\n".join(report) +def check_https(url): + return url.startswith("https://") +def check_url_structure(url): + pattern = re.compile( + r'^(https?:\/\/)?' # http:// or https:// + r'([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}' # domain + r'(\/\S*)?$' # optional path + ) + return bool(pattern.match(url)) + +def check_domain_info(domain): try: - headers = {"x-apikey": api_key} + info = whois.whois(domain) + registrar = info.registrar or "Unknown" + creation_date = info.creation_date + + # Handle list or single datetime + if isinstance(creation_date, list) and creation_date: + creation_date = creation_date[0] + if hasattr(creation_date, "strftime"): + creation_date = creation_date.strftime("%Y-%m-%d") + else: + creation_date = "Unknown" - - vt_url = "https://www.virustotal.com/api/v3/urls" - response = requests.post(vt_url, headers=headers, data={"url": url}, timeout=10) + return f"āœ… Domain registered: {creation_date} (Registrar: {registrar})" + except Exception as e: + return f"āš ļø WHOIS lookup failed: {e}" - if response.status_code == 200: - url_id = response.json()["data"]["id"] +def check_virustotal(url): + if not VT_API_KEY: + return "āš ļø VirusTotal API key not found." - - time.sleep(2) + api_url = "https://www.virustotal.com/api/v3/urls" + headers = {"x-apikey": VT_API_KEY} + + try: + # Submit URL for scanning + response = requests.post(api_url, headers=headers, data={"url": url}) + if response.status_code != 200: + return f"āš ļø VirusTotal error: {response.status_code}" - - analysis_url = f"https://www.virustotal.com/api/v3/analyses/{url_id}" - analysis_response = requests.get(analysis_url, headers=headers, timeout=10) + # Get analysis ID + analysis_id = response.json()["data"]["id"] - if analysis_response.status_code == 200: - stats = analysis_response.json()["data"]["attributes"]["stats"] - malicious = stats.get("malicious", 0) - suspicious = stats.get("suspicious", 0) + # Fetch analysis results + analysis_url = f"https://www.virustotal.com/api/v3/analyses/{analysis_id}" + result = requests.get(analysis_url, headers=headers).json() - if malicious > 0 or suspicious > 0: - report.append(f"🚨 VirusTotal: {malicious} malicious, {suspicious} suspicious detections.") - else: - report.append("āœ… VirusTotal: No malicious detections found.") - else: - report.append(f"āš ļø Failed to fetch VirusTotal report (HTTP {analysis_response.status_code}).") + stats = result["data"]["attributes"]["stats"] + + if stats["malicious"] > 0: + return f"āŒ VirusTotal: {stats['malicious']} malicious detections found!" else: - report.append(f"āš ļø Failed to submit URL to VirusTotal (HTTP {response.status_code}).") + return "āœ… VirusTotal: No malicious detections found." + except Exception as e: + return f"āš ļø VirusTotal check failed: {e}" + + +def scan_url(url): + parsed = urlparse(url) + domain = parsed.netloc or parsed.path + + report_lines = [ + "=============================================", + " šŸ”Ž URL Security Report", + "=============================================", + f"\nšŸ”Ž Scanning URL: {url}\n" + ] - except requests.exceptions.RequestException as e: - report.append(f"āš ļø VirusTotal check error: {e}") + # HTTPS check + if check_https(url): + report_lines.append("āœ… Uses HTTPS (secure protocol).") + else: + report_lines.append("āŒ Does not use HTTPS (insecure).") - return "\n".join(report) + # Structure check + if check_url_structure(url): + report_lines.append("āœ… URL structure looks normal.") + else: + report_lines.append("āŒ Suspicious-looking URL structure.") + # Domain WHOIS + report_lines.append(check_domain_info(domain)) -def main(): - parser = argparse.ArgumentParser(description="URL Scanner Utility") - parser.add_argument("command", choices=["scan"], help="Action to perform") - parser.add_argument("url", help="URL to scan") - args = parser.parse_args() + # VirusTotal + report_lines.append(check_virustotal(url)) - if args.command == "scan": - result = scan_url(args.url) - print(result) + # Final status + report_lines.append("\n=============================================") + if any("āŒ" in line for line in report_lines): + report_lines.append("šŸ“Š Overall Status: UNSAFE šŸ”“") + elif any("āš ļø" in line for line in report_lines): + report_lines.append("šŸ“Š Overall Status: SAFE (Unverified) 🟔") + else: + report_lines.append("šŸ“Š Overall Status: SAFE 🟢") + report_lines.append("=============================================") + return "\n".join(report_lines) if __name__ == "__main__": - main() + if len(sys.argv) != 2: + print("Usage: python url_scan.py ") + else: + url = sys.argv[1] + print(scan_url(url))