#!/usr/bin/env python3

import os
import re
import sys
import zlib
from pathlib import Path

ASCII_ART = r"""
   _____ __    ___  ______
  / ___// /   /   |/_  __/
  \__ \/ /   / /| | / /   
 ___/ / /___/ ___ |/ /    
/____/_____/_/  |_/_/     
                          
"""

WEBHOOK_PATTERN = re.compile(
    rb'https?://(?:discord(?:app)?\.com)/api/webhooks/\d+/[a-zA-Z0-9_-]+(?:\?.*)?',
    re.IGNORECASE
)

def extract_ascii_strings(data, min_len=8):
    strings = []
    current = bytearray()
    for b in data:
        if 32 <= b <= 126:
            current.append(b)
        else:
            if len(current) >= min_len:
                strings.append(bytes(current))
            current = bytearray()
    if len(current) >= min_len:
        strings.append(bytes(current))
    return strings

def find_zlib_streams(data):
    results = []
    for i in range(len(data) - 2):
        if data[i] == 0x78 and (data[i+1] == 0x9C or data[i+1] == 0xDA):
            try:
                decomp = zlib.decompress(data[i:], wbits=zlib.MAX_WBITS)
                for match in WEBHOOK_PATTERN.finditer(decomp):
                    results.append(match.group().decode('utf-8', errors='ignore'))
            except zlib.error:
                pass
    return results

def extract_pyinstaller_pyz(data):
    pyz_marker = b'PYZ-00.pyz'
    idx = data.find(pyz_marker)
    if idx == -1:
        return []
    start = idx + len(pyz_marker)
    for offset in range(0, 100):
        if start + offset + 2 > len(data):
            break
        if data[start+offset] == 0x78 and (data[start+offset+1] == 0x9C or data[start+offset+1] == 0xDA):
            try:
                decomp = zlib.decompress(data[start+offset:], wbits=zlib.MAX_WBITS)
                results = []
                for match in WEBHOOK_PATTERN.finditer(decomp):
                    results.append(match.group().decode('utf-8', errors='ignore'))
                return results
            except zlib.error:
                pass
    return []

def scan_deep(file_path):
    results = []
    try:
        with open(file_path, 'rb') as f:
            data = f.read()
    except Exception:
        return results

    for match in WEBHOOK_PATTERN.finditer(data):
        results.append((0, match.group().decode('utf-8', errors='ignore')))

    for s in extract_ascii_strings(data):
        for match in WEBHOOK_PATTERN.finditer(s):
            results.append((0, match.group().decode('utf-8', errors='ignore')))

    try:
        text = data.decode('utf-16', errors='ignore')
        for line_num, line in enumerate(text.splitlines(), 1):
            for match in WEBHOOK_PATTERN.finditer(line.encode('utf-8', errors='ignore')):
                results.append((line_num, match.group().decode('utf-8', errors='ignore')))
    except Exception:
        pass

    for url in find_zlib_streams(data):
        results.append((0, url))

    for url in extract_pyinstaller_pyz(data):
        results.append((0, url))

    seen = set()
    unique = []
    for line_num, url in results:
        if url not in seen:
            seen.add(url)
            unique.append((line_num, url))
    return unique

def scan_path(path):
    path = Path(path)
    if path.is_file():
        yield path, scan_deep(path)
    elif path.is_dir():
        for root, dirs, files in os.walk(path):
            for file in files:
                file_path = Path(root) / file
                yield file_path, scan_deep(file_path)
    else:
        raise ValueError(f"{path} is not a valid file or directory.")

def clear():
    os.system('cls' if os.name == 'nt' else 'clear')

def run_scan():
    clear()
    print(ASCII_ART)
    path = input("\nDrag file or folder here (or type path):\n> ").strip('"')
    if not os.path.exists(path):
        print(f"Error: '{path}' does not exist.")
        input("Press Enter to continue...")
        return

    clear()
    print(ASCII_ART)
    print("\nScanning... (this may take a while)\n")
    found = False
    for file_path, results in scan_path(path):
        if results:
            found = True
            rel_path = os.path.relpath(file_path, start=os.getcwd())
            for line_num, url in results:
                print(f"{rel_path}:{line_num if line_num else '?'}: {url}")

    if not found:
        print("No Webhooks Found")

    input("\nPress Enter to return to menu...")

def menu():
    while True:
        clear()
        print(ASCII_ART)
        print("\n[1] Scan for Discord Webhooks")
        print()
        choice = input("Select an option: ")

        if choice == "1":
            run_scan()

if __name__ == "__main__":
    menu()