Compare commits
1 Commits
feature/me
...
v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b48478746 |
@@ -131,6 +131,102 @@
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T13:26:42.615884",
|
||||
"created_at": "2025-02-11T13:26:42.615884"
|
||||
},
|
||||
{
|
||||
"email": "fzbsolew265285@586vip.cn",
|
||||
"password": "HdI@COBPCO9x",
|
||||
"first_name": "Kdlynp",
|
||||
"last_name": "Omcope",
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNE45VFowOUc3R1haMDhHVlgxQzZYIiwidGltZSI6IjE3MzkyNjUzNDMiLCJyYW5kb21uZXNzIjoiOTRiZWM5YTctOWYyMi00NGFhIiwiZXhwIjo0MzMxMjY1MzQzLCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.ZnYwmu8RF4BvEaH7ZFWgnzgn6ZIBMHxKqS2-ZQu7W-0",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNE45VFowOUc3R1haMDhHVlgxQzZYIiwidGltZSI6IjE3MzkyNjUzNDMiLCJyYW5kb21uZXNzIjoiOTRiZWM5YTctOWYyMi00NGFhIiwiZXhwIjo0MzMxMjY1MzQzLCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.ZnYwmu8RF4BvEaH7ZFWgnzgn6ZIBMHxKqS2-ZQu7W-0",
|
||||
"machine_id": "",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T17:16:21.905458",
|
||||
"created_at": "2025-02-11T17:16:21.905458"
|
||||
},
|
||||
{
|
||||
"email": "chvldgvz265405@586vip.cn",
|
||||
"password": "HdI@COBPCO9x",
|
||||
"first_name": "Nsgtsc",
|
||||
"last_name": "Yrgcuy",
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNFJYODE0WVhQMlpaWkpENk1aUlI1IiwidGltZSI6IjE3MzkyNjU0NjIiLCJyYW5kb21uZXNzIjoiZDJiNDAzMDQtNTcyNy00ZTg5IiwiZXhwIjo0MzMxMjY1NDYyLCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.dBB1AiYk06INf_YnN8Kuu1ZgI9kUi5eDqWz4C2ExfQg",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNFJYODE0WVhQMlpaWkpENk1aUlI1IiwidGltZSI6IjE3MzkyNjU0NjIiLCJyYW5kb21uZXNzIjoiZDJiNDAzMDQtNTcyNy00ZTg5IiwiZXhwIjo0MzMxMjY1NDYyLCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.dBB1AiYk06INf_YnN8Kuu1ZgI9kUi5eDqWz4C2ExfQg",
|
||||
"machine_id": "",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T17:18:16.076468",
|
||||
"created_at": "2025-02-11T17:18:16.076468"
|
||||
},
|
||||
{
|
||||
"email": "skdjndzg265518@586vip.cn",
|
||||
"password": "HdI@COBPCO9x",
|
||||
"first_name": "Suykzr",
|
||||
"last_name": "Fomxgs",
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNFdCWENBVFpCMkcwQkFCMlExQUdDIiwidGltZSI6IjE3MzkyNjU1NzQiLCJyYW5kb21uZXNzIjoiZTU1Mzk3YjgtYzU5Ny00ZWIwIiwiZXhwIjo0MzMxMjY1NTc0LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.bIrBvtQxgV8tiD0MK8ZkdBnvoCvWcmGWbMzXyJo__-Q",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNFdCWENBVFpCMkcwQkFCMlExQUdDIiwidGltZSI6IjE3MzkyNjU1NzQiLCJyYW5kb21uZXNzIjoiZTU1Mzk3YjgtYzU5Ny00ZWIwIiwiZXhwIjo0MzMxMjY1NTc0LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.bIrBvtQxgV8tiD0MK8ZkdBnvoCvWcmGWbMzXyJo__-Q",
|
||||
"machine_id": "",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T17:20:12.770495",
|
||||
"created_at": "2025-02-11T17:20:12.770495"
|
||||
},
|
||||
{
|
||||
"email": "qgmjlglr265641@586vip.cn",
|
||||
"password": "HdI@COBPCO9x",
|
||||
"first_name": "Ozyepu",
|
||||
"last_name": "Nyrnjw",
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNTA1Vk5WOFE4Mko1OERKQlc0NFFKIiwidGltZSI6IjE3MzkyNjU2OTkiLCJyYW5kb21uZXNzIjoiOWQ2Y2NjYTMtYTU4Yy00OWI0IiwiZXhwIjo0MzMxMjY1Njk5LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.cuR7IJ2SDyvWHzdXk6wfRDL1L2AH38AIs1hweN49u2s",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNTA1Vk5WOFE4Mko1OERKQlc0NFFKIiwidGltZSI6IjE3MzkyNjU2OTkiLCJyYW5kb21uZXNzIjoiOWQ2Y2NjYTMtYTU4Yy00OWI0IiwiZXhwIjo0MzMxMjY1Njk5LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.cuR7IJ2SDyvWHzdXk6wfRDL1L2AH38AIs1hweN49u2s",
|
||||
"machine_id": "",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T17:22:17.167933",
|
||||
"created_at": "2025-02-11T17:22:17.167933"
|
||||
},
|
||||
{
|
||||
"email": "cetkjbyo265764@586vip.cn",
|
||||
"password": "HdI@COBPCO9x",
|
||||
"first_name": "Ykaokw",
|
||||
"last_name": "Xgnibi",
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNTNXUUtRRkY1VEpQNTJQV1o1V1k2IiwidGltZSI6IjE3MzkyNjU4MjEiLCJyYW5kb21uZXNzIjoiYThkNTZiODgtYTQ2OS00NDY0IiwiZXhwIjo0MzMxMjY1ODIxLCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.2VcD_cjuI1V6775SrHuJEPKMJz094yRywVC-SdgKMl8",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNTNXUUtRRkY1VEpQNTJQV1o1V1k2IiwidGltZSI6IjE3MzkyNjU4MjEiLCJyYW5kb21uZXNzIjoiYThkNTZiODgtYTQ2OS00NDY0IiwiZXhwIjo0MzMxMjY1ODIxLCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.2VcD_cjuI1V6775SrHuJEPKMJz094yRywVC-SdgKMl8",
|
||||
"machine_id": "",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T17:24:20.739727",
|
||||
"created_at": "2025-02-11T17:24:20.739727"
|
||||
},
|
||||
{
|
||||
"email": "vosglsoj265881@586vip.cn",
|
||||
"password": "HdI@COBPCO9x",
|
||||
"first_name": "Tbkztl",
|
||||
"last_name": "Cpcnyd",
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNTdGMjQ3QktYNlFHRlpTNjVOOFBXIiwidGltZSI6IjE3MzkyNjU5MzgiLCJyYW5kb21uZXNzIjoiOWIzNjdmN2QtNmRkMy00ZGNkIiwiZXhwIjo0MzMxMjY1OTM4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.6hR-fP769x368tTlBjmtIK0ZpHeJOE9Y4FynxAr48bI",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNTdGMjQ3QktYNlFHRlpTNjVOOFBXIiwidGltZSI6IjE3MzkyNjU5MzgiLCJyYW5kb21uZXNzIjoiOWIzNjdmN2QtNmRkMy00ZGNkIiwiZXhwIjo0MzMxMjY1OTM4LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.6hR-fP769x368tTlBjmtIK0ZpHeJOE9Y4FynxAr48bI",
|
||||
"machine_id": "",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T17:26:21.044597",
|
||||
"created_at": "2025-02-11T17:26:21.044597"
|
||||
},
|
||||
{
|
||||
"email": "otzumrrm266001@586vip.cn",
|
||||
"password": "HdI@COBPCO9x",
|
||||
"first_name": "Mfmwza",
|
||||
"last_name": "Axmmui",
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNUIzNEM2OEc4Szc1NlM2SE5YMFIyIiwidGltZSI6IjE3MzkyNjYwNTUiLCJyYW5kb21uZXNzIjoiYmM0NWIyZTYtNjgxMS00OTE4IiwiZXhwIjo0MzMxMjY2MDU1LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.geHcjT0DzddtOpxILQTawKvc90_dqJG6c-_ZDS9ZVUw",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNUIzNEM2OEc4Szc1NlM2SE5YMFIyIiwidGltZSI6IjE3MzkyNjYwNTUiLCJyYW5kb21uZXNzIjoiYmM0NWIyZTYtNjgxMS00OTE4IiwiZXhwIjo0MzMxMjY2MDU1LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.geHcjT0DzddtOpxILQTawKvc90_dqJG6c-_ZDS9ZVUw",
|
||||
"machine_id": "",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T17:28:13.605804",
|
||||
"created_at": "2025-02-11T17:28:13.605804"
|
||||
},
|
||||
{
|
||||
"email": "nrnivqap266115@nosqli.com",
|
||||
"password": "HdI@COBPCO9x",
|
||||
"first_name": "Veqlgf",
|
||||
"last_name": "Qwxxdc",
|
||||
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNUVGQlk0RDRZV1paWTVSNUpFUjhYIiwidGltZSI6IjE3MzkyNjYxNjYiLCJyYW5kb21uZXNzIjoiMjM4YzM5MGEtY2U4Mi00ZDQ2IiwiZXhwIjo0MzMxMjY2MTY2LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.fPCSlBZR8ZoKKfij6NYRz0lDvIFm3Rrs2KZMGJIyWAE",
|
||||
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhdXRoMHx1c2VyXzAxSktUNUVGQlk0RDRZV1paWTVSNUpFUjhYIiwidGltZSI6IjE3MzkyNjYxNjYiLCJyYW5kb21uZXNzIjoiMjM4YzM5MGEtY2U4Mi00ZDQ2IiwiZXhwIjo0MzMxMjY2MTY2LCJpc3MiOiJodHRwczovL2F1dGhlbnRpY2F0aW9uLmN1cnNvci5zaCIsInNjb3BlIjoib3BlbmlkIHByb2ZpbGUgZW1haWwgb2ZmbGluZV9hY2Nlc3MiLCJhdWQiOiJodHRwczovL2N1cnNvci5jb20ifQ.fPCSlBZR8ZoKKfij6NYRz0lDvIFm3Rrs2KZMGJIyWAE",
|
||||
"machine_id": "",
|
||||
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
"registration_time": "2025-02-11T17:30:05.829510",
|
||||
"created_at": "2025-02-11T17:30:05.829510"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -5,9 +5,13 @@ import logging
|
||||
import subprocess
|
||||
import uuid
|
||||
import hashlib
|
||||
import sys
|
||||
import time
|
||||
from typing import Optional, Dict, Tuple
|
||||
from pathlib import Path
|
||||
from utils.config import Config
|
||||
from utils.cursor_registry import CursorRegistry
|
||||
from cursor_auth_manager import CursorAuthManager
|
||||
|
||||
def get_hardware_id() -> str:
|
||||
"""获取硬件唯一标识"""
|
||||
@@ -32,35 +36,6 @@ def get_hardware_id() -> str:
|
||||
# 如果获取失败,使用UUID作为备选方案
|
||||
return str(uuid.uuid4())
|
||||
|
||||
class CursorAuthManager:
|
||||
def __init__(self):
|
||||
self.cursor_path = Path(os.path.expanduser("~")) / "AppData" / "Local" / "Programs" / "Cursor"
|
||||
self.app_path = self.cursor_path / "resources" / "app"
|
||||
self.package_json = self.app_path / "package.json"
|
||||
|
||||
def update_auth(self, email: str, access_token: str, refresh_token: str) -> bool:
|
||||
"""更新Cursor认证信息"""
|
||||
try:
|
||||
# 读取package.json
|
||||
with open(self.package_json, "r", encoding="utf-8") as f:
|
||||
data = json.load(f)
|
||||
|
||||
# 更新认证信息
|
||||
data["email"] = email
|
||||
data["accessToken"] = access_token
|
||||
data["refreshToken"] = refresh_token
|
||||
|
||||
# 保存更新后的文件
|
||||
with open(self.package_json, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
logging.info(f"认证信息更新成功: {email}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"更新认证信息失败: {str(e)}")
|
||||
return False
|
||||
|
||||
class AccountSwitcher:
|
||||
def __init__(self):
|
||||
self.cursor_path = Path(os.path.expanduser("~")) / "AppData" / "Local" / "Programs" / "Cursor"
|
||||
@@ -69,6 +44,7 @@ class AccountSwitcher:
|
||||
self.auth_manager = CursorAuthManager()
|
||||
self.config = Config()
|
||||
self.hardware_id = get_hardware_id()
|
||||
self.registry = CursorRegistry() # 添加注册表操作工具类
|
||||
|
||||
def get_device_info(self) -> dict:
|
||||
"""获取设备信息"""
|
||||
@@ -384,6 +360,142 @@ class AccountSwitcher:
|
||||
"activation_records": []
|
||||
}
|
||||
|
||||
def restart_cursor(self) -> bool:
|
||||
"""重启Cursor编辑器
|
||||
|
||||
Returns:
|
||||
bool: 是否成功重启
|
||||
"""
|
||||
try:
|
||||
logging.info("正在重启Cursor...")
|
||||
if sys.platform == "win32":
|
||||
# Windows系统
|
||||
# 关闭Cursor
|
||||
os.system("taskkill /f /im Cursor.exe 2>nul")
|
||||
time.sleep(2)
|
||||
# 获取Cursor安装路径
|
||||
cursor_exe = self.cursor_path / "Cursor.exe"
|
||||
if cursor_exe.exists():
|
||||
# 启动Cursor
|
||||
os.startfile(str(cursor_exe))
|
||||
logging.info("Cursor重启成功")
|
||||
return True
|
||||
else:
|
||||
logging.error(f"未找到Cursor程序: {cursor_exe}")
|
||||
return False
|
||||
elif sys.platform == "darwin":
|
||||
# macOS系统
|
||||
os.system("killall Cursor 2>/dev/null")
|
||||
time.sleep(2)
|
||||
os.system("open -a Cursor")
|
||||
logging.info("Cursor重启成功")
|
||||
return True
|
||||
elif sys.platform == "linux":
|
||||
# Linux系统
|
||||
os.system("pkill -f cursor")
|
||||
time.sleep(2)
|
||||
os.system("cursor &")
|
||||
logging.info("Cursor重启成功")
|
||||
return True
|
||||
else:
|
||||
logging.error(f"不支持的操作系统: {sys.platform}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"重启Cursor时发生错误: {str(e)}")
|
||||
return False
|
||||
|
||||
def refresh_cursor_auth(self) -> Tuple[bool, str]:
|
||||
"""刷新Cursor授权
|
||||
|
||||
Returns:
|
||||
Tuple[bool, str]: (是否成功, 提示消息)
|
||||
"""
|
||||
try:
|
||||
# 获取未使用的账号
|
||||
endpoint = "https://cursorapi.nosqli.com/admin/api.account/getUnused"
|
||||
data = {
|
||||
"machine_id": self.hardware_id
|
||||
}
|
||||
headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
try:
|
||||
# 添加SSL验证选项和超时设置
|
||||
response = requests.post(
|
||||
endpoint,
|
||||
json=data,
|
||||
headers=headers,
|
||||
timeout=30, # 增加超时时间
|
||||
verify=False, # 禁用SSL验证
|
||||
)
|
||||
# 禁用SSL警告
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
response_data = response.json()
|
||||
|
||||
if response_data.get("code") == 200:
|
||||
account_data = response_data.get("data", {})
|
||||
|
||||
# 获取账号信息
|
||||
email = account_data.get("email", "")
|
||||
access_token = account_data.get("access_token", "")
|
||||
refresh_token = account_data.get("refresh_token", "")
|
||||
expire_time = account_data.get("expire_time", "")
|
||||
days_left = account_data.get("days_left", 0)
|
||||
|
||||
if not all([email, access_token, refresh_token]):
|
||||
return False, "获取账号信息不完整"
|
||||
|
||||
# 更新Cursor认证信息
|
||||
if not self.auth_manager.update_auth(email, access_token, refresh_token):
|
||||
return False, "更新Cursor认证信息失败"
|
||||
|
||||
# 重置机器码
|
||||
if not self.reset_machine_id():
|
||||
return False, "重置机器码失败"
|
||||
|
||||
# 刷新注册表
|
||||
if not self.registry.refresh_registry():
|
||||
logging.warning("注册表刷新失败,但不影响主要功能")
|
||||
|
||||
# 重启Cursor
|
||||
if not self.auth_manager.restart_cursor():
|
||||
return False, "重启Cursor失败"
|
||||
# 重启Cursor
|
||||
# if not self.restart_cursor():
|
||||
# logging.warning("Cursor重启失败,请手动重启")
|
||||
# return True, f"授权刷新成功,请手动重启Cursor编辑器\n邮箱: {email}\n到期时间: {expire_time}\n剩余天数: {days_left}天"
|
||||
|
||||
return True, f"授权刷新成功,Cursor编辑器已重启\n邮箱: {email}\n"
|
||||
|
||||
elif response_data.get("code") == 404:
|
||||
return False, "没有可用的未使用账号"
|
||||
else:
|
||||
error_msg = response_data.get("msg", "未知错误")
|
||||
logging.error(f"获取未使用账号失败: {error_msg}")
|
||||
return False, f"获取账号失败: {error_msg}"
|
||||
|
||||
except requests.exceptions.SSLError as e:
|
||||
logging.error(f"SSL验证失败: {str(e)}")
|
||||
return False, "SSL验证失败,请检查网络设置"
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
logging.error(f"网络连接错误: {str(e)}")
|
||||
return False, "网络连接失败,请检查网络设置"
|
||||
except requests.exceptions.Timeout as e:
|
||||
logging.error(f"请求超时: {str(e)}")
|
||||
return False, "请求超时,请稍后重试"
|
||||
except requests.RequestException as e:
|
||||
logging.error(f"请求失败: {str(e)}")
|
||||
return False, f"网络请求失败: {str(e)}"
|
||||
except Exception as e:
|
||||
logging.error(f"未知错误: {str(e)}")
|
||||
return False, f"发生未知错误: {str(e)}"
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"刷新授权过程出错: {str(e)}")
|
||||
return False, f"刷新失败: {str(e)}"
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
try:
|
||||
|
||||
134
interactive/cursor_auth_manager.py
Normal file
134
interactive/cursor_auth_manager.py
Normal file
@@ -0,0 +1,134 @@
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import time
|
||||
import logging
|
||||
import sqlite3
|
||||
from pathlib import Path
|
||||
|
||||
class CursorAuthManager:
|
||||
"""Cursor认证信息管理器"""
|
||||
|
||||
def __init__(self):
|
||||
# 判断操作系统
|
||||
if sys.platform == "win32": # Windows
|
||||
appdata = os.getenv("APPDATA")
|
||||
if appdata is None:
|
||||
raise EnvironmentError("APPDATA 环境变量未设置")
|
||||
self.db_path = os.path.join(
|
||||
appdata, "Cursor", "User", "globalStorage", "state.vscdb"
|
||||
)
|
||||
elif sys.platform == "darwin": # macOS
|
||||
self.db_path = os.path.abspath(os.path.expanduser(
|
||||
"~/Library/Application Support/Cursor/User/globalStorage/state.vscdb"
|
||||
))
|
||||
elif sys.platform == "linux" : # Linux 和其他类Unix系统
|
||||
self.db_path = os.path.abspath(os.path.expanduser(
|
||||
"~/.config/Cursor/User/globalStorage/state.vscdb"
|
||||
))
|
||||
else:
|
||||
raise NotImplementedError(f"不支持的操作系统: {sys.platform}")
|
||||
|
||||
self.cursor_path = Path(os.path.expanduser("~")) / "AppData" / "Local" / "Programs" / "Cursor"
|
||||
|
||||
def update_auth(self, email=None, access_token=None, refresh_token=None):
|
||||
"""
|
||||
更新Cursor的认证信息
|
||||
:param email: 新的邮箱地址
|
||||
:param access_token: 新的访问令牌
|
||||
:param refresh_token: 新的刷新令牌
|
||||
:return: bool 是否成功更新
|
||||
"""
|
||||
updates = []
|
||||
# 登录状态
|
||||
updates.append(("cursorAuth/cachedSignUpType", "Auth_0"))
|
||||
|
||||
if email is not None:
|
||||
updates.append(("cursorAuth/cachedEmail", email))
|
||||
if access_token is not None:
|
||||
updates.append(("cursorAuth/accessToken", access_token))
|
||||
if refresh_token is not None:
|
||||
updates.append(("cursorAuth/refreshToken", refresh_token))
|
||||
|
||||
if not updates:
|
||||
logging.warning("没有提供任何要更新的值")
|
||||
return False
|
||||
|
||||
conn = None
|
||||
try:
|
||||
conn = sqlite3.connect(self.db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
for key, value in updates:
|
||||
# 检查key是否存在
|
||||
check_query = f"SELECT COUNT(*) FROM itemTable WHERE key = ?"
|
||||
cursor.execute(check_query, (key,))
|
||||
if cursor.fetchone()[0] == 0:
|
||||
insert_query = "INSERT INTO itemTable (key, value) VALUES (?, ?)"
|
||||
cursor.execute(insert_query, (key, value))
|
||||
else:
|
||||
update_query = "UPDATE itemTable SET value = ? WHERE key = ?"
|
||||
cursor.execute(update_query, (value, key))
|
||||
|
||||
if cursor.rowcount > 0:
|
||||
logging.info(f"成功更新 {key.split('/')[-1]}")
|
||||
else:
|
||||
logging.warning(f"未找到 {key.split('/')[-1]} 或值未变化")
|
||||
|
||||
conn.commit()
|
||||
logging.info(f"认证信息更新成功: {email}")
|
||||
return True
|
||||
|
||||
except sqlite3.Error as e:
|
||||
logging.error(f"数据库错误: {str(e)}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"更新认证信息失败: {str(e)}")
|
||||
return False
|
||||
finally:
|
||||
if conn:
|
||||
conn.close()
|
||||
|
||||
def restart_cursor(self) -> bool:
|
||||
"""重启Cursor编辑器
|
||||
|
||||
Returns:
|
||||
bool: 是否成功重启
|
||||
"""
|
||||
try:
|
||||
logging.info("正在重启Cursor...")
|
||||
if sys.platform == "win32":
|
||||
# Windows系统
|
||||
# 关闭Cursor
|
||||
os.system("taskkill /f /im Cursor.exe 2>nul")
|
||||
time.sleep(2)
|
||||
# 获取Cursor安装路径
|
||||
cursor_exe = self.cursor_path / "Cursor.exe"
|
||||
if cursor_exe.exists():
|
||||
# 启动Cursor
|
||||
os.startfile(str(cursor_exe))
|
||||
logging.info("Cursor重启成功")
|
||||
return True
|
||||
else:
|
||||
logging.error(f"未找到Cursor程序: {cursor_exe}")
|
||||
return False
|
||||
elif sys.platform == "darwin":
|
||||
# macOS系统
|
||||
os.system("killall Cursor 2>/dev/null")
|
||||
time.sleep(2)
|
||||
os.system("open -a Cursor")
|
||||
logging.info("Cursor重启成功")
|
||||
return True
|
||||
elif sys.platform == "linux":
|
||||
# Linux系统
|
||||
os.system("pkill -f cursor")
|
||||
time.sleep(2)
|
||||
os.system("cursor &")
|
||||
logging.info("Cursor重启成功")
|
||||
return True
|
||||
else:
|
||||
logging.error(f"不支持的操作系统: {sys.platform}")
|
||||
return False
|
||||
except Exception as e:
|
||||
logging.error(f"重启Cursor时发生错误: {str(e)}")
|
||||
return False
|
||||
@@ -110,8 +110,8 @@ class MainWindow:
|
||||
btn_frame.pack(fill="x", pady=5)
|
||||
|
||||
self.style.configure("Action.TButton", padding=8)
|
||||
ttk.Button(btn_frame, text="刷新Cursor授权", command=self.reset_machine_id, style="Action.TButton").pack(fill="x", pady=2)
|
||||
ttk.Button(btn_frame, text="实现Cursor0.45.x限制", command=self.dummy_function, style="Action.TButton").pack(fill="x", pady=2)
|
||||
ttk.Button(btn_frame, text="刷新Cursor编辑器授权", command=self.reset_machine_id, style="Action.TButton").pack(fill="x", pady=2)
|
||||
ttk.Button(btn_frame, text="突破Cursor0.45.x限制", command=self.dummy_function, style="Action.TButton").pack(fill="x", pady=2)
|
||||
ttk.Button(btn_frame, text="禁用Cursor版本更新", command=self.dummy_function, style="Action.TButton").pack(fill="x", pady=2)
|
||||
|
||||
def copy_device_id(self):
|
||||
@@ -283,21 +283,13 @@ class MainWindow:
|
||||
messagebox.showinfo("提示", "此功能暂未实现")
|
||||
|
||||
def reset_machine_id(self):
|
||||
"""重置机器码"""
|
||||
# 先检查状态
|
||||
if not self.check_status():
|
||||
return
|
||||
|
||||
"""刷新Cursor编辑器授权"""
|
||||
try:
|
||||
if self.switcher.reset_machine_id():
|
||||
messagebox.showinfo("成功", "机器码重置成功")
|
||||
# 重置后检查一次状态
|
||||
self.check_status()
|
||||
# 刷新授权
|
||||
success, message = self.switcher.refresh_cursor_auth()
|
||||
if success:
|
||||
messagebox.showinfo("成功", "Cursor编辑器授权刷新成功!\n" + message)
|
||||
else:
|
||||
messagebox.showerror("错误", "机器码重置失败,请查看日志")
|
||||
# 失败后也检查状态
|
||||
self.check_status()
|
||||
messagebox.showerror("错误", message)
|
||||
except Exception as e:
|
||||
messagebox.showerror("错误", f"重置失败: {str(e)}")
|
||||
# 出错后也检查状态
|
||||
self.check_status()
|
||||
messagebox.showerror("错误", f"刷新失败: {str(e)}")
|
||||
@@ -1,37 +1,61 @@
|
||||
import logging
|
||||
import sys
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
from gui.main_window import MainWindow
|
||||
|
||||
def setup_logging():
|
||||
"""设置日志"""
|
||||
log_dir = Path.home() / ".cursor_switcher" / "logs"
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
log_file = log_dir / "switcher.log"
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format="%(asctime)s - %(levelname)s - %(message)s",
|
||||
handlers=[
|
||||
logging.FileHandler(log_file, encoding="utf-8"),
|
||||
logging.StreamHandler()
|
||||
]
|
||||
)
|
||||
logging.info("日志系统初始化完成")
|
||||
try:
|
||||
log_dir = Path.home() / ".cursor_switcher" / "logs"
|
||||
log_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
log_file = log_dir / "switcher.log"
|
||||
|
||||
# 同时输出到文件和控制台
|
||||
handlers = [logging.FileHandler(log_file, encoding="utf-8")]
|
||||
if sys.stdout is not None:
|
||||
handlers.append(logging.StreamHandler(sys.stdout))
|
||||
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, # 使用INFO级别以显示更多信息
|
||||
format="%(asctime)s - %(levelname)s - %(message)s",
|
||||
handlers=handlers
|
||||
)
|
||||
logging.info("日志系统初始化成功")
|
||||
except Exception as e:
|
||||
print(f"设置日志系统失败: {str(e)}")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
try:
|
||||
print("正在启动程序...")
|
||||
setup_logging()
|
||||
logging.info("启动GUI界面...")
|
||||
|
||||
# 检查Python版本
|
||||
logging.info(f"Python版本: {sys.version}")
|
||||
|
||||
# 检查工作目录
|
||||
logging.info(f"当前工作目录: {Path.cwd()}")
|
||||
|
||||
# 检查模块路径
|
||||
logging.info("Python路径:")
|
||||
for p in sys.path:
|
||||
logging.info(f" - {p}")
|
||||
|
||||
logging.info("正在初始化主窗口...")
|
||||
window = MainWindow()
|
||||
|
||||
logging.info("正在启动主窗口...")
|
||||
window.run()
|
||||
except KeyboardInterrupt:
|
||||
logging.info("程序被用户中断")
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"程序运行出错: {str(e)}")
|
||||
finally:
|
||||
logging.info("程序退出")
|
||||
error_msg = f"程序运行出错: {str(e)}\n{traceback.format_exc()}"
|
||||
logging.error(error_msg)
|
||||
print(error_msg) # 直接打印错误信息
|
||||
|
||||
# 保持窗口不关闭
|
||||
input("按回车键退出...")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,2 +1,4 @@
|
||||
requests==2.31.0
|
||||
pyinstaller==6.3.0
|
||||
pyinstaller==6.3.0
|
||||
pillow==10.2.0 # 用于处理图标
|
||||
setuptools==65.5.1 # 解决pkg_resources.extern问题
|
||||
72
interactive/utils/cursor_registry.py
Normal file
72
interactive/utils/cursor_registry.py
Normal file
@@ -0,0 +1,72 @@
|
||||
import os
|
||||
import winreg
|
||||
import logging
|
||||
from pathlib import Path
|
||||
|
||||
class CursorRegistry:
|
||||
"""Cursor注册表操作工具类"""
|
||||
|
||||
def __init__(self):
|
||||
self.cursor_path = Path(os.path.expanduser("~")) / "AppData" / "Local" / "Programs" / "Cursor"
|
||||
self.app_path = self.cursor_path / "resources" / "app"
|
||||
|
||||
def refresh_registry(self) -> bool:
|
||||
"""刷新Cursor相关的注册表项
|
||||
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
try:
|
||||
# 获取Cursor安装路径
|
||||
cursor_exe = self.cursor_path / "Cursor.exe"
|
||||
if not cursor_exe.exists():
|
||||
logging.error("未找到Cursor.exe")
|
||||
return False
|
||||
|
||||
# 刷新注册表项
|
||||
try:
|
||||
# 打开HKEY_CURRENT_USER\Software\Classes\Directory\Background\shell\Cursor
|
||||
key_path = r"Software\Classes\Directory\Background\shell\Cursor"
|
||||
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path, 0, winreg.KEY_WRITE) as key:
|
||||
winreg.SetValueEx(key, "Icon", 0, winreg.REG_SZ, str(cursor_exe))
|
||||
|
||||
# 打开command子键
|
||||
with winreg.OpenKey(winreg.HKEY_CURRENT_USER, key_path + r"\command", 0, winreg.KEY_WRITE) as key:
|
||||
winreg.SetValueEx(key, "", 0, winreg.REG_SZ, f'"{str(cursor_exe)}" "%V"')
|
||||
|
||||
logging.info("注册表刷新成功")
|
||||
return True
|
||||
|
||||
except WindowsError as e:
|
||||
logging.error(f"刷新注册表失败: {str(e)}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"刷新注册表过程出错: {str(e)}")
|
||||
return False
|
||||
|
||||
def clean_registry(self) -> bool:
|
||||
"""清理Cursor相关的注册表项
|
||||
|
||||
Returns:
|
||||
bool: 是否成功
|
||||
"""
|
||||
try:
|
||||
# 删除注册表项
|
||||
try:
|
||||
key_path = r"Software\Classes\Directory\Background\shell\Cursor"
|
||||
winreg.DeleteKey(winreg.HKEY_CURRENT_USER, key_path + r"\command")
|
||||
winreg.DeleteKey(winreg.HKEY_CURRENT_USER, key_path)
|
||||
logging.info("注册表清理成功")
|
||||
return True
|
||||
|
||||
except WindowsError as e:
|
||||
if e.winerror == 2: # 找不到注册表项
|
||||
logging.info("注册表项不存在,无需清理")
|
||||
return True
|
||||
logging.error(f"清理注册表失败: {str(e)}")
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
logging.error(f"清理注册表过程出错: {str(e)}")
|
||||
return False
|
||||
@@ -18,7 +18,7 @@ def test_member_status(machine_id: str):
|
||||
}
|
||||
|
||||
print("\n发送请求...")
|
||||
response = requests.post(endpoint, json=data, headers=headers, timeout=10)
|
||||
response = requests.post(endpoint, json=data, headers=headers, timeout=10, verify=False)
|
||||
print(f"状态码: {response.status_code}")
|
||||
|
||||
print("\n响应数据:")
|
||||
@@ -43,6 +43,43 @@ def test_member_status(machine_id: str):
|
||||
except Exception as e:
|
||||
print(f"\n请求失败: {str(e)}")
|
||||
|
||||
def test_get_unused_account(machine_id: str):
|
||||
"""测试获取未使用账号接口"""
|
||||
print(f"\n=== 测试获取未使用账号 ===")
|
||||
print(f"设备码: {machine_id}")
|
||||
|
||||
try:
|
||||
# 构造请求
|
||||
endpoint = "https://cursorapi.nosqli.com/admin/api.account/getUnused"
|
||||
data = {
|
||||
"machine_id": machine_id
|
||||
}
|
||||
headers = {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
|
||||
print("\n发送请求...")
|
||||
response = requests.post(endpoint, json=data, headers=headers, timeout=30, verify=False)
|
||||
print(f"状态码: {response.status_code}")
|
||||
|
||||
print("\n响应数据:")
|
||||
response_data = response.json()
|
||||
print(json.dumps(response_data, indent=2, ensure_ascii=False))
|
||||
|
||||
if response_data.get("code") == 200:
|
||||
account_data = response_data.get("data", {})
|
||||
print("\n账号信息:")
|
||||
print(f"邮箱: {account_data.get('email', '')}")
|
||||
print(f"到期时间: {account_data.get('expire_time', '')}")
|
||||
print(f"剩余天数: {account_data.get('days_left', 0)}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\n请求失败: {str(e)}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
# 禁用SSL警告
|
||||
requests.packages.urllib3.disable_warnings()
|
||||
|
||||
machine_id = "b2c32bdeff8d3f0d33dc88f2aadea6bc"
|
||||
test_member_status(machine_id)
|
||||
test_member_status(machine_id)
|
||||
test_get_unused_account(machine_id)
|
||||
Reference in New Issue
Block a user