├── requirements.txt ├── img ├── en.png └── tr.jpg ├── README.md ├── README.tr.md ├── .gitignore ├── chrome-extension ├── README.md ├── manifest.json ├── background.js └── content.js ├── start.bat ├── macos_bridge_config.py ├── start-macos.sh ├── windows_bridge_config.py ├── style.qss ├── warp_bridge_server.py ├── warp_proxy_script.py └── languages.py /requirements.txt: -------------------------------------------------------------------------------- 1 | PyQt5 2 | requests 3 | mitmproxy 4 | psutil 5 | -------------------------------------------------------------------------------- /img/en.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghondar/warp.dev_account_manager/HEAD/img/en.png -------------------------------------------------------------------------------- /img/tr.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ghondar/warp.dev_account_manager/HEAD/img/tr.jpg -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Warp Account Manager 2 | 3 |  4 | 5 | This extension allows you to easily switch between your accounts. 6 | - No ban issues 7 | - Custom chrome extension 8 | 9 | ## NOTE 10 | 11 | This project is designed to facilitate the use of Warp.dev. No responsibility is accepted. 12 | 13 | ## Usage Video: 14 | https://youtu.be/5_itpYHZGJc 15 | -------------------------------------------------------------------------------- /README.tr.md: -------------------------------------------------------------------------------- 1 | # Warp Account Manager 2 | 3 |  4 | 5 | Bu eklenti ile hesaplarınız arasında kolayca geçiş yapabilirsiniz. 6 | - Ban problemi yoktur 7 | - Özel chrome eklentisi 8 | 9 | ## NOT 10 | 11 | Bu proje, Warp.dev kullanımını kolaylaştırmak amacıyla hazırlanmıştır. Hiçbir sorumluluk kabul etmez. 12 | 13 | ## Kullanım Videosu: 14 | https://youtu.be/cfcCbqCJUWA 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Database files 2 | accounts.db 3 | 4 | # User settings 5 | user_settings.json 6 | 7 | # Temporary files 8 | account_change_trigger.tmp 9 | 10 | # Python cache 11 | __pycache__/ 12 | *.pyc 13 | *.pyo 14 | *.pyd 15 | 16 | # Virtual environment 17 | venv/ 18 | env/ 19 | .env 20 | 21 | # IDE files 22 | .vscode/ 23 | .idea/ 24 | *.swp 25 | *.swo 26 | 27 | # OS files 28 | .DS_Store 29 | Thumbs.db 30 | -------------------------------------------------------------------------------- /chrome-extension/README.md: -------------------------------------------------------------------------------- 1 | # Warp Account Bridge - Chrome Extension 2 | 3 | Bu Chrome eklentisi Warp hesap verilerini otomatik olarak Python uygulamasına aktarmak için kullanılır. 4 | 5 | ## Kurulum 6 | 7 | 1. Chrome'da `chrome://extensions/` adresine gidin 8 | 2. Sağ üst köşeden "Developer mode" açın 9 | 3. "Load unpacked" butonuna tıklayın 10 | 4. Bu klasörü (`chrome-extension`) seçin 11 | 12 | ## Kullanım 13 | 14 | 1. Python uygulamasını çalıştırın (Bridge server otomatik başlar) 15 | 2. Chrome'da `https://app.warp.dev/logged_in/remote` sayfasına gidin 16 | 3. Sayfada "📡 Add to Warp Manager" butonu görünecek 17 | 4. Butona tıklayarak hesap verilerini otomatik aktarın 18 | 19 | ## Özellikler 20 | 21 | - ✅ Otomatik veri çıkarma 22 | - ✅ Güvenli bridge iletişimi 23 | - ✅ Sabit extension ID 24 | - ✅ Hata yönetimi 25 | - ✅ Görsel geri bildirim 26 | 27 | ## Teknik Detaylar 28 | 29 | - **Port**: 8765 (Python uygulaması) 30 | - **Extension ID**: `warp-account-bridge-v1` 31 | - **Target Page**: `app.warp.dev/logged_in/remote` 32 | - **Data Source**: IndexedDB (firebaseLocalStorageDb) 33 | 34 | ## Dosyalar 35 | 36 | - `manifest.json`: Extension configuration 37 | - `content.js`: Page injection script 38 | - `background.js`: Extension lifecycle management 39 | -------------------------------------------------------------------------------- /chrome-extension/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "Warp Account Bridge", 4 | "version": "1.0", 5 | "description": "Bridge extension for Warp account management", 6 | "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvXIun41RYc3Ln6RQZI4xLkSzJkAlExAeg3nFLhW5cQNv44OGwglABrBlmcaDxuVQ1bSlm8MITITsUR7g+4rV/d/0BsRLr8EPnZsaek+RMQpMaLUb5O9rBGNXUzh7NhpkBGj3SIpVbj1NA/ruTZP+MoR6SlidjzJQHQXaKAVWdr+pWWJkvTU1I8IysUxKutxcVRNWiwklFQZk/C0mnBPxqvYtYsTXuq44twgIMv4jRydcf0hBAFOKNONEWG8j/hVukAROh6JV0OFNrPzxRp+CuqUynWxN8xYUyPuyzllR5xhpPVRFvgrfDqyr0CPcSuyJA96CeEIQyBnFVD65VjQATQIDAQAB", 7 | "permissions": [ 8 | "tabs", 9 | "storage", 10 | "activeTab", 11 | "scripting" 12 | ], 13 | "host_permissions": [ 14 | "https://app.warp.dev/logged_in/*" 15 | ], 16 | "background": { 17 | "service_worker": "background.js" 18 | }, 19 | "content_scripts": [ 20 | { 21 | "matches": [ 22 | "https://app.warp.dev/logged_in/remote*", 23 | "https://app.warp.dev/logged_in*", 24 | "https://app.warp.dev/login*" 25 | ], 26 | "js": [ 27 | "content.js" 28 | ], 29 | "run_at": "document_end" 30 | } 31 | ], 32 | "action": { 33 | "default_title": "Warp Account Bridge" 34 | }, 35 | "externally_connectable": { 36 | "matches": [ 37 | "http://localhost:*/*" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /start.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | :: Warp Account Manager Launcher - Enhanced Edition 3 | :: Automatic installation and startup script 4 | 5 | title Warp Account Manager - Installation and Startup 6 | chcp 65001 >nul 2>&1 7 | 8 | echo. 9 | echo ==================================================== 10 | echo Warp Account Manager - Automatic Installation 11 | echo ==================================================== 12 | echo. 13 | 14 | :: Administrator permission check 15 | echo [1/6] Checking administrator permissions... 16 | net session >nul 2>&1 17 | if errorlevel 1 ( 18 | echo [ERROR] This application must be run with administrator privileges! 19 | echo. 20 | echo Solution: 21 | echo 1. Right-click on this file 22 | echo 2. Click "Run as administrator" 23 | echo. 24 | pause 25 | exit /b 1 26 | ) 27 | echo [OK] Administrator privileges verified 28 | echo. 29 | 30 | :: Check if Python is installed 31 | echo [2/6] Checking Python installation... 32 | python --version >nul 2>&1 33 | if errorlevel 1 ( 34 | echo [ERROR] Python not found! 35 | echo. 36 | echo Python 3.8 or higher is required. 37 | echo Please download and install Python from https://python.org 38 | echo. 39 | pause 40 | exit /b 1 41 | ) 42 | 43 | for /f "tokens=2" %%i in ('python --version 2^>^&1') do set PYTHON_VERSION=%%i 44 | echo [OK] Python %PYTHON_VERSION% found 45 | echo. 46 | 47 | :: Check if pip is installed 48 | echo [3/6] Checking pip installation... 49 | pip --version >nul 2>&1 50 | if errorlevel 1 ( 51 | echo [ERROR] pip not found! 52 | echo. 53 | echo pip should come with Python. 54 | echo Try reinstalling Python. 55 | echo. 56 | pause 57 | exit /b 1 58 | ) 59 | echo [OK] pip found 60 | echo. 61 | 62 | :: Check and install required packages 63 | echo [4/6] Checking required Python packages... 64 | echo. 65 | 66 | :: Package list 67 | set PACKAGES=PyQt5 requests mitmproxy psutil 68 | 69 | :: Check each package 70 | for %%p in (%PACKAGES%) do ( 71 | echo Checking: %%p 72 | pip show %%p >nul 2>&1 73 | if errorlevel 1 ( 74 | echo [MISSING] Installing %%p... 75 | pip install %%p 76 | if errorlevel 1 ( 77 | echo [ERROR] Failed to install %%p! 78 | echo. 79 | echo Please check your internet connection and try again. 80 | echo. 81 | pause 82 | exit /b 1 83 | ) 84 | echo [OK] %%p successfully installed 85 | ) else ( 86 | echo [OK] %%p already installed 87 | ) 88 | ) 89 | 90 | echo. 91 | echo [OK] All required packages are ready 92 | echo. 93 | 94 | :: Database file check 95 | echo [5/6] Checking database file... 96 | if exist "accounts.db" ( 97 | echo [OK] Database file exists 98 | ) else ( 99 | echo [INFO] Database file will be created 100 | ) 101 | echo. 102 | 103 | :: Start Warp Account Manager 104 | echo [6/6] Starting Warp Account Manager... 105 | echo. 106 | echo ==================================================== 107 | echo Installation completed - Starting application 108 | echo ==================================================== 109 | echo. 110 | 111 | :: Navigate to script directory 112 | cd /d "%~dp0" 113 | 114 | if exist "warp_account_manager.py" ( 115 | echo Opening Warp Account Manager... 116 | echo. 117 | echo NOTE: Do not close this window! This console window 118 | echo must remain open while the application is running. 119 | echo. 120 | python warp_account_manager.py 121 | 122 | echo. 123 | echo Warp Account Manager closed. 124 | ) else ( 125 | echo [ERROR] warp_account_manager.py file not found! 126 | echo. 127 | echo Current directory: %CD% 128 | echo Script directory: %~dp0 129 | echo. 130 | echo Please ensure all files are in the correct location. 131 | ) 132 | 133 | echo. 134 | echo Press any key to exit... 135 | pause >nul 136 | -------------------------------------------------------------------------------- /chrome-extension/background.js: -------------------------------------------------------------------------------- 1 | // Background script for Warp Account Bridge 2 | // Handles extension lifecycle and bridge communication 3 | 4 | const BRIDGE_CONFIG = { 5 | pythonAppPort: 8765, 6 | extensionId: "warp-account-bridge-v1", 7 | }; 8 | 9 | // Check if Python app is running 10 | async function checkPythonApp() { 11 | try { 12 | const response = await fetch(`http://localhost:${BRIDGE_CONFIG.pythonAppPort}/health`, { 13 | method: "GET", 14 | headers: { 15 | "X-Extension-ID": BRIDGE_CONFIG.extensionId, 16 | }, 17 | }); 18 | return response.ok; 19 | } catch (error) { 20 | return false; 21 | } 22 | } 23 | 24 | // Setup bridge configuration on Python app 25 | async function setupBridge() { 26 | try { 27 | const response = await fetch(`http://localhost:${BRIDGE_CONFIG.pythonAppPort}/setup-bridge`, { 28 | method: "POST", 29 | headers: { 30 | "Content-Type": "application/json", 31 | "X-Extension-ID": BRIDGE_CONFIG.extensionId, 32 | }, 33 | body: JSON.stringify({ 34 | extensionId: chrome.runtime.id, 35 | version: chrome.runtime.getManifest().version, 36 | }), 37 | }); 38 | 39 | if (response.ok) { 40 | console.log("Bridge setup successful"); 41 | return true; 42 | } else { 43 | console.log("Bridge setup failed:", await response.text()); 44 | return false; 45 | } 46 | } catch (error) { 47 | console.log("Bridge setup error:", error); 48 | return false; 49 | } 50 | } 51 | 52 | // Extension installed/startup 53 | chrome.runtime.onInstalled.addListener(async (details) => { 54 | console.log("Warp Account Bridge installed/updated"); 55 | 56 | // Try to setup bridge with Python app 57 | setTimeout(async () => { 58 | const isAppRunning = await checkPythonApp(); 59 | if (isAppRunning) { 60 | await setupBridge(); 61 | } 62 | }, 2000); 63 | }); 64 | 65 | // Extension startup 66 | chrome.runtime.onStartup.addListener(async () => { 67 | console.log("Warp Account Bridge started"); 68 | 69 | // Try to setup bridge with Python app 70 | setTimeout(async () => { 71 | const isAppRunning = await checkPythonApp(); 72 | if (isAppRunning) { 73 | await setupBridge(); 74 | } 75 | }, 2000); 76 | }); 77 | 78 | // Handle messages from content scripts 79 | chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { 80 | if (request.type === "EXTRACT_ACCOUNT_DATA") { 81 | // This could be used for alternative data extraction if needed 82 | handleAccountDataExtraction(request, sender, sendResponse); 83 | return true; // Will respond asynchronously 84 | } else if (request.type === "CHECK_PYTHON_APP") { 85 | checkPythonApp().then(sendResponse); 86 | return true; 87 | } 88 | }); 89 | 90 | // Handle account data extraction (alternative method) 91 | async function handleAccountDataExtraction(request, sender, sendResponse) { 92 | try { 93 | // Execute script in the content script's context to extract data 94 | const results = await chrome.scripting.executeScript({ 95 | target: { tabId: sender.tab.id }, 96 | func: extractFirebaseData, 97 | }); 98 | 99 | if (results && results[0] && results[0].result) { 100 | sendResponse({ success: true, data: results[0].result }); 101 | } else { 102 | sendResponse({ success: false, error: "No data found" }); 103 | } 104 | } catch (error) { 105 | sendResponse({ success: false, error: error.message }); 106 | } 107 | } 108 | 109 | // Function to inject into page for data extraction 110 | function extractFirebaseData() { 111 | return new Promise((resolve, reject) => { 112 | try { 113 | const request = indexedDB.open("firebaseLocalStorageDb"); 114 | 115 | request.onsuccess = function (event) { 116 | const db = event.target.result; 117 | const transaction = db.transaction(["firebaseLocalStorage"], "readonly"); 118 | const objectStore = transaction.objectStore("firebaseLocalStorage"); 119 | 120 | objectStore.getAll().onsuccess = function (event) { 121 | const results = event.target.result; 122 | 123 | for (let result of results) { 124 | if (result.value && typeof result.value === "object" && result.value.email && result.value.stsTokenManager) { 125 | resolve(result.value); 126 | return; 127 | } 128 | } 129 | reject(new Error("No valid account data found")); 130 | }; 131 | 132 | objectStore.getAll().onerror = () => reject(new Error("Database read error")); 133 | }; 134 | 135 | request.onerror = () => reject(new Error("Database connection error")); 136 | } catch (error) { 137 | reject(error); 138 | } 139 | }); 140 | } 141 | 142 | // Monitor tab changes to detect warp.dev visits 143 | chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => { 144 | if (changeInfo.status === "complete" && tab.url && tab.url.includes("app.warp.dev/logged_in")) { 145 | // Check if Python app is running when user visits the target page 146 | const isAppRunning = await checkPythonApp(); 147 | if (!isAppRunning) { 148 | // Could show a notification here if needed 149 | console.log("Python app not running when visiting Warp page"); 150 | } 151 | } 152 | }); 153 | 154 | // Periodic health check (every 5 minutes) 155 | setInterval(async () => { 156 | const isAppRunning = await checkPythonApp(); 157 | if (isAppRunning) { 158 | // Ensure bridge is properly configured 159 | await setupBridge(); 160 | } 161 | }, 300000); // 5 minutes 162 | -------------------------------------------------------------------------------- /macos_bridge_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | macOS Bridge Configuration - Native messaging setup for Chrome extension 6 | """ 7 | 8 | import os 9 | import sys 10 | import json 11 | from pathlib import Path 12 | 13 | 14 | class MacOSBridgeConfig: 15 | def __init__(self): 16 | self.extension_id = "warp-account-bridge-v1" 17 | self.app_name = "com.warp.account.bridge" 18 | self.native_messaging_dir = Path.home() / "Library/Application Support/Google/Chrome/NativeMessagingHosts" 19 | 20 | def is_admin(self): 21 | """Check if running as administrator (root)""" 22 | return os.getuid() == 0 23 | 24 | def setup_localhost_access(self): 25 | """Configure macOS for localhost access from extensions""" 26 | try: 27 | print("🔧 Chrome extension manifest localhost access...") 28 | 29 | # Chrome extension uses externally_connectable in manifest 30 | # No additional macOS-specific registry settings needed 31 | print("✅ Manifest-based localhost access active") 32 | print("📋 Extension manifest has externally_connectable configuration") 33 | 34 | return True 35 | 36 | except Exception as e: 37 | print(f"❌ Localhost access setup error: {e}") 38 | return False 39 | 40 | def create_native_messaging_manifest(self): 41 | """Create native messaging host manifest for macOS""" 42 | try: 43 | # Python executable path 44 | python_exe = sys.executable 45 | script_path = os.path.abspath("warp_account_manager.py") 46 | 47 | manifest = { 48 | "name": self.app_name, 49 | "description": "Warp Account Bridge Native Host", 50 | "path": python_exe, 51 | "type": "stdio", 52 | "allowed_origins": [ 53 | f"chrome-extension://{self.extension_id}/" 54 | ] 55 | } 56 | 57 | # Create manifest directory if it doesn't exist 58 | self.native_messaging_dir.mkdir(parents=True, exist_ok=True) 59 | 60 | manifest_path = self.native_messaging_dir / f"{self.app_name}.json" 61 | with open(manifest_path, 'w') as f: 62 | json.dump(manifest, f, indent=2) 63 | 64 | print(f"✅ Native messaging manifest created: {manifest_path}") 65 | return str(manifest_path) 66 | 67 | except Exception as e: 68 | print(f"❌ Manifest creation error: {e}") 69 | return None 70 | 71 | def register_native_host(self): 72 | """Register native messaging host (macOS uses file-based registration)""" 73 | try: 74 | manifest_path = self.create_native_messaging_manifest() 75 | if not manifest_path: 76 | return False 77 | 78 | print(f"✅ Native host registered: {manifest_path}") 79 | return True 80 | 81 | except Exception as e: 82 | print(f"❌ Native host registration error: {e}") 83 | return False 84 | 85 | def setup_bridge_config(self): 86 | """Complete bridge configuration for macOS""" 87 | print("🌉 macOS Bridge configuration starting...") 88 | 89 | # 1. Localhost access setup 90 | localhost_ok = self.setup_localhost_access() 91 | 92 | # 2. Native messaging host registration 93 | native_ok = self.register_native_host() 94 | 95 | if localhost_ok and native_ok: 96 | print("✅ Bridge configuration completed!") 97 | print("\n📋 Next steps:") 98 | print("1. Restart Chrome") 99 | print("2. Load extension from chrome://extensions/ page") 100 | print("3. Start Warp Account Manager") 101 | return True 102 | else: 103 | print("❌ Bridge configuration failed!") 104 | return False 105 | 106 | def check_configuration(self): 107 | """Check if bridge is properly configured""" 108 | try: 109 | print("🔍 Checking bridge configuration...") 110 | 111 | # Check if manifest file exists 112 | manifest_path = self.native_messaging_dir / f"{self.app_name}.json" 113 | if manifest_path.exists(): 114 | print("✅ Native messaging manifest found") 115 | return True 116 | else: 117 | print("❌ Native messaging manifest not found") 118 | return False 119 | 120 | except Exception as e: 121 | print(f"❌ Configuration check error: {e}") 122 | return False 123 | 124 | def remove_configuration(self): 125 | """Remove bridge configuration (cleanup)""" 126 | try: 127 | print("🧹 Cleaning up bridge configuration...") 128 | 129 | # Remove manifest file 130 | manifest_path = self.native_messaging_dir / f"{self.app_name}.json" 131 | if manifest_path.exists(): 132 | manifest_path.unlink() 133 | print("✅ Manifest file removed") 134 | else: 135 | print("⚠️ Manifest file not found") 136 | 137 | return True 138 | 139 | except Exception as e: 140 | print(f"❌ Cleanup error: {e}") 141 | return False 142 | 143 | 144 | def setup_bridge(): 145 | """Setup bridge configuration""" 146 | config = MacOSBridgeConfig() 147 | return config.setup_bridge_config() 148 | 149 | def check_bridge(): 150 | """Check bridge configuration""" 151 | config = MacOSBridgeConfig() 152 | return config.check_configuration() 153 | 154 | def remove_bridge(): 155 | """Remove bridge configuration""" 156 | config = MacOSBridgeConfig() 157 | return config.remove_configuration() 158 | 159 | 160 | if __name__ == "__main__": 161 | if len(sys.argv) > 1: 162 | action = sys.argv[1] 163 | 164 | if action == "setup": 165 | setup_bridge() 166 | elif action == "check": 167 | check_bridge() 168 | elif action == "remove": 169 | remove_bridge() 170 | else: 171 | print("Usage: python macos_bridge_config.py [setup|check|remove]") 172 | else: 173 | # Default: setup 174 | setup_bridge() -------------------------------------------------------------------------------- /start-macos.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Warp Account Manager Launcher - macOS Edition 3 | # Automatic installation and startup script 4 | 5 | # Colors for better output 6 | RED='\033[0;31m' 7 | GREEN='\033[0;32m' 8 | YELLOW='\033[1;33m' 9 | BLUE='\033[0;34m' 10 | NC='\033[0m' # No Color 11 | 12 | # Clear screen and show header 13 | clear 14 | echo 15 | echo "====================================================" 16 | echo " Warp Account Manager - Automatic Installation" 17 | echo "====================================================" 18 | echo 19 | 20 | # Function to print status messages 21 | print_status() { 22 | echo -e "${GREEN}[OK]${NC} $1" 23 | } 24 | 25 | print_info() { 26 | echo -e "${BLUE}[INFO]${NC} $1" 27 | } 28 | 29 | print_error() { 30 | echo -e "${RED}[ERROR]${NC} $1" 31 | } 32 | 33 | print_warning() { 34 | echo -e "${YELLOW}[WARNING]${NC} $1" 35 | } 36 | 37 | # Navigate to script directory 38 | SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" 39 | cd "$SCRIPT_DIR" 40 | 41 | # Check if running as root (administrator equivalent) 42 | echo "[1/6] Checking permissions..." 43 | if [[ $EUID -eq 0 ]]; then 44 | print_warning "Running as root - this is not recommended for this application" 45 | print_info "You may run this script as a regular user" 46 | else 47 | print_status "Running as regular user" 48 | fi 49 | echo 50 | 51 | # Check if Python is installed 52 | echo "[2/6] Checking Python installation..." 53 | if command -v python3 &> /dev/null; then 54 | PYTHON_VERSION=$(python3 --version 2>&1 | cut -d' ' -f2) 55 | print_status "Python $PYTHON_VERSION found" 56 | PYTHON_CMD="python3" 57 | elif command -v python &> /dev/null; then 58 | PYTHON_VERSION=$(python --version 2>&1 | cut -d' ' -f2) 59 | # Check if it's Python 3 60 | if python -c "import sys; exit(0 if sys.version_info[0] >= 3 else 1)" 2>/dev/null; then 61 | print_status "Python $PYTHON_VERSION found" 62 | PYTHON_CMD="python" 63 | else 64 | print_error "Python 3.8 or higher is required, but found Python 2" 65 | echo 66 | echo "Please install Python 3 using one of these methods:" 67 | echo "1. Homebrew: brew install python3" 68 | echo "2. Python.org: https://python.org" 69 | echo "3. Pyenv: pyenv install 3.11" 70 | echo 71 | read -p "Press Enter to exit..." 72 | exit 1 73 | fi 74 | else 75 | print_error "Python not found!" 76 | echo 77 | echo "Python 3.8 or higher is required." 78 | echo "Please install Python using one of these methods:" 79 | echo "1. Homebrew: brew install python3" 80 | echo "2. Python.org: https://python.org" 81 | echo "3. Pyenv: pyenv install 3.11" 82 | echo 83 | read -p "Press Enter to exit..." 84 | exit 1 85 | fi 86 | echo 87 | 88 | # Check if pip is installed 89 | echo "[3/6] Checking pip installation..." 90 | if command -v pip3 &> /dev/null; then 91 | print_status "pip3 found" 92 | PIP_CMD="pip3" 93 | elif command -v pip &> /dev/null; then 94 | print_status "pip found" 95 | PIP_CMD="pip" 96 | else 97 | print_error "pip not found!" 98 | echo 99 | echo "pip should come with Python." 100 | echo "Try reinstalling Python or install pip manually:" 101 | echo "curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py" 102 | echo "$PYTHON_CMD get-pip.py" 103 | echo 104 | read -p "Press Enter to exit..." 105 | exit 1 106 | fi 107 | echo 108 | 109 | # Check and install required packages 110 | echo "[4/6] Checking required Python packages..." 111 | echo 112 | 113 | # Package list 114 | PACKAGES=("PyQt5" "requests" "mitmproxy" "psutil") 115 | 116 | # Check each package 117 | for package in "${PACKAGES[@]}"; do 118 | echo " Checking: $package" 119 | if $PIP_CMD show "$package" > /dev/null 2>&1; then 120 | print_status " $package already installed" 121 | else 122 | print_info " [MISSING] Installing $package..." 123 | 124 | # Try different installation methods for macOS 125 | if [[ "$package" == "PyQt5" ]]; then 126 | # PyQt5 via Homebrew on macOS 127 | if command -v brew &> /dev/null; then 128 | echo " Trying Homebrew installation for PyQt5..." 129 | if brew install pyqt@5; then 130 | print_status " $package successfully installed via Homebrew" 131 | continue 132 | fi 133 | fi 134 | elif [[ "$package" == "mitmproxy" ]]; then 135 | # mitmproxy via Homebrew (already should be installed) 136 | if command -v mitmdump &> /dev/null; then 137 | print_status " mitmproxy already available via Homebrew" 138 | continue 139 | fi 140 | fi 141 | 142 | # Try pip with --break-system-packages as fallback 143 | if $PIP_CMD install "$package" --break-system-packages; then 144 | print_status " $package successfully installed" 145 | else 146 | print_error " Failed to install $package!" 147 | echo 148 | echo " Possible solutions:" 149 | echo " 1. Install via Homebrew: brew install $package" 150 | echo " 2. Create virtual environment" 151 | echo " 3. Try: $PIP_CMD install --user $package --break-system-packages" 152 | echo 153 | read -p "Continue anyway? (y/N): " -n 1 -r 154 | echo 155 | if [[ ! $REPLY =~ ^[Yy]$ ]]; then 156 | exit 1 157 | fi 158 | fi 159 | fi 160 | done 161 | 162 | echo 163 | print_status "All required packages are ready" 164 | echo 165 | 166 | # Database file check 167 | echo "[5/6] Checking database file..." 168 | if [[ -f "accounts.db" ]]; then 169 | print_status "Database file exists" 170 | else 171 | print_info "Database file will be created" 172 | fi 173 | echo 174 | 175 | # Start Warp Account Manager 176 | echo "[6/6] Starting Warp Account Manager..." 177 | echo 178 | echo "====================================================" 179 | echo " Installation completed - Starting application" 180 | echo "====================================================" 181 | echo 182 | 183 | if [[ -f "warp_account_manager.py" ]]; then 184 | print_info "Opening Warp Account Manager..." 185 | echo 186 | print_warning "NOTE: Do not close this terminal window! This console window" 187 | print_warning " must remain open while the application is running." 188 | echo 189 | 190 | # Start the application 191 | $PYTHON_CMD warp_account_manager.py 192 | 193 | echo 194 | print_info "Warp Account Manager closed." 195 | else 196 | print_error "warp_account_manager.py file not found!" 197 | echo 198 | echo "Current directory: $(pwd)" 199 | echo "Script directory: $SCRIPT_DIR" 200 | echo 201 | echo "Please ensure all files are in the correct location." 202 | fi 203 | 204 | echo 205 | echo "Press Enter to exit..." 206 | read -------------------------------------------------------------------------------- /windows_bridge_config.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | Windows Bridge Configuration - Registry settings for Chrome extension 6 | """ 7 | 8 | import winreg 9 | import os 10 | import sys 11 | import json 12 | from pathlib import Path 13 | 14 | class WindowsBridgeConfig: 15 | def __init__(self): 16 | self.extension_id = "warp-account-bridge-v1" 17 | self.app_name = "com.warp.account.bridge" 18 | self.registry_paths = [ 19 | r"SOFTWARE\Google\Chrome\NativeMessagingHosts", 20 | r"SOFTWARE\Microsoft\Edge\NativeMessagingHosts" 21 | ] 22 | 23 | def is_admin(self): 24 | """Check if running as administrator""" 25 | try: 26 | return os.getuid() == 0 27 | except AttributeError: 28 | # Windows 29 | import ctypes 30 | try: 31 | return ctypes.windll.shell32.IsUserAnAdmin() 32 | except: 33 | return False 34 | 35 | def setup_localhost_access(self): 36 | """Configure Windows for localhost access from extensions""" 37 | try: 38 | print("🔧 Chrome extension manifest ile localhost erişimi...") 39 | 40 | # Chrome extension manifest'te externally_connectable kullanıyoruz 41 | # Registry ayarı gerekmez, manifest yeterli 42 | print("✅ Manifest-based localhost erişimi aktif") 43 | print("📋 Extension manifest'te externally_connectable yapılandırması mevcut") 44 | 45 | return True 46 | 47 | except Exception as e: 48 | print(f"❌ Localhost erişim ayarı hatası: {e}") 49 | return False 50 | 51 | def create_native_messaging_manifest(self): 52 | """Create native messaging host manifest""" 53 | try: 54 | # Python executable path 55 | python_exe = sys.executable 56 | script_path = os.path.abspath("warp_account_manager.py") 57 | 58 | manifest = { 59 | "name": self.app_name, 60 | "description": "Warp Account Bridge Native Host", 61 | "path": python_exe, 62 | "type": "stdio", 63 | "allowed_origins": [ 64 | f"chrome-extension://{self.extension_id}/" 65 | ] 66 | } 67 | 68 | # Manifest dosyasını kaydet 69 | manifest_dir = os.path.join(os.getenv('APPDATA'), 'WarpAccountManager') 70 | os.makedirs(manifest_dir, exist_ok=True) 71 | 72 | manifest_path = os.path.join(manifest_dir, f"{self.app_name}.json") 73 | with open(manifest_path, 'w') as f: 74 | json.dump(manifest, f, indent=2) 75 | 76 | print(f"✅ Native messaging manifest oluşturuldu: {manifest_path}") 77 | return manifest_path 78 | 79 | except Exception as e: 80 | print(f"❌ Manifest oluşturma hatası: {e}") 81 | return None 82 | 83 | def register_native_host(self): 84 | """Register native messaging host in registry""" 85 | try: 86 | manifest_path = self.create_native_messaging_manifest() 87 | if not manifest_path: 88 | return False 89 | 90 | success = False 91 | 92 | for registry_path in self.registry_paths: 93 | try: 94 | # HKEY_CURRENT_USER'da kaydet (yönetici gerektirmez) 95 | key = winreg.CreateKey(winreg.HKEY_CURRENT_USER, registry_path) 96 | winreg.SetValueEx(key, self.app_name, 0, winreg.REG_SZ, manifest_path) 97 | winreg.CloseKey(key) 98 | print(f"✅ Native host kaydedildi: {registry_path}") 99 | success = True 100 | 101 | except Exception as e: 102 | print(f"⚠️ Registry kaydı hatası ({registry_path}): {e}") 103 | 104 | return success 105 | 106 | except Exception as e: 107 | print(f"❌ Native host kayıt hatası: {e}") 108 | return False 109 | 110 | def setup_bridge_config(self): 111 | """Complete bridge configuration""" 112 | print("🌉 Windows Bridge konfigürasyonu başlatılıyor...") 113 | 114 | # 1. Localhost erişim ayarları 115 | localhost_ok = self.setup_localhost_access() 116 | 117 | # 2. Native messaging host kaydı (opsiyonel) 118 | # native_ok = self.register_native_host() 119 | 120 | if localhost_ok: 121 | print("✅ Bridge konfigürasyonu tamamlandı!") 122 | print("\n📋 Sonraki adımlar:") 123 | print("1. Chrome'u yeniden başlat") 124 | print("2. Eklentiyi chrome://extensions/ sayfasından yükle") 125 | print("3. Warp Account Manager'ı başlat") 126 | return True 127 | else: 128 | print("❌ Bridge konfigürasyonu başarısız!") 129 | return False 130 | 131 | def check_configuration(self): 132 | """Check if bridge is properly configured""" 133 | try: 134 | print("🔍 Bridge konfigürasyon kontrol ediliyor...") 135 | 136 | # Manifest-based konfigürasyon için her zaman True döndür 137 | # Gerçek kontrol extension yüklendiğinde yapılacak 138 | print("✅ Manifest-based bridge konfigürasyonu") 139 | return True 140 | 141 | except Exception as e: 142 | print(f"❌ Konfigürasyon kontrol hatası: {e}") 143 | return False 144 | 145 | def remove_configuration(self): 146 | """Remove bridge configuration (cleanup)""" 147 | try: 148 | print("🧹 Bridge konfigürasyonu temizleniyor...") 149 | 150 | # Registry temizliği 151 | chrome_policies_path = r"SOFTWARE\Policies\Google\Chrome" 152 | 153 | try: 154 | key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, chrome_policies_path, 0, winreg.KEY_SET_VALUE) 155 | winreg.DeleteValue(key, "URLAllowlist") 156 | winreg.CloseKey(key) 157 | print("✅ Chrome policy temizlendi") 158 | except FileNotFoundError: 159 | print("⚠️ Chrome policy zaten mevcut değil") 160 | 161 | # Manifest dosyası temizliği 162 | manifest_dir = os.path.join(os.getenv('APPDATA'), 'WarpAccountManager') 163 | manifest_path = os.path.join(manifest_dir, f"{self.app_name}.json") 164 | 165 | if os.path.exists(manifest_path): 166 | os.remove(manifest_path) 167 | print("✅ Manifest dosyası silindi") 168 | 169 | return True 170 | 171 | except Exception as e: 172 | print(f"❌ Temizlik hatası: {e}") 173 | return False 174 | 175 | 176 | def setup_bridge(): 177 | """Setup bridge configuration""" 178 | config = WindowsBridgeConfig() 179 | return config.setup_bridge_config() 180 | 181 | def check_bridge(): 182 | """Check bridge configuration""" 183 | config = WindowsBridgeConfig() 184 | return config.check_configuration() 185 | 186 | def remove_bridge(): 187 | """Remove bridge configuration""" 188 | config = WindowsBridgeConfig() 189 | return config.remove_configuration() 190 | 191 | 192 | if __name__ == "__main__": 193 | if len(sys.argv) > 1: 194 | action = sys.argv[1] 195 | 196 | if action == "setup": 197 | setup_bridge() 198 | elif action == "check": 199 | check_bridge() 200 | elif action == "remove": 201 | remove_bridge() 202 | else: 203 | print("Kullanım: python windows_bridge_config.py [setup|check|remove]") 204 | else: 205 | # Varsayılan: setup 206 | setup_bridge() 207 | -------------------------------------------------------------------------------- /style.qss: -------------------------------------------------------------------------------- 1 | /* Modern Compact Theme for Warp Hesap Yöneticisi */ 2 | 3 | /* Global */ 4 | QMainWindow, QWidget { 5 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 6 | stop: 0 #f8fafc, stop: 1 #f1f5f9); 7 | color: #1e293b; 8 | font-family: "Segoe UI", "SF Pro Display", "Inter", system-ui, sans-serif; 9 | font-size: 10pt; 10 | font-weight: 400; 11 | } 12 | 13 | /* Labels */ 14 | QLabel { 15 | color: #334155; 16 | font-weight: 500; 17 | } 18 | 19 | /* Status Bar */ 20 | QStatusBar { 21 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 22 | stop: 0 #ffffff, stop: 1 #f8fafc); 23 | border-top: 1px solid #e2e8f0; 24 | color: #64748b; 25 | font-size: 9pt; 26 | } 27 | 28 | /* Buttons - Modern Glass Effect */ 29 | QPushButton { 30 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 31 | stop: 0 #ffffff, stop: 1 #f8fafc); 32 | border: 1px solid #e2e8f0; 33 | border-radius: 8px; 34 | padding: 8px 16px; 35 | color: #475569; 36 | font-weight: 500; 37 | font-size: 10pt; 38 | } 39 | 40 | QPushButton:hover { 41 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 42 | stop: 0 #f8fafc, stop: 1 #f1f5f9); 43 | border-color: #cbd5e1; 44 | } 45 | 46 | QPushButton:pressed { 47 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 48 | stop: 0 #e2e8f0, stop: 1 #cbd5e1); 49 | } 50 | 51 | QPushButton:disabled { 52 | color: #94a3b8; 53 | background: #f8fafc; 54 | border-color: #f1f5f9; 55 | } 56 | 57 | /* Accent Buttons with Beautiful Gradients */ 58 | QPushButton#StartButton { 59 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 60 | stop: 0 #10b981, stop: 1 #059669); 61 | border: 1px solid #047857; 62 | color: white; 63 | font-weight: 600; 64 | } 65 | QPushButton#StartButton:hover { 66 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 67 | stop: 0 #34d399, stop: 1 #10b981); 68 | border-color: #065f46; 69 | } 70 | 71 | QPushButton#StopButton { 72 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 73 | stop: 0 #ef4444, stop: 1 #dc2626); 74 | border: 1px solid #b91c1c; 75 | color: white; 76 | font-weight: 600; 77 | } 78 | QPushButton#StopButton:hover { 79 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 80 | stop: 0 #f87171, stop: 1 #ef4444); 81 | border-color: #991b1b; 82 | } 83 | 84 | QPushButton#AddButton { 85 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 86 | stop: 0 #3b82f6, stop: 1 #2563eb); 87 | border: 1px solid #1d4ed8; 88 | color: white; 89 | font-weight: 600; 90 | } 91 | QPushButton#AddButton:hover { 92 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 93 | stop: 0 #60a5fa, stop: 1 #3b82f6); 94 | border-color: #1e40af; 95 | } 96 | 97 | QPushButton#RefreshButton { 98 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 99 | stop: 0 #8b5cf6, stop: 1 #7c3aed); 100 | border: 1px solid #6d28d9; 101 | color: white; 102 | font-weight: 600; 103 | } 104 | QPushButton#RefreshButton:hover { 105 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 106 | stop: 0 #a78bfa, stop: 1 #8b5cf6); 107 | border-color: #5b21b6; 108 | } 109 | 110 | /* ComboBox - Modern Style */ 111 | QComboBox { 112 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 113 | stop: 0 #ffffff, stop: 1 #f8fafc); 114 | border: 1px solid #e2e8f0; 115 | border-radius: 6px; 116 | padding: 4px 8px; 117 | color: #475569; 118 | font-weight: 500; 119 | } 120 | 121 | QComboBox:hover { 122 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 123 | stop: 0 #f8fafc, stop: 1 #f1f5f9); 124 | border-color: #cbd5e1; 125 | } 126 | 127 | QComboBox::drop-down { 128 | border: none; 129 | width: 20px; 130 | } 131 | 132 | QComboBox::down-arrow { 133 | width: 12px; 134 | height: 12px; 135 | margin-right: 4px; 136 | } 137 | 138 | QComboBox QAbstractItemView { 139 | background: #ffffff; 140 | border: 1px solid #e2e8f0; 141 | border-radius: 8px; 142 | selection-background-color: #3b82f6; 143 | selection-color: white; 144 | outline: none; 145 | } 146 | 147 | /* Text Edits - Clean and Modern */ 148 | QTextEdit { 149 | background: #ffffff; 150 | border: 2px solid #e2e8f0; 151 | border-radius: 10px; 152 | padding: 12px; 153 | color: #334155; 154 | font-size: 10pt; 155 | selection-background-color: #dbeafe; 156 | } 157 | 158 | QTextEdit:focus { 159 | border-color: #3b82f6; 160 | background: #fefefe; 161 | } 162 | 163 | /* Table - Beautiful Modern Design */ 164 | QTableWidget { 165 | background: #ffffff; 166 | border: 1px solid #e2e8f0; 167 | border-radius: 12px; 168 | gridline-color: transparent; 169 | alternate-background-color: #f8fafc; 170 | selection-background-color: #dbeafe; 171 | selection-color: #1e293b; 172 | outline: none; 173 | } 174 | 175 | QTableWidget::item { 176 | padding: 8px 12px; 177 | border: none; 178 | color: #334155; 179 | } 180 | 181 | QTableWidget::item:selected { 182 | background: #dbeafe; 183 | color: #1e40af; 184 | } 185 | 186 | /* Table Header - Elegant */ 187 | QHeaderView::section { 188 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 189 | stop: 0 #f8fafc, stop: 1 #f1f5f9); 190 | color: #475569; 191 | border: none; 192 | border-bottom: 2px solid #e2e8f0; 193 | padding: 10px 12px; 194 | font-weight: 600; 195 | font-size: 10pt; 196 | } 197 | 198 | QHeaderView::section:first { 199 | border-top-left-radius: 12px; 200 | } 201 | 202 | QHeaderView::section:last { 203 | border-top-right-radius: 12px; 204 | } 205 | 206 | QTableCornerButton::section { 207 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 208 | stop: 0 #f8fafc, stop: 1 #f1f5f9); 209 | border: none; 210 | border-bottom: 2px solid #e2e8f0; 211 | border-top-left-radius: 12px; 212 | } 213 | 214 | /* Scrollbars - Minimal and Modern */ 215 | QScrollBar:vertical { 216 | background: #f8fafc; 217 | width: 8px; 218 | border-radius: 4px; 219 | margin: 0; 220 | } 221 | 222 | QScrollBar::handle:vertical { 223 | background: #cbd5e1; 224 | border-radius: 4px; 225 | min-height: 20px; 226 | } 227 | 228 | QScrollBar::handle:vertical:hover { 229 | background: #94a3b8; 230 | } 231 | 232 | QScrollBar::add-line:vertical, 233 | QScrollBar::sub-line:vertical { 234 | height: 0px; 235 | } 236 | 237 | QScrollBar:horizontal { 238 | background: #f8fafc; 239 | height: 8px; 240 | border-radius: 4px; 241 | margin: 0; 242 | } 243 | 244 | QScrollBar::handle:horizontal { 245 | background: #cbd5e1; 246 | border-radius: 4px; 247 | min-width: 20px; 248 | } 249 | 250 | QScrollBar::handle:horizontal:hover { 251 | background: #94a3b8; 252 | } 253 | 254 | QScrollBar::add-line:horizontal, 255 | QScrollBar::sub-line:horizontal { 256 | width: 0px; 257 | } 258 | 259 | /* Progress Dialog - Clean */ 260 | QProgressDialog { 261 | background: #ffffff; 262 | border: 1px solid #e2e8f0; 263 | border-radius: 12px; 264 | } 265 | 266 | QProgressBar { 267 | background: #f1f5f9; 268 | border: 1px solid #e2e8f0; 269 | border-radius: 6px; 270 | text-align: center; 271 | color: #475569; 272 | font-weight: 500; 273 | } 274 | 275 | QProgressBar::chunk { 276 | background: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, 277 | stop: 0 #3b82f6, stop: 1 #1d4ed8); 278 | border-radius: 5px; 279 | } 280 | 281 | /* Dialog Windows */ 282 | QDialog { 283 | background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, 284 | stop: 0 #ffffff, stop: 1 #f8fafc); 285 | border-radius: 12px; 286 | } 287 | 288 | /* Menu */ 289 | QMenu { 290 | background: #ffffff; 291 | border: 1px solid #e2e8f0; 292 | border-radius: 8px; 293 | padding: 4px; 294 | color: #334155; 295 | } 296 | 297 | QMenu::item { 298 | padding: 8px 16px; 299 | border-radius: 6px; 300 | margin: 2px; 301 | } 302 | 303 | QMenu::item:selected { 304 | background: #f1f5f9; 305 | color: #1e40af; 306 | } 307 | 308 | QMenu::separator { 309 | height: 1px; 310 | background: #e2e8f0; 311 | margin: 4px 8px; 312 | } 313 | 314 | /* Tooltips */ 315 | QToolTip { 316 | background: #1e293b; 317 | color: #f8fafc; 318 | border: none; 319 | border-radius: 6px; 320 | padding: 6px 10px; 321 | font-size: 9pt; 322 | } 323 | -------------------------------------------------------------------------------- /warp_bridge_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | 4 | """ 5 | HTTP server for Warp Account Bridge - Chrome extension integration 6 | """ 7 | 8 | import json 9 | import threading 10 | import time 11 | from http.server import HTTPServer, BaseHTTPRequestHandler 12 | try: 13 | # Python 3.7+ 14 | from http.server import ThreadingHTTPServer as _ThreadingHTTPServer 15 | except ImportError: # pragma: no cover 16 | from socketserver import ThreadingMixIn 17 | 18 | class _ThreadingHTTPServer(ThreadingMixIn, HTTPServer): 19 | daemon_threads = True 20 | from urllib.parse import urlparse, parse_qs 21 | import sqlite3 22 | from languages import get_language_manager, _ 23 | 24 | class BridgeRequestHandler(BaseHTTPRequestHandler): 25 | def __init__(self, *args, account_manager=None, on_account_added=None, **kwargs): 26 | self.account_manager = account_manager 27 | self.on_account_added = on_account_added 28 | super().__init__(*args, **kwargs) 29 | 30 | def _set_cors_headers(self): 31 | """CORS headers for browser requests""" 32 | self.send_header('Access-Control-Allow-Origin', '*') 33 | self.send_header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS') 34 | self.send_header('Access-Control-Allow-Headers', 'Content-Type, X-Extension-ID') 35 | 36 | def _send_json_response(self, status_code, data): 37 | """Send JSON response""" 38 | self.send_response(status_code) 39 | self.send_header('Content-Type', 'application/json') 40 | self._set_cors_headers() 41 | self.end_headers() 42 | response_data = json.dumps(data, ensure_ascii=False) 43 | self.wfile.write(response_data.encode('utf-8')) 44 | 45 | def _verify_extension(self): 46 | """Verify request comes from our extension""" 47 | extension_id = self.headers.get('X-Extension-ID') 48 | return extension_id == 'warp-account-bridge-v1' 49 | 50 | def do_OPTIONS(self): 51 | """Handle CORS preflight requests""" 52 | self.send_response(200) 53 | self._set_cors_headers() 54 | self.end_headers() 55 | 56 | def do_GET(self): 57 | """Handle GET requests""" 58 | parsed_url = urlparse(self.path) 59 | 60 | if parsed_url.path == '/health': 61 | # Health check endpoint 62 | self._send_json_response(200, { 63 | 'status': 'ok', 64 | 'service': 'warp-bridge', 65 | 'timestamp': int(time.time()) 66 | }) 67 | else: 68 | self._send_json_response(404, {'error': 'Endpoint not found'}) 69 | 70 | def do_POST(self): 71 | """Handle POST requests""" 72 | parsed_url = urlparse(self.path) 73 | 74 | if not self._verify_extension(): 75 | self._send_json_response(403, {'error': 'Unauthorized - Invalid extension ID'}) 76 | return 77 | 78 | if parsed_url.path == '/add-account': 79 | self._handle_add_account() 80 | elif parsed_url.path == '/setup-bridge': 81 | self._handle_setup_bridge() 82 | else: 83 | self._send_json_response(404, {'error': 'Endpoint not found'}) 84 | 85 | def _handle_add_account(self): 86 | """Handle account addition from extension""" 87 | try: 88 | # Read request body 89 | content_length = int(self.headers.get('Content-Length', 0)) 90 | if content_length == 0: 91 | self._send_json_response(400, {'error': 'Empty request body'}) 92 | return 93 | 94 | body = self.rfile.read(content_length) 95 | account_data = json.loads(body.decode('utf-8')) 96 | 97 | # Validate account data structure 98 | if not self._validate_account_data(account_data): 99 | self._send_json_response(400, {'error': 'Invalid account data structure'}) 100 | return 101 | 102 | # Convert to JSON string for AccountManager 103 | account_json = json.dumps(account_data, ensure_ascii=False) 104 | 105 | # Add account using AccountManager 106 | if self.account_manager: 107 | success, message = self.account_manager.add_account(account_json) 108 | 109 | if success: 110 | print(f"✅ Bridge: Hesap eklendi - {account_data.get('email', 'Unknown')}") 111 | 112 | # Yanıtı hemen döndür, UI yenilemeyi arka planda tetikle 113 | self._send_json_response(200, { 114 | 'success': True, 115 | 'message': message, 116 | 'email': account_data.get('email') 117 | }) 118 | 119 | if self.on_account_added: 120 | try: 121 | threading.Thread( 122 | target=self.on_account_added, 123 | args=(account_data.get('email'),), 124 | daemon=True 125 | ).start() 126 | except Exception as e: 127 | print(f"⚠️ Tablo güncelleme hatası: {e}") 128 | return 129 | else: 130 | print(f"❌ Bridge: Hesap ekleme hatası - {message}") 131 | self._send_json_response(400, { 132 | 'success': False, 133 | 'error': message 134 | }) 135 | else: 136 | self._send_json_response(500, {'error': 'Account manager not available'}) 137 | 138 | except json.JSONDecodeError: 139 | self._send_json_response(400, {'error': 'Invalid JSON data'}) 140 | except Exception as e: 141 | print(f"❌ Bridge: Add account error - {str(e)}") 142 | self._send_json_response(500, {'error': f'Server error: {str(e)}'}) 143 | 144 | def _handle_setup_bridge(self): 145 | """Handle bridge setup from extension""" 146 | try: 147 | content_length = int(self.headers.get('Content-Length', 0)) 148 | if content_length > 0: 149 | body = self.rfile.read(content_length) 150 | setup_data = json.loads(body.decode('utf-8')) 151 | print(f"🔗 Bridge: Extension connected - ID: {setup_data.get('extensionId', 'Unknown')}") 152 | 153 | self._send_json_response(200, { 154 | 'success': True, 155 | 'message': 'Bridge setup successful', 156 | 'server_version': '1.0' 157 | }) 158 | 159 | except Exception as e: 160 | print(f"❌ Bridge: Setup error - {str(e)}") 161 | self._send_json_response(500, {'error': f'Setup error: {str(e)}'}) 162 | 163 | def _validate_account_data(self, data): 164 | """Validate account data structure""" 165 | try: 166 | # Check required fields 167 | required_fields = ['email', 'stsTokenManager'] 168 | for field in required_fields: 169 | if field not in data: 170 | return False 171 | 172 | # Check stsTokenManager structure 173 | sts_manager = data['stsTokenManager'] 174 | required_sts_fields = ['accessToken', 'refreshToken'] 175 | for field in required_sts_fields: 176 | if field not in sts_manager: 177 | return False 178 | 179 | return True 180 | 181 | except Exception: 182 | return False 183 | 184 | def log_message(self, format, *args): 185 | """Override to reduce log noise""" 186 | pass # Silent logging 187 | 188 | 189 | class WarpBridgeServer: 190 | def __init__(self, account_manager, port=8765, on_account_added=None): 191 | self.account_manager = account_manager 192 | self.port = port 193 | self.server = None 194 | self.server_thread = None 195 | self.running = False 196 | self.on_account_added = on_account_added 197 | 198 | def start(self): 199 | """Start the bridge server""" 200 | try: 201 | # Create request handler with account_manager 202 | def handler(*args, **kwargs): 203 | return BridgeRequestHandler(*args, account_manager=self.account_manager, 204 | on_account_added=self.on_account_added, **kwargs) 205 | 206 | self.server = _ThreadingHTTPServer(('localhost', self.port), handler) 207 | try: 208 | self.server.daemon_threads = True 209 | self.server.allow_reuse_address = True 210 | except Exception: 211 | pass 212 | self.running = True 213 | 214 | # Start server in separate thread 215 | self.server_thread = threading.Thread(target=self._run_server, daemon=True) 216 | self.server_thread.start() 217 | 218 | print(f"🌉 Bridge Server başlatıldı: http://localhost:{self.port}") 219 | return True 220 | 221 | except Exception as e: 222 | print(f"❌ Bridge Server başlatma hatası: {e}") 223 | return False 224 | 225 | def _run_server(self): 226 | """Run the server in thread""" 227 | try: 228 | self.server.serve_forever() 229 | except Exception as e: 230 | if self.running: # Only show error if we're supposed to be running 231 | print(f"❌ Bridge Server çalışma hatası: {e}") 232 | 233 | def stop(self): 234 | """Stop the bridge server""" 235 | if self.server and self.running: 236 | self.running = False 237 | self.server.shutdown() 238 | if self.server_thread: 239 | self.server_thread.join(timeout=2) 240 | print("🛑 Bridge Server durduruldu") 241 | 242 | def is_running(self): 243 | """Check if server is running""" 244 | return self.running and self.server_thread and self.server_thread.is_alive() 245 | 246 | 247 | # Test function 248 | if __name__ == "__main__": 249 | from warp_account_manager import AccountManager 250 | 251 | print("Testing Warp Bridge Server...") 252 | 253 | # Create account manager 254 | account_manager = AccountManager() 255 | 256 | # Start bridge server 257 | bridge = WarpBridgeServer(account_manager) 258 | 259 | if bridge.start(): 260 | print("Bridge server is running. Press Ctrl+C to stop.") 261 | try: 262 | while True: 263 | time.sleep(1) 264 | except KeyboardInterrupt: 265 | bridge.stop() 266 | print("Bridge server stopped.") 267 | else: 268 | print("Failed to start bridge server.") 269 | -------------------------------------------------------------------------------- /chrome-extension/content.js: -------------------------------------------------------------------------------- 1 | // Content script for Warp Account Bridge 2 | // Runs on https://app.warp.dev/logged_in/remote pages 3 | 4 | const BRIDGE_CONFIG = { 5 | pythonAppPort: 8765, 6 | extensionId: "warp-account-bridge-v1", 7 | }; 8 | 9 | let bridgeButton = null; 10 | let isDataExtracted = false; 11 | let isProcessing = false; 12 | 13 | // Check if we can extract data 14 | async function checkDataAvailability() { 15 | try { 16 | const request = indexedDB.open("firebaseLocalStorageDb"); 17 | 18 | return new Promise((resolve) => { 19 | request.onsuccess = function (event) { 20 | const db = event.target.result; 21 | const transaction = db.transaction(["firebaseLocalStorage"], "readonly"); 22 | const objectStore = transaction.objectStore("firebaseLocalStorage"); 23 | 24 | objectStore.getAll().onsuccess = function (event) { 25 | const results = event.target.result; 26 | const hasValidData = results.some((item) => item.value && typeof item.value === "object" && item.value.email && item.value.stsTokenManager); 27 | resolve(hasValidData); 28 | }; 29 | 30 | objectStore.getAll().onerror = () => resolve(false); 31 | }; 32 | 33 | request.onerror = () => resolve(false); 34 | }); 35 | } catch (error) { 36 | console.log("Data check error:", error); 37 | return false; 38 | } 39 | } 40 | 41 | // Extract account data 42 | async function extractAccountData() { 43 | try { 44 | const request = indexedDB.open("firebaseLocalStorageDb"); 45 | 46 | return new Promise((resolve, reject) => { 47 | request.onsuccess = function (event) { 48 | const db = event.target.result; 49 | const transaction = db.transaction(["firebaseLocalStorage"], "readonly"); 50 | const objectStore = transaction.objectStore("firebaseLocalStorage"); 51 | 52 | objectStore.getAll().onsuccess = function (event) { 53 | const results = event.target.result; 54 | 55 | for (let result of results) { 56 | if (result.value && typeof result.value === "object" && result.value.email && result.value.stsTokenManager) { 57 | resolve(result.value); 58 | return; 59 | } 60 | } 61 | reject(new Error("No valid account data found")); 62 | }; 63 | 64 | objectStore.getAll().onerror = () => reject(new Error("Database read error")); 65 | }; 66 | 67 | request.onerror = () => reject(new Error("Database connection error")); 68 | }); 69 | } catch (error) { 70 | throw new Error(`Data extraction failed: ${error.message}`); 71 | } 72 | } 73 | 74 | // Send data to Python app 75 | async function sendDataToPythonApp(accountData) { 76 | try { 77 | console.log("Sending account data to bridge server..."); 78 | const response = await fetch(`http://localhost:${BRIDGE_CONFIG.pythonAppPort}/add-account`, { 79 | method: "POST", 80 | headers: { 81 | "Content-Type": "application/json", 82 | "X-Extension-ID": BRIDGE_CONFIG.extensionId, 83 | }, 84 | body: JSON.stringify(accountData), 85 | }); 86 | 87 | if (response.ok) { 88 | const result = await response.json(); 89 | console.log("Account successfully sent to bridge server"); 90 | return { success: true, message: result.message || "Account added successfully" }; 91 | } else { 92 | const error = await response.text(); 93 | console.error("Bridge server returned error:", error); 94 | return { success: false, message: `Server error: ${error}` }; 95 | } 96 | } catch (error) { 97 | console.error("Bridge connection error:", error); 98 | if (error.message.includes("Failed to fetch") || error.message.includes("ERR_CONNECTION_REFUSED")) { 99 | return { success: false, message: "Bridge server not running. Please start Warp Account Manager first!" }; 100 | } 101 | return { success: false, message: `Connection failed: ${error.message}` }; 102 | } 103 | } 104 | 105 | // Create and show bridge button 106 | function createBridgeButton() { 107 | if (bridgeButton) return; 108 | 109 | bridgeButton = document.createElement("div"); 110 | bridgeButton.id = "warp-bridge-button"; 111 | bridgeButton.innerHTML = ` 112 |
mitmproxy-ca-cert.cer dosyasına çift tıklayınmitmproxy-ca-cert.cer file