콘텐츠로 이동

LinkFinder Cheat Sheet

Overview

LinkFinder is a Python script designed to discover endpoints and their parameters in JavaScript files. It's particularly useful for bug bounty hunters and penetration testers who need to find hidden endpoints that might not be documented or easily discoverable through traditional crawling methods. LinkFinder uses regular expressions to extract relative and absolute URLs from JavaScript source code.

💡 Key Features: Endpoint extraction from JavaScript, parameter discovery, relative URL detection, Burp Suite integration, bulk processing capabilities, and comprehensive output formatting.

Installation and Setup

Python Installation

# Clone the repository
git clone https://github.com/GerbenJavado/LinkFinder.git
cd LinkFinder

# Install Python dependencies
pip install -r requirements.txt

# Make the script executable
chmod +x linkfinder.py

# Create symbolic link for global access
sudo ln -s $(pwd)/linkfinder.py /usr/local/bin/linkfinder

# Verify installation
linkfinder --help
python3 linkfinder.py --help

Virtual Environment Setup

# Create virtual environment
python3 -m venv linkfinder-env
source linkfinder-env/bin/activate

# Install dependencies
pip install requests argparse jsbeautifier

# Clone and setup LinkFinder
git clone https://github.com/GerbenJavado/LinkFinder.git
cd LinkFinder
pip install -r requirements.txt

# Test installation
python3 linkfinder.py --help

# Create activation script
cat > activate_linkfinder.sh << 'EOF'
#!/bin/bash
cd /path/to/LinkFinder
source linkfinder-env/bin/activate
python3 linkfinder.py "$@"
EOF

chmod +x activate_linkfinder.sh

Docker Installation

# Create Dockerfile
cat > Dockerfile << 'EOF'
FROM python:3.9-alpine

RUN apk add --no-cache git

WORKDIR /app

RUN git clone https://github.com/GerbenJavado/LinkFinder.git .
RUN pip install -r requirements.txt

ENTRYPOINT ["python3", "linkfinder.py"]
EOF

# Build Docker image
docker build -t linkfinder .

# Run LinkFinder in Docker
docker run --rm linkfinder --help

# Run with volume mount for output
docker run --rm -v $(pwd):/output linkfinder -i /output/script.js -o /output/results.html

# Create alias for easier usage
echo 'alias linkfinder="docker run --rm -v $(pwd):/output linkfinder"' >> ~/.bashrc
source ~/.bashrc

Dependencies and Requirements

# Install required Python packages
pip install requests argparse jsbeautifier colorama

# Install additional useful packages
pip install beautifulsoup4 urllib3 tldextract

# Create requirements file
cat > requirements.txt << 'EOF'
requests>=2.25.1
argparse>=1.4.0
jsbeautifier>=1.14.0
colorama>=0.4.4
beautifulsoup4>=4.9.3
urllib3>=1.26.5
tldextract>=3.1.0
EOF

# Install from requirements
pip install -r requirements.txt

# Verify all dependencies
python3 -c "import requests, argparse, jsbeautifier; print('All dependencies installed successfully')"

Configuration and Setup

# Create configuration directory
mkdir -p ~/.linkfinder

# Create configuration file
cat > ~/.linkfinder/config.json << 'EOF'
{
  "default_options": {
    "timeout": 30,
    "user_agent": "LinkFinder/1.0",
    "max_retries": 3,
    "output_format": "html"
  },
  "regex_patterns": {
    "endpoints": [
      "(?:\"|')(((?:[a-zA-Z]{1,10}://|//)[^\"'/]{1,}\\.[a-zA-Z]{2,}[^\"']{0,})|((?:/|\\.\\./|\\./)[^\"'><,;| *()(%%$^/\\\\\\[\\]][^\"'><,;|()]{1,})|([a-zA-Z0-9_\\-/]{1,}/[a-zA-Z0-9_\\-/]{1,}\\.(?:[a-zA-Z]{1,4}|action)(?:[\\?|#][^\"|']{0,}|))|([a-zA-Z0-9_\\-/]{1,}/[a-zA-Z0-9_\\-/]{3,}(?:[\\?|#][^\"|']{0,}|))|([a-zA-Z0-9_\\-]{1,}\\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:[\\?|#][^\"|']{0,}|)))(?:\"|')"
    ],
    "parameters": [
      "(?:\"|')([a-zA-Z0-9_\\-]+)(?:\"|')\\s*:\\s*(?:\"|')([^\"']+)(?:\"|')",
      "(?:\\?|&)([a-zA-Z0-9_\\-]+)=([^&\\s\"']+)"
    ]
  },
  "output": {
    "save_raw": true,
    "beautify_js": true,
    "create_html": true
  }
}
EOF

# Set environment variables
export LINKFINDER_CONFIG=~/.linkfinder/config.json
export LINKFINDER_OUTPUT=~/.linkfinder/output

Basic Usage and Commands

Single File Analysis

# Basic JavaScript file analysis
linkfinder -i script.js

# Analyze with HTML output
linkfinder -i script.js -o results.html

# Analyze with custom output directory
linkfinder -i script.js -o /path/to/output/

# Analyze with verbose output
linkfinder -i script.js -v

# Analyze and beautify JavaScript
linkfinder -i script.js -b

# Analyze with custom regex
linkfinder -i script.js -r "custom_regex_pattern"

URL-based Analysis

# Analyze JavaScript from URL
linkfinder -i https://example.com/script.js

# Analyze with custom headers
linkfinder -i https://example.com/script.js -H "Authorization: Bearer token123"

# Analyze with custom user agent
linkfinder -i https://example.com/script.js -H "User-Agent: Custom LinkFinder 1.0"

# Analyze with proxy
linkfinder -i https://example.com/script.js --proxy http://127.0.0.1:8080

# Analyze with timeout
linkfinder -i https://example.com/script.js --timeout 60

# Analyze and save raw content
linkfinder -i https://example.com/script.js -o results.html --save-raw

Bulk Analysis

# Analyze multiple files
linkfinder -i script1.js script2.js script3.js -o bulk_results.html

# Analyze from file list
echo -e "https://example.com/script1.js\nhttps://example.com/script2.js" > js_urls.txt
linkfinder -i js_urls.txt -o bulk_analysis.html

# Analyze all JS files in directory
find /path/to/js/files -name "*.js" -exec linkfinder -i {} -o results_{}.html \;

# Analyze with threading (custom script)
cat > bulk_linkfinder.sh << 'EOF'
#!/bin/bash
input_file="$1"
output_dir="$2"
max_jobs="${3:-10}"

mkdir -p "$output_dir"

while read -r url; do
    if [ -n "$url" ]; then
        (
            safe_name=$(echo "$url" | sed 's/[^a-zA-Z0-9]/_/g')
            linkfinder -i "$url" -o "$output_dir/${safe_name}.html"
        ) &

        # Limit concurrent jobs
        while [ $(jobs -r | wc -l) -ge $max_jobs ]; do
            sleep 1
        done
    fi
done < "$input_file"

# Wait for all jobs to complete
wait
EOF

chmod +x bulk_linkfinder.sh
./bulk_linkfinder.sh js_urls.txt results/ 5

Advanced Endpoint Discovery

Custom Pattern Extraction

#!/usr/bin/env python3
# Enhanced LinkFinder with custom patterns and analysis

import re
import json
import requests
import argparse
import threading
import time
from urllib.parse import urljoin, urlparse
from concurrent.futures import ThreadPoolExecutor, as_completed
import os
import jsbeautifier

class AdvancedLinkFinder:
    def __init__(self, config_file=None):
        self.results = []
        self.lock = threading.Lock()
        self.session = requests.Session()

        # Enhanced regex patterns
        self.patterns = {
            'endpoints': [
                # Original LinkFinder pattern
                r'(?:"|\')\s*(((?:[a-zA-Z]{1,10}://|//)[^"\'/]{1,}\.[a-zA-Z]{2,}[^"\']{0,})|((?:/|\.\.\/|\.\/)[^"\'><,;| *()(%%$^/\\\\\\[\\]][^"\'><,;|()]{1,})|([a-zA-Z0-9_\\-/]{1,}/[a-zA-Z0-9_\\-/]{1,}\.(?:[a-zA-Z]{1,4}|action)(?:[\\?|#][^"|\']{0,}|))|([a-zA-Z0-9_\\-/]{1,}/[a-zA-Z0-9_\\-/]{3,}(?:[\\?|#][^"|\']{0,}|))|([a-zA-Z0-9_\\-]{1,}\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:[\\?|#][^"|\']{0,}|)))\s*(?:"|\')',

                # Additional patterns for modern frameworks
                r'(?:fetch|axios|ajax)\s*\(\s*["\']([^"\']+)["\']',
                r'(?:GET|POST|PUT|DELETE|PATCH)\s*["\']([^"\']+)["\']',
                r'(?:href|src|action)\s*=\s*["\']([^"\']+)["\']',
                r'(?:url|endpoint|path)\s*:\s*["\']([^"\']+)["\']',
                r'(?:api|route)\s*\(\s*["\']([^"\']+)["\']',
                r'router\.\w+\s*\(\s*["\']([^"\']+)["\']',
                r'app\.\w+\s*\(\s*["\']([^"\']+)["\']',

                # GraphQL and API patterns
                r'(?:query|mutation)\s*["\']([^"\']+)["\']',
                r'(?:graphql|gql)\s*`([^`]+)`',
                r'(?:endpoint|baseURL)\s*:\s*["\']([^"\']+)["\']',

                # WebSocket patterns
                r'(?:ws|wss)://[^"\'\\s]+',
                r'WebSocket\s*\(\s*["\']([^"\']+)["\']',

                # File upload patterns
                r'(?:upload|file)\s*:\s*["\']([^"\']+)["\']',
                r'FormData\s*\(\s*["\']([^"\']+)["\']'
            ],
            'parameters': [
                r'(?:"|\')\s*([a-zA-Z0-9_\\-]+)\s*(?:"|\')\s*:\s*(?:"|\')\s*([^"\']+)\s*(?:"|\')',
                r'(?:\\?|&)([a-zA-Z0-9_\\-]+)=([^&\\s"\']+)',
                r'(?:param|parameter|arg)\s*:\s*["\']([^"\']+)["\']',
                r'(?:data|body)\s*\[\s*["\']([^"\']+)["\']',
                r'getElementById\s*\(\s*["\']([^"\']+)["\']',
                r'querySelector\s*\(\s*["\']([^"\']+)["\']',
                r'name\s*=\s*["\']([^"\']+)["\']',
                r'id\s*=\s*["\']([^"\']+)["\']'
            ],
            'secrets': [
                r'(?i)(api[_\\-]?key|apikey)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{10,})["\']',
                r'(?i)(secret|password|pwd)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{8,})["\']',
                r'(?i)(token|auth)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{10,})["\']',
                r'(?i)(access[_\\-]?token)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{10,})["\']',
                r'(?i)(client[_\\-]?secret)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{10,})["\']',
                r'(?i)(private[_\\-]?key)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{10,})["\']'
            ],
            'domains': [
                r'(?:https?://)?([a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,})',
                r'(?:"|\')\s*([a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,})\s*(?:"|\')',
                r'(?:subdomain|host|domain)\s*:\s*["\']([a-zA-Z0-9.-]+)["\']'
            ],
            'comments': [
                r'/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/',
                r'//.*$'
            ]
        }

        # Load custom configuration if provided
        if config_file and os.path.exists(config_file):
            with open(config_file, 'r') as f:
                config = json.load(f)
                if 'regex_patterns' in config:
                    self.patterns.update(config['regex_patterns'])

    def analyze_javascript_file(self, input_source, beautify=False):
        """Analyze JavaScript file or URL for endpoints and parameters"""

        results = {
            'source': input_source,
            'endpoints': [],
            'parameters': [],
            'secrets': [],
            'domains': [],
            'comments': [],
            'analysis': {
                'total_lines': 0,
                'minified': False,
                'obfuscated': False,
                'framework_detected': [],
                'api_calls': 0,
                'external_requests': 0
            }
        }

        try:
            # Get JavaScript content
            if input_source.startswith(('http://', 'https://')):
                content = self._fetch_from_url(input_source)
                results['source_type'] = 'url'
            else:
                content = self._read_from_file(input_source)
                results['source_type'] = 'file'

            if not content:
                results['error'] = 'Failed to retrieve content'
                return results

            # Beautify if requested
            if beautify:
                try:
                    content = jsbeautifier.beautify(content)
                    results['beautified'] = True
                except:
                    results['beautified'] = False

            # Analyze content
            results['analysis'] = self._analyze_content(content)

            # Extract patterns
            for pattern_type, patterns in self.patterns.items():
                if pattern_type in results:
                    for pattern in patterns:
                        matches = re.findall(pattern, content, re.MULTILINE | re.IGNORECASE)
                        if matches:
                            for match in matches:
                                # Handle tuple results from groups
                                if isinstance(match, tuple):
                                    match = next((m for m in match if m), match[0])

                                if match and match not in results[pattern_type]:
                                    results[pattern_type].append(match)

            # Clean and validate results
            results = self._clean_results(results, input_source)

        except Exception as e:
            results['error'] = str(e)

        return results

    def _fetch_from_url(self, url):
        """Fetch JavaScript content from URL"""

        try:
            response = self.session.get(url, timeout=30)
            response.raise_for_status()
            return response.text
        except Exception as e:
            print(f"Error fetching {url}: {e}")
            return None

    def _read_from_file(self, file_path):
        """Read JavaScript content from file"""

        try:
            with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
                return f.read()
        except Exception as e:
            print(f"Error reading {file_path}: {e}")
            return None

    def _analyze_content(self, content):
        """Analyze JavaScript content characteristics"""

        analysis = {
            'total_lines': len(content.split('\n')),
            'minified': False,
            'obfuscated': False,
            'framework_detected': [],
            'api_calls': 0,
            'external_requests': 0,
            'eval_usage': 0,
            'document_write': 0
        }

        # Check for minification
        if '\n' not in content[:1000] and len(content) > 1000:
            analysis['minified'] = True

        # Check for obfuscation
        if re.search(r'\\x[0-9a-fA-F]{2}', content) or len(re.findall(r'[a-zA-Z_$][a-zA-Z0-9_$]*', content)) < len(content) / 20:
            analysis['obfuscated'] = True

        # Detect frameworks
        frameworks = {
            'React': ['React', 'react', 'ReactDOM', 'jsx'],
            'Vue': ['Vue', 'vue', 'v-if', 'v-for'],
            'Angular': ['angular', 'ng-', '@angular', 'Angular'],
            'jQuery': ['jQuery', '$', 'jquery'],
            'Express': ['express', 'app.get', 'app.post'],
            'Next.js': ['next', 'Next', '_next'],
            'Nuxt.js': ['nuxt', 'Nuxt', '_nuxt'],
            'Svelte': ['svelte', 'Svelte'],
            'Ember': ['ember', 'Ember'],
            'Backbone': ['backbone', 'Backbone'],
            'D3': ['d3', 'D3'],
            'Lodash': ['lodash', '_'],
            'Moment': ['moment', 'Moment'],
            'Axios': ['axios', 'Axios'],
            'Socket.io': ['socket.io', 'io(']
        }

        for framework, indicators in frameworks.items():
            if any(indicator in content for indicator in indicators):
                analysis['framework_detected'].append(framework)

        # Count specific patterns
        analysis['api_calls'] = len(re.findall(r'(?:fetch|axios|ajax|XMLHttpRequest)', content, re.IGNORECASE))
        analysis['external_requests'] = len(re.findall(r'https?://(?!(?:localhost|127\.0\.0\.1|0\.0\.0\.0))', content))
        analysis['eval_usage'] = len(re.findall(r'\\beval\\s*\\(', content))
        analysis['document_write'] = len(re.findall(r'document\\.write', content))

        return analysis

    def _clean_results(self, results, source_url):
        """Clean and validate extracted results"""

        # Clean endpoints
        cleaned_endpoints = []
        for endpoint in results['endpoints']:
            endpoint = endpoint.strip('\'"')

            # Skip if too short or contains invalid characters
            if len(endpoint) < 2 or any(char in endpoint for char in ['<', '>', '{', '}', '\n', '\t']):
                continue

            # Convert relative URLs to absolute if source URL is provided
            if source_url and source_url.startswith(('http://', 'https://')) and not endpoint.startswith(('http://', 'https://')):
                if endpoint.startswith('/'):
                    base_url = f"{urlparse(source_url).scheme}://{urlparse(source_url).netloc}"
                    endpoint = urljoin(base_url, endpoint)
                else:
                    endpoint = urljoin(source_url, endpoint)

            if endpoint not in cleaned_endpoints:
                cleaned_endpoints.append(endpoint)

        results['endpoints'] = cleaned_endpoints

        # Clean parameters
        cleaned_parameters = []
        for param in results['parameters']:
            if isinstance(param, tuple):
                param = param[0] if param[0] else param[1] if len(param) > 1 else ''

            param = param.strip('\'"')
            if len(param) > 0 and (param.isalnum() or '_' in param or '-' in param):
                if param not in cleaned_parameters:
                    cleaned_parameters.append(param)

        results['parameters'] = cleaned_parameters

        # Clean secrets
        cleaned_secrets = []
        for secret in results['secrets']:
            if isinstance(secret, tuple) and len(secret) >= 2:
                key, value = secret[0], secret[1]
                if value.lower() not in ['password', 'secret', 'token', 'key', 'null', 'undefined']:
                    cleaned_secrets.append({'type': key, 'value': value})

        results['secrets'] = cleaned_secrets

        # Clean domains
        cleaned_domains = []
        for domain in results['domains']:
            domain = domain.strip('\'"')
            if '.' in domain and len(domain) > 3:
                if domain not in cleaned_domains:
                    cleaned_domains.append(domain)

        results['domains'] = cleaned_domains

        return results

    def bulk_analyze(self, input_list, max_workers=10, beautify=False):
        """Analyze multiple JavaScript files/URLs in parallel"""

        print(f"Starting bulk analysis of {len(input_list)} targets")
        print(f"Max workers: {max_workers}")

        with ThreadPoolExecutor(max_workers=max_workers) as executor:
            # Submit all tasks
            future_to_input = {
                executor.submit(self.analyze_javascript_file, input_source, beautify): input_source 
                for input_source in input_list
            }

            # Process completed tasks
            for future in as_completed(future_to_input):
                input_source = future_to_input[future]
                try:
                    result = future.result()

                    with self.lock:
                        self.results.append(result)

                    if 'error' not in result:
                        endpoint_count = len(result['endpoints'])
                        param_count = len(result['parameters'])
                        secret_count = len(result['secrets'])
                        print(f"✓ {input_source}: {endpoint_count} endpoints, {param_count} parameters, {secret_count} secrets")
                    else:
                        print(f"✗ {input_source}: {result['error']}")

                except Exception as e:
                    print(f"✗ Error analyzing {input_source}: {e}")

        return self.results

    def generate_html_report(self, output_file='linkfinder_report.html'):
        """Generate HTML report similar to original LinkFinder"""

        # Calculate statistics
        total_endpoints = sum(len(r.get('endpoints', [])) for r in self.results)
        total_parameters = sum(len(r.get('parameters', [])) for r in self.results)
        total_secrets = sum(len(r.get('secrets', [])) for r in self.results)

        # Aggregate unique findings
        all_endpoints = []
        all_parameters = []
        all_domains = []

        for result in self.results:
            all_endpoints.extend(result.get('endpoints', []))
            all_parameters.extend(result.get('parameters', []))
            all_domains.extend(result.get('domains', []))

        unique_endpoints = sorted(list(set(all_endpoints)))
        unique_parameters = sorted(list(set(all_parameters)))
        unique_domains = sorted(list(set(all_domains)))

        # Generate HTML content
        html_content = f"""
<!DOCTYPE html>
<html>
<head>
    <title>LinkFinder Analysis Report</title>
    <style>
        body {{ font-family: Arial, sans-serif; margin: 20px; background-color: #f5f5f5; }}
        .header {{ background-color: #2c3e50; color: white; padding: 20px; border-radius: 5px; margin-bottom: 20px; }}
        .stats {{ display: flex; justify-content: space-around; margin: 20px 0; }}
        .stat-box {{ background-color: white; padding: 15px; border-radius: 5px; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
        .section {{ background-color: white; margin: 20px 0; padding: 20px; border-radius: 5px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }}
        .endpoint {{ margin: 5px 0; padding: 8px; background-color: #ecf0f1; border-left: 4px solid #3498db; }}
        .parameter {{ margin: 5px 0; padding: 8px; background-color: #e8f5e8; border-left: 4px solid #27ae60; }}
        .secret {{ margin: 5px 0; padding: 8px; background-color: #fdf2e9; border-left: 4px solid #e67e22; }}
        .domain {{ margin: 5px 0; padding: 8px; background-color: #f4ecf7; border-left: 4px solid #8e44ad; }}
        table {{ width: 100%; border-collapse: collapse; margin: 10px 0; }}
        th, td {{ border: 1px solid #ddd; padding: 8px; text-align: left; }}
        th {{ background-color: #34495e; color: white; }}
        .toggle-btn {{ background-color: #3498db; color: white; border: none; padding: 5px 10px; cursor: pointer; border-radius: 3px; }}
        .hidden {{ display: none; }}
    </style>
    <script>
        function toggleSection(id) {{
            var element = document.getElementById(id);
            element.classList.toggle('hidden');
        }}
    </script>
</head>
<body>
    <div class="header">
        <h1>LinkFinder Analysis Report</h1>
        <p>Generated on: {time.strftime('%Y-%m-%d %H:%M:%S')}</p>
        <p>Files analyzed: {len(self.results)}</p>
    </div>

    <div class="stats">
        <div class="stat-box">
            <h3>{total_endpoints}</h3>
            <p>Total Endpoints</p>
        </div>
        <div class="stat-box">
            <h3>{len(unique_endpoints)}</h3>
            <p>Unique Endpoints</p>
        </div>
        <div class="stat-box">
            <h3>{total_parameters}</h3>
            <p>Total Parameters</p>
        </div>
        <div class="stat-box">
            <h3>{len(unique_parameters)}</h3>
            <p>Unique Parameters</p>
        </div>
        <div class="stat-box">
            <h3>{total_secrets}</h3>
            <p>Secrets Found</p>
        </div>
    </div>

    <div class="section">
        <h2>Unique Endpoints <button class="toggle-btn" onclick="toggleSection('endpoints')">Toggle</button></h2>
        <div id="endpoints">
"""

        for endpoint in unique_endpoints[:100]:  # Show first 100
            html_content += f'            <div class="endpoint">{endpoint}</div>\n'

        if len(unique_endpoints) > 100:
            html_content += f'            <p><em>... and {len(unique_endpoints) - 100} more endpoints</em></p>\n'

        html_content += """
        </div>
    </div>

    <div class="section">
        <h2>Unique Parameters <button class="toggle-btn" onclick="toggleSection('parameters')">Toggle</button></h2>
        <div id="parameters">
"""

        for param in unique_parameters[:50]:  # Show first 50
            html_content += f'            <div class="parameter">{param}</div>\n'

        if len(unique_parameters) > 50:
            html_content += f'            <p><em>... and {len(unique_parameters) - 50} more parameters</em></p>\n'

        html_content += """
        </div>
    </div>

    <div class="section">
        <h2>Detailed Results <button class="toggle-btn" onclick="toggleSection('detailed')">Toggle</button></h2>
        <div id="detailed">
            <table>
                <tr>
                    <th>Source</th>
                    <th>Type</th>
                    <th>Endpoints</th>
                    <th>Parameters</th>
                    <th>Secrets</th>
                    <th>Framework</th>
                </tr>
"""

        for result in self.results:
            source = result.get('source', 'Unknown')
            source_type = result.get('source_type', 'unknown')
            endpoint_count = len(result.get('endpoints', []))
            param_count = len(result.get('parameters', []))
            secret_count = len(result.get('secrets', []))
            frameworks = ', '.join(result.get('analysis', {}).get('framework_detected', []))

            html_content += f"""
                <tr>
                    <td>{source}</td>
                    <td>{source_type}</td>
                    <td>{endpoint_count}</td>
                    <td>{param_count}</td>
                    <td>{secret_count}</td>
                    <td>{frameworks}</td>
                </tr>
"""

        html_content += """
            </table>
        </div>
    </div>
</body>
</html>
"""

        # Save HTML report
        with open(output_file, 'w') as f:
            f.write(html_content)

        print(f"HTML report generated: {output_file}")
        return output_file

    def generate_json_report(self, output_file='linkfinder_report.json'):
        """Generate JSON report with all findings"""

        # Calculate statistics
        total_endpoints = sum(len(r.get('endpoints', [])) for r in self.results)
        total_parameters = sum(len(r.get('parameters', [])) for r in self.results)
        total_secrets = sum(len(r.get('secrets', [])) for r in self.results)

        # Aggregate unique findings
        all_endpoints = []
        all_parameters = []
        all_domains = []

        for result in self.results:
            all_endpoints.extend(result.get('endpoints', []))
            all_parameters.extend(result.get('parameters', []))
            all_domains.extend(result.get('domains', []))

        unique_endpoints = sorted(list(set(all_endpoints)))
        unique_parameters = sorted(list(set(all_parameters)))
        unique_domains = sorted(list(set(all_domains)))

        report = {
            'scan_summary': {
                'total_files': len(self.results),
                'scan_date': time.strftime('%Y-%m-%d %H:%M:%S'),
                'total_endpoints': total_endpoints,
                'unique_endpoints': len(unique_endpoints),
                'total_parameters': total_parameters,
                'unique_parameters': len(unique_parameters),
                'total_secrets': total_secrets,
                'unique_domains': len(unique_domains)
            },
            'unique_findings': {
                'endpoints': unique_endpoints,
                'parameters': unique_parameters,
                'domains': unique_domains
            },
            'detailed_results': self.results
        }

        # Save JSON report
        with open(output_file, 'w') as f:
            json.dump(report, f, indent=2)

        print(f"JSON report generated: {output_file}")
        return output_file

# Usage example
if __name__ == "__main__":
    # Create LinkFinder instance
    linkfinder = AdvancedLinkFinder()

    # Analyze single file
    result = linkfinder.analyze_javascript_file('example.js', beautify=True)
    print(json.dumps(result, indent=2))

    # Bulk analysis
    targets = [
        'https://example.com/script1.js',
        'https://example.com/script2.js',
        'local_script.js'
    ]

    results = linkfinder.bulk_analyze(targets, max_workers=5, beautify=True)

    # Generate reports
    linkfinder.generate_html_report('comprehensive_linkfinder_report.html')
    linkfinder.generate_json_report('comprehensive_linkfinder_report.json')

Automated Endpoint Discovery

#!/bin/bash
# Comprehensive endpoint discovery using LinkFinder

TARGET_DOMAIN="$1"
OUTPUT_DIR="$2"

if [ -z "$TARGET_DOMAIN" ] || [ -z "$OUTPUT_DIR" ]; then
    echo "Usage: $0 <target_domain> <output_dir>"
    exit 1
fi

echo "Starting comprehensive endpoint discovery for: $TARGET_DOMAIN"
echo "Output directory: $OUTPUT_DIR"

mkdir -p "$OUTPUT_DIR"

# Step 1: Discover JavaScript files using multiple methods
echo "Step 1: Discovering JavaScript files..."

# Method 1: Wayback Machine
echo "Collecting JS files from Wayback Machine..."
echo "$TARGET_DOMAIN" | waybackurls | grep -E "\\.js(\$|\\?)" | sort -u > "$OUTPUT_DIR/wayback_js.txt"

# Method 2: Common crawling
echo "Collecting JS files with gau..."
echo "$TARGET_DOMAIN" | gau | grep -E "\\.js(\$|\\?)" | sort -u > "$OUTPUT_DIR/gau_js.txt"

# Method 3: Hakrawler
echo "Collecting JS files with hakrawler..."
echo "https://$TARGET_DOMAIN" | hakrawler -js -depth 3 | sort -u > "$OUTPUT_DIR/hakrawler_js.txt"

# Method 4: Subfinder + httpx + JS discovery
echo "Discovering subdomains and their JS files..."
subfinder -d "$TARGET_DOMAIN" -silent | httpx -silent | while read url; do
    curl -s "$url" | grep -oE 'src="[^"]*\\.js[^"]*"' | sed 's/src="//g' | sed 's/"//g' | while read js_path; do
        if [[ "$js_path" == /* ]]; then
            echo "$url$js_path"
        elif [[ "$js_path" == http* ]]; then
            echo "$js_path"
        else
            echo "$url/$js_path"
        fi
    done
done | sort -u > "$OUTPUT_DIR/subdomain_js.txt"

# Method 5: Directory bruteforcing for common JS files
echo "Bruteforcing common JS file paths..."
cat > "$OUTPUT_DIR/common_js_paths.txt" << 'EOF'
/js/app.js
/js/main.js
/js/bundle.js
/js/vendor.js
/js/chunk.js
/assets/js/app.js
/assets/js/main.js
/static/js/main.js
/static/js/app.js
/dist/js/app.js
/build/js/main.js
/_next/static/chunks/main.js
/_nuxt/app.js
/wp-content/themes/*/js/main.js
/wp-includes/js/jquery/jquery.js
EOF

while read js_path; do
    url="https://$TARGET_DOMAIN$js_path"
    if curl -s -I "$url" | grep -q "200 OK"; then
        echo "$url"
    fi
done < "$OUTPUT_DIR/common_js_paths.txt" > "$OUTPUT_DIR/bruteforce_js.txt"

# Combine all JS file sources
cat "$OUTPUT_DIR"/*_js.txt | sort -u > "$OUTPUT_DIR/all_js_files.txt"
JS_COUNT=$(wc -l < "$OUTPUT_DIR/all_js_files.txt")

echo "Found $JS_COUNT JavaScript files total"

# Step 2: Analyze JavaScript files with LinkFinder
echo "Step 2: Analyzing JavaScript files with LinkFinder..."

mkdir -p "$OUTPUT_DIR/linkfinder_results"

# Process each JS file
counter=0
while read -r js_url; do
    if [ -n "$js_url" ]; then
        counter=$((counter + 1))
        echo "[$counter/$JS_COUNT] Analyzing: $js_url"

        # Create safe filename
        safe_filename=$(echo "$js_url" | sed 's/[^a-zA-Z0-9]/_/g')

        # Run LinkFinder
        timeout 60 linkfinder -i "$js_url" -o "$OUTPUT_DIR/linkfinder_results/${safe_filename}.html" 2>/dev/null

        # Also extract endpoints to text file
        timeout 60 linkfinder -i "$js_url" 2>/dev/null | grep -oE 'https?://[^"'\''\\s<>]+' > "$OUTPUT_DIR/linkfinder_results/${safe_filename}_endpoints.txt" 2>/dev/null
        timeout 60 linkfinder -i "$js_url" 2>/dev/null | grep -oE '/[^"'\''\\s<>]+' >> "$OUTPUT_DIR/linkfinder_results/${safe_filename}_endpoints.txt" 2>/dev/null
    fi
done < "$OUTPUT_DIR/all_js_files.txt"

# Step 3: Aggregate and analyze results
echo "Step 3: Aggregating results..."

# Combine all endpoints
find "$OUTPUT_DIR/linkfinder_results" -name "*_endpoints.txt" -exec cat {} \; | sort -u > "$OUTPUT_DIR/all_endpoints.txt"

# Separate absolute and relative URLs
grep -E '^https?://' "$OUTPUT_DIR/all_endpoints.txt" > "$OUTPUT_DIR/absolute_endpoints.txt"
grep -E '^/' "$OUTPUT_DIR/all_endpoints.txt" | grep -v '^//' > "$OUTPUT_DIR/relative_endpoints.txt"

# Extract API endpoints
grep -iE '(api|endpoint|/v[0-9]|graphql|rest)' "$OUTPUT_DIR/all_endpoints.txt" > "$OUTPUT_DIR/api_endpoints.txt"

# Extract admin/sensitive endpoints
grep -iE '(admin|dashboard|panel|config|debug|test|dev|staging)' "$OUTPUT_DIR/all_endpoints.txt" > "$OUTPUT_DIR/sensitive_endpoints.txt"

# Extract file extensions
grep -oE '\\.[a-zA-Z0-9]+(\$|\\?)' "$OUTPUT_DIR/all_endpoints.txt" | cut -d'?' -f1 | sort | uniq -c | sort -nr > "$OUTPUT_DIR/file_extensions.txt"

# Extract parameters
grep -oE '\\?[^\\s"'\''<>]+' "$OUTPUT_DIR/all_endpoints.txt" | sed 's/?//' | sed 's/&/\\n/g' | cut -d'=' -f1 | sort -u > "$OUTPUT_DIR/parameters.txt"

# Step 4: Validate endpoints
echo "Step 4: Validating endpoints..."

# Test relative endpoints against target domain
mkdir -p "$OUTPUT_DIR/validated"

echo "Testing relative endpoints..."
head -100 "$OUTPUT_DIR/relative_endpoints.txt" | while read endpoint; do
    if [ -n "$endpoint" ]; then
        test_url="https://$TARGET_DOMAIN$endpoint"
        status_code=$(curl -s -o /dev/null -w "%{http_code}" "$test_url" --max-time 10)

        if [ "$status_code" = "200" ]; then
            echo "$test_url" >> "$OUTPUT_DIR/validated/live_endpoints.txt"
            echo "✓ $test_url (200)"
        elif [ "$status_code" = "403" ] || [ "$status_code" = "401" ]; then
            echo "$test_url" >> "$OUTPUT_DIR/validated/protected_endpoints.txt"
            echo "⚠ $test_url ($status_code)"
        fi
    fi
done

# Test absolute endpoints
echo "Testing absolute endpoints..."
head -50 "$OUTPUT_DIR/absolute_endpoints.txt" | while read endpoint; do
    if [ -n "$endpoint" ]; then
        status_code=$(curl -s -o /dev/null -w "%{http_code}" "$endpoint" --max-time 10)

        if [ "$status_code" = "200" ]; then
            echo "$endpoint" >> "$OUTPUT_DIR/validated/live_absolute_endpoints.txt"
            echo "✓ $endpoint (200)"
        fi
    fi
done

# Step 5: Generate comprehensive report
echo "Step 5: Generating comprehensive report..."

TOTAL_ENDPOINTS=$(wc -l < "$OUTPUT_DIR/all_endpoints.txt")
ABSOLUTE_COUNT=$(wc -l < "$OUTPUT_DIR/absolute_endpoints.txt")
RELATIVE_COUNT=$(wc -l < "$OUTPUT_DIR/relative_endpoints.txt")
API_COUNT=$(wc -l < "$OUTPUT_DIR/api_endpoints.txt")
SENSITIVE_COUNT=$(wc -l < "$OUTPUT_DIR/sensitive_endpoints.txt")
PARAM_COUNT=$(wc -l < "$OUTPUT_DIR/parameters.txt")
LIVE_COUNT=$(wc -l < "$OUTPUT_DIR/validated/live_endpoints.txt" 2>/dev/null || echo "0")
PROTECTED_COUNT=$(wc -l < "$OUTPUT_DIR/validated/protected_endpoints.txt" 2>/dev/null || echo "0")

cat > "$OUTPUT_DIR/discovery_report.txt" << EOF
LinkFinder Endpoint Discovery Report
===================================
Target Domain: $TARGET_DOMAIN
Discovery Date: $(date)
Analysis Duration: $(date -d@$SECONDS -u +%H:%M:%S)

JavaScript Files Analyzed: $JS_COUNT files

Endpoint Discovery Results:
- Total Endpoints Found: $TOTAL_ENDPOINTS
- Absolute URLs: $ABSOLUTE_COUNT
- Relative Paths: $RELATIVE_COUNT
- API Endpoints: $API_COUNT
- Sensitive Endpoints: $SENSITIVE_COUNT
- Unique Parameters: $PARAM_COUNT

Validation Results:
- Live Endpoints (200): $LIVE_COUNT
- Protected Endpoints (401/403): $PROTECTED_COUNT

Top 10 File Extensions:
$(head -10 "$OUTPUT_DIR/file_extensions.txt")

Top 20 Endpoints:
$(head -20 "$OUTPUT_DIR/all_endpoints.txt")

Top 20 Parameters:
$(head -20 "$OUTPUT_DIR/parameters.txt")

Sensitive Endpoints Found:
$(head -10 "$OUTPUT_DIR/sensitive_endpoints.txt")

API Endpoints Found:
$(head -10 "$OUTPUT_DIR/api_endpoints.txt")
EOF

# Create summary files for easy access
echo "Creating summary files..."

# High-value targets
cat > "$OUTPUT_DIR/high_value_targets.txt" << EOF
# High-Value Targets for Manual Testing

## Live Endpoints (Confirmed 200 responses)
$(cat "$OUTPUT_DIR/validated/live_endpoints.txt" 2>/dev/null || echo "None validated")

## Protected Endpoints (401/403 - potential bypass targets)
$(cat "$OUTPUT_DIR/validated/protected_endpoints.txt" 2>/dev/null || echo "None found")

## API Endpoints (potential for injection/logic flaws)
$(head -20 "$OUTPUT_DIR/api_endpoints.txt")

## Sensitive Endpoints (admin/debug/config paths)
$(head -20 "$OUTPUT_DIR/sensitive_endpoints.txt")

## Interesting Parameters (potential for parameter pollution/injection)
$(head -30 "$OUTPUT_DIR/parameters.txt")
EOF

echo "Discovery completed successfully!"
echo ""
echo "📊 Summary:"
echo "  JavaScript files analyzed: $JS_COUNT"
echo "  Total endpoints discovered: $TOTAL_ENDPOINTS"
echo "  API endpoints: $API_COUNT"
echo "  Sensitive endpoints: $SENSITIVE_COUNT"
echo "  Live endpoints validated: $LIVE_COUNT"
echo ""
echo "📁 Output files:"
echo "  Main report: $OUTPUT_DIR/discovery_report.txt"
echo "  All endpoints: $OUTPUT_DIR/all_endpoints.txt"
echo "  High-value targets: $OUTPUT_DIR/high_value_targets.txt"
echo "  LinkFinder HTML reports: $OUTPUT_DIR/linkfinder_results/"
echo ""
echo "🎯 Next steps:"
echo "  1. Review high-value targets for manual testing"
echo "  2. Test API endpoints for injection vulnerabilities"
echo "  3. Attempt to access protected endpoints"
echo "  4. Fuzz parameters for additional attack vectors"

Integration with Security Tools

Burp Suite Extension

#!/usr/bin/env python3
# Burp Suite extension for LinkFinder integration

from burp import IBurpExtender, IHttpListener, ITab, IContextMenuFactory, IContextMenuInvocation
from javax.swing import JPanel, JButton, JTextArea, JScrollPane, JLabel, JTextField
from java.awt import BorderLayout, GridLayout, FlowLayout
from java.awt.event import ActionListener
import json
import re
import threading

class BurpExtender(IBurpExtender, IHttpListener, ITab, IContextMenuFactory):
    def registerExtenderCallbacks(self, callbacks):
        self._callbacks = callbacks
        self._helpers = callbacks.getHelpers()

        callbacks.setExtensionName("LinkFinder Integration")
        callbacks.registerHttpListener(self)
        callbacks.registerContextMenuFactory(self)

        # Create UI
        self._create_ui()
        callbacks.addSuiteTab(self)

        # Storage for results
        self._results = []

        print("LinkFinder Integration loaded successfully")

    def _create_ui(self):
        self._main_panel = JPanel(BorderLayout())

        # Control panel
        control_panel = JPanel(GridLayout(3, 2))

        # Auto-analysis toggle
        self._auto_analyze = JButton("Enable Auto-Analysis", actionPerformed=self._toggle_auto_analysis)
        self._auto_enabled = False

        # Manual analysis button
        self._analyze_button = JButton("Analyze Selected", actionPerformed=self._analyze_selected)

        # Clear results button
        self._clear_button = JButton("Clear Results", actionPerformed=self._clear_results)

        # Export results button
        self._export_button = JButton("Export Results", actionPerformed=self._export_results)

        # URL filter
        self._url_filter = JTextField("Filter URLs (regex)")

        # Status label
        self._status_label = JLabel("Ready")

        control_panel.add(self._auto_analyze)
        control_panel.add(self._analyze_button)
        control_panel.add(self._clear_button)
        control_panel.add(self._export_button)
        control_panel.add(JLabel("URL Filter:"))
        control_panel.add(self._url_filter)

        # Results area
        self._results_area = JTextArea(25, 100)
        self._results_area.setEditable(False)
        results_scroll = JScrollPane(self._results_area)

        # Status panel
        status_panel = JPanel(FlowLayout())
        status_panel.add(self._status_label)

        # Add components
        self._main_panel.add(control_panel, BorderLayout.NORTH)
        self._main_panel.add(results_scroll, BorderLayout.CENTER)
        self._main_panel.add(status_panel, BorderLayout.SOUTH)

    def getTabCaption(self):
        return "LinkFinder"

    def getUiComponent(self):
        return self._main_panel

    def createMenuItems(self, invocation):
        # Context menu for right-click analysis
        menu_items = []

        if invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_EDITOR_REQUEST or \
           invocation.getInvocationContext() == IContextMenuInvocation.CONTEXT_MESSAGE_VIEWER_RESPONSE:

            menu_item = JMenuItem("Analyze with LinkFinder", actionPerformed=lambda x: self._analyze_context_menu(invocation))
            menu_items.append(menu_item)

        return menu_items

    def processHttpMessage(self, toolFlag, messageIsRequest, messageInfo):
        # Auto-analyze JavaScript responses if enabled
        if self._auto_enabled and not messageIsRequest:
            response = messageInfo.getResponse()
            if response:
                response_info = self._helpers.analyzeResponse(response)
                headers = response_info.getHeaders()

                # Check if response is JavaScript
                content_type = ""
                for header in headers:
                    if header.lower().startswith("content-type:"):
                        content_type = header.lower()
                        break

                if "javascript" in content_type or "application/js" in content_type:
                    # Check URL filter
                    url = str(messageInfo.getUrl())
                    url_filter = self._url_filter.getText()

                    if not url_filter or re.search(url_filter, url):
                        # Analyze in background thread
                        thread = threading.Thread(target=self._analyze_response, args=(messageInfo,))
                        thread.daemon = True
                        thread.start()

    def _toggle_auto_analysis(self, event):
        self._auto_enabled = not self._auto_enabled
        if self._auto_enabled:
            self._auto_analyze.setText("Disable Auto-Analysis")
            self._status_label.setText("Auto-analysis enabled")
        else:
            self._auto_analyze.setText("Enable Auto-Analysis")
            self._status_label.setText("Auto-analysis disabled")

    def _analyze_selected(self, event):
        # Analyze selected request/response
        selected_messages = self._callbacks.getSelectedMessages()

        if not selected_messages:
            self._status_label.setText("No request/response selected")
            return

        self._status_label.setText("Analyzing selected messages...")

        # Analyze in background thread
        thread = threading.Thread(target=self._analyze_messages, args=(selected_messages,))
        thread.daemon = True
        thread.start()

    def _analyze_context_menu(self, invocation):
        # Analyze from context menu
        messages = invocation.getSelectedMessages()
        if messages:
            thread = threading.Thread(target=self._analyze_messages, args=(messages,))
            thread.daemon = True
            thread.start()

    def _analyze_messages(self, messages):
        for message in messages:
            self._analyze_response(message)

        self._status_label.setText(f"Analysis complete. {len(self._results)} total results.")

    def _analyze_response(self, messageInfo):
        """Analyze HTTP response for JavaScript endpoints"""

        try:
            response = messageInfo.getResponse()
            if not response:
                return

            response_info = self._helpers.analyzeResponse(response)
            body_offset = response_info.getBodyOffset()
            body = response[body_offset:].tostring()

            url = str(messageInfo.getUrl())

            # Parse JavaScript content
            results = self._parse_javascript_content(body)

            if results['endpoints'] or results['parameters'] or results['secrets']:
                result_entry = {
                    'url': url,
                    'timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
                    'endpoints': results['endpoints'],
                    'parameters': results['parameters'],
                    'secrets': results['secrets'],
                    'domains': results['domains']
                }

                self._results.append(result_entry)
                self._add_results_to_ui(url, results)

        except Exception as e:
            print(f"Error analyzing response: {e}")

    def _parse_javascript_content(self, content):
        """Parse JavaScript content using LinkFinder patterns"""

        results = {
            'endpoints': [],
            'parameters': [],
            'secrets': [],
            'domains': []
        }

        # LinkFinder endpoint pattern
        endpoint_pattern = r'(?:"|\')\s*(((?:[a-zA-Z]{1,10}://|//)[^"\'/]{1,}\.[a-zA-Z]{2,}[^"\']{0,})|((?:/|\.\.\/|\.\/)[^"\'><,;| *()(%%$^/\\\\\\[\\]][^"\'><,;|()]{1,})|([a-zA-Z0-9_\\-/]{1,}/[a-zA-Z0-9_\\-/]{1,}\.(?:[a-zA-Z]{1,4}|action)(?:[\\?|#][^"|\']{0,}|))|([a-zA-Z0-9_\\-/]{1,}/[a-zA-Z0-9_\\-/]{3,}(?:[\\?|#][^"|\']{0,}|))|([a-zA-Z0-9_\\-]{1,}\.(?:php|asp|aspx|jsp|json|action|html|js|txt|xml)(?:[\\?|#][^"|\']{0,}|)))\s*(?:"|\')'

        # Additional patterns
        additional_patterns = [
            r'(?:fetch|axios|ajax)\s*\(\s*["\']([^"\']+)["\']',
            r'(?:GET|POST|PUT|DELETE|PATCH)\s*["\']([^"\']+)["\']',
            r'(?:href|src|action)\s*=\s*["\']([^"\']+)["\']'
        ]

        # Parameter patterns
        parameter_patterns = [
            r'(?:\\?|&)([a-zA-Z0-9_\\-]+)=([^&\\s"\']+)',
            r'(?:param|parameter|arg)\s*:\s*["\']([^"\']+)["\']'
        ]

        # Secret patterns
        secret_patterns = [
            r'(?i)(api[_\\-]?key|apikey)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{10,})["\']',
            r'(?i)(secret|password|pwd)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{8,})["\']',
            r'(?i)(token|auth)\s*[:=]\s*["\']([a-zA-Z0-9_\\-]{10,})["\']'
        ]

        # Domain patterns
        domain_patterns = [
            r'(?:https?://)?([a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,})',
            r'(?:"|\')\s*([a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,})\s*(?:"|\')'
        ]

        # Extract endpoints
        all_endpoint_patterns = [endpoint_pattern] + additional_patterns
        for pattern in all_endpoint_patterns:
            matches = re.findall(pattern, content, re.MULTILINE | re.IGNORECASE)
            for match in matches:
                if isinstance(match, tuple):
                    match = next((m for m in match if m), match[0])

                if match and match not in results['endpoints']:
                    # Clean the match
                    match = match.strip('\'"')
                    if len(match) > 1 and not any(char in match for char in ['<', '>', '{', '}', '\n']):
                        results['endpoints'].append(match)

        # Extract parameters
        for pattern in parameter_patterns:
            matches = re.findall(pattern, content, re.MULTILINE | re.IGNORECASE)
            for match in matches:
                if isinstance(match, tuple):
                    param = match[0] if match[0] else match[1] if len(match) > 1 else ''
                else:
                    param = match

                if param and param not in results['parameters']:
                    results['parameters'].append(param)

        # Extract secrets
        for pattern in secret_patterns:
            matches = re.findall(pattern, content, re.MULTILINE | re.IGNORECASE)
            for match in matches:
                if isinstance(match, tuple) and len(match) >= 2:
                    secret_info = f"{match[0]}: {match[1]}"
                    if secret_info not in results['secrets']:
                        results['secrets'].append(secret_info)

        # Extract domains
        for pattern in domain_patterns:
            matches = re.findall(pattern, content, re.MULTILINE | re.IGNORECASE)
            for match in matches:
                if match and match not in results['domains']:
                    results['domains'].append(match)

        return results

    def _add_results_to_ui(self, source_url, results):
        """Add parsing results to the UI"""

        self._results_area.append(f"\\n=== Analysis: {source_url} ===\\n")
        self._results_area.append(f"Timestamp: {time.strftime('%Y-%m-%d %H:%M:%S')}\\n")

        if results['endpoints']:
            self._results_area.append(f"\\nEndpoints ({len(results['endpoints'])}):
")
            for endpoint in results['endpoints'][:15]:  # Show first 15
                self._results_area.append(f"  • {endpoint}\\n")
            if len(results['endpoints']) > 15:
                self._results_area.append(f"  ... and {len(results['endpoints']) - 15} more\\n")

        if results['parameters']:
            self._results_area.append(f"\\nParameters ({len(results['parameters'])}):
")
            for param in results['parameters'][:10]:  # Show first 10
                self._results_area.append(f"  • {param}\\n")
            if len(results['parameters']) > 10:
                self._results_area.append(f"  ... and {len(results['parameters']) - 10} more\\n")

        if results['secrets']:
            self._results_area.append(f"\\nSecrets ({len(results['secrets'])}):
")
            for secret in results['secrets']:
                self._results_area.append(f"  ⚠️  {secret}\\n")

        if results['domains']:
            self._results_area.append(f"\\nDomains ({len(results['domains'])}):
")
            for domain in results['domains'][:10]:  # Show first 10
                self._results_area.append(f"  • {domain}\\n")

        self._results_area.append("\\n" + "="*80 + "\\n")

        # Auto-scroll to bottom
        self._results_area.setCaretPosition(self._results_area.getDocument().getLength())

    def _clear_results(self, event):
        self._results_area.setText("")
        self._results = []
        self._status_label.setText("Results cleared")

    def _export_results(self, event):
        """Export results to JSON file"""

        if not self._results:
            self._status_label.setText("No results to export")
            return

        try:
            # Create export data
            export_data = {
                'export_timestamp': time.strftime('%Y-%m-%d %H:%M:%S'),
                'total_analyses': len(self._results),
                'results': self._results
            }

            # Save to file (in Burp's working directory)
            filename = f"linkfinder_export_{int(time.time())}.json"
            with open(filename, 'w') as f:
                json.dump(export_data, f, indent=2)

            self._status_label.setText(f"Results exported to {filename}")

        except Exception as e:
            self._status_label.setText(f"Export failed: {e}")

Performance Optimization and Troubleshooting

Performance Tuning

# Optimize LinkFinder for different scenarios

# Fast analysis with minimal output
linkfinder -i script.js --no-beautify

# Memory-efficient analysis for large files
linkfinder -i large_script.js --timeout 30

# Parallel processing for multiple files
find /path/to/js/files -name "*.js" | xargs -P 10 -I {} linkfinder -i {}

# Network-optimized analysis
linkfinder -i https://example.com/script.js --timeout 60 --retries 3

# Performance monitoring script
#!/bin/bash
monitor_linkfinder_performance() {
    local target="$1"
    local output_file="linkfinder-performance-$(date +%s).log"

    echo "Monitoring LinkFinder performance for: $target"

    # Start monitoring
    {
        echo "Timestamp,CPU%,Memory(MB),Status"
        while true; do
            if pgrep -f "linkfinder" > /dev/null; then
                local cpu=$(ps -p $(pgrep -f "linkfinder") -o %cpu --no-headers)
                local mem=$(ps -p $(pgrep -f "linkfinder") -o rss --no-headers | awk '{print $1/1024}')
                echo "$(date +%s),$cpu,$mem,running"
            fi
            sleep 1
        done
    } > "$output_file" &

    local monitor_pid=$!

    # Run LinkFinder
    time linkfinder -i "$target" -o performance_test.html

    # Stop monitoring
    kill $monitor_pid 2>/dev/null

    echo "Performance monitoring completed: $output_file"
}

# Usage
monitor_linkfinder_performance "https://example.com/script.js"

Troubleshooting Common Issues

# Troubleshooting script for LinkFinder
troubleshoot_linkfinder() {
    echo "LinkFinder Troubleshooting Guide"
    echo "==============================="

    # Check if Python is installed
    if ! command -v python3 &> /dev/null; then
        echo "❌ Python 3 not found"
        echo "Solution: Install Python 3"
        return 1
    fi

    echo "✅ Python 3 found: $(python3 --version)"

    # Check if LinkFinder is available
    if ! command -v linkfinder &> /dev/null && [ ! -f "linkfinder.py" ]; then
        echo "❌ LinkFinder not found"
        echo "Solution: Clone LinkFinder repository"
        return 1
    fi

    echo "✅ LinkFinder found"

    # Check Python dependencies
    local required_modules=("requests" "argparse" "jsbeautifier")
    for module in "${required_modules[@]}"; do
        if python3 -c "import $module" 2>/dev/null; then
            echo "✅ Python module '$module': OK"
        else
            echo "❌ Python module '$module': Missing"
            echo "Solution: pip install $module"
        fi
    done

    # Check network connectivity
    if ! curl -s --connect-timeout 5 https://httpbin.org/get > /dev/null; then
        echo "❌ Network connectivity issues"
        echo "Solution: Check internet connection"
        return 1
    fi

    echo "✅ Network connectivity OK"

    # Test basic functionality
    echo "Testing basic LinkFinder functionality..."

    # Create test JavaScript file
    cat > test_script.js << 'EOF'
var apiEndpoint = "/api/users";
var secretKey = "abc123def456";
fetch("/api/data");
window.location.href = "/dashboard";
EOF

    if linkfinder -i test_script.js > /dev/null 2>&1; then
        echo "✅ Basic functionality test passed"
    else
        echo "❌ Basic functionality test failed"
        echo "Solution: Check LinkFinder installation and dependencies"
    fi

    # Clean up
    rm -f test_script.js

    echo "Troubleshooting completed"
}

# Common error solutions
fix_common_linkfinder_errors() {
    echo "Common LinkFinder Error Solutions"
    echo "================================"

    echo "1. 'ModuleNotFoundError: No module named ...'"
    echo "   Solution: pip install -r requirements.txt"
    echo "   Alternative: pip install requests jsbeautifier"
    echo ""

    echo "2. 'Permission denied' when running linkfinder"
    echo "   Solution: chmod +x linkfinder.py"
    echo "   Alternative: python3 linkfinder.py [options]"
    echo ""

    echo "3. 'Connection timeout' or network errors"
    echo "   Solution: Increase timeout with --timeout option"
    echo "   Example: linkfinder -i <url> --timeout 60"
    echo ""

    echo "4. 'No endpoints found' (false negatives)"
    echo "   Solution: Try beautifying JavaScript first"
    echo "   Example: linkfinder -i <file> -b"
    echo ""

    echo "5. 'Memory error' for large files"
    echo "   Solution: Process files in smaller chunks"
    echo "   Alternative: Increase system memory"
    echo ""

    echo "6. 'SSL certificate error'"
    echo "   Solution: Use --no-ssl-verify option (not recommended for production)"
    echo ""

    echo "7. 'Too many false positives'"
    echo "   Solution: Use custom regex patterns or post-processing filters"
    echo "   Example: Filter results based on file extensions or paths"
    echo ""

    echo "8. 'HTML output not generated'"
    echo "   Solution: Check output directory permissions"
    echo "   Alternative: Specify full output path"
}

# Run troubleshooting
troubleshoot_linkfinder
fix_common_linkfinder_errors

Resources and Documentation

Official Resources

Community Resources

Integration Examples