cursor_auto_register/cursor_shadow_patcher.py

289 lines
7.8 KiB
Python
Raw Normal View History

2025-05-11 23:06:57 +08:00
import os
import re
import random
import shutil
import pathlib
import platform
from uuid import uuid4
from logger import info, warning, error
from config import CURSOR_PATH
# 颜色常量定义,保留用于日志输出
GREEN = "\033[92m"
RED = "\033[91m"
YELLOW = "\033[93m"
BLUE = "\033[96m"
PURPLE = "\033[95m"
RESET = "\033[0m"
SYSTEM = platform.system()
if SYSTEM not in ("Windows", "Linux", "Darwin"):
raise OSError(f"不支持的操作系统: {SYSTEM}")
def uuid():
"""生成随机UUID"""
return str(uuid4())
def path(path_str):
"""获取绝对路径"""
return pathlib.Path(path_str).resolve()
def randomuuid(randomuuid_str):
"""获取随机UUID如果提供则使用提供的值"""
if not randomuuid_str:
randomuuid_str = uuid()
return randomuuid_str
def random_mac():
"""生成随机MAC地址"""
mac = [
0x00,
0x16,
0x3E,
random.randint(0x00, 0x7F),
random.randint(0x00, 0xFF),
random.randint(0x00, 0xFF),
]
return ":".join(map(lambda x: "%02x" % x, mac))
def load(file_path: pathlib.Path):
"""加载文件内容"""
with open(file_path, "rb") as f:
return f.read()
def save(file_path: pathlib.Path, data: bytes):
"""保存文件内容"""
with open(file_path, "wb") as f:
f.write(data)
def backup(file_path: pathlib.Path):
"""备份文件"""
backup_path = file_path.with_suffix(file_path.suffix + ".bak")
if not backup_path.exists():
shutil.copy2(file_path, backup_path)
print(f"已备份 {file_path} -> {backup_path}")
def replace(data: bytes, pattern: str, replace_str: str, probe: str = None) -> bytes:
"""替换文件内容"""
pattern_bytes = pattern.encode() if isinstance(pattern, str) else pattern
replace_bytes = (
replace_str.encode() if isinstance(replace_str, str) else replace_str
)
if probe:
probe_bytes = probe.encode() if isinstance(probe, str) else probe
if re.search(probe_bytes, data):
print("检测到已经被修补的代码,跳过...")
return data
return re.sub(pattern_bytes, replace_bytes, data)
def find_main_js():
"""查找Cursor的main.js文件"""
error(f"SYSTEM: {SYSTEM}")
if SYSTEM == "Windows":
localappdata = os.getenv("LOCALAPPDATA")
if not localappdata:
raise OSError("环境变量 %LOCALAPPDATA% 不存在")
# 使用本地变量保存路径
cursor_path = CURSOR_PATH
if not cursor_path:
error("当前windows系统, 环境变量 CURSOR_PATH 不存在,使用默认路径")
cursor_path = os.getenv("LOCALAPPDATA", "")
else:
info(f"当前windows系统, CURSOR_PATH: {cursor_path}")
# 常见的Cursor安装路径
paths = [
path(os.path.join(cursor_path, "resources", "app", "out", "main.js")),
path(
os.path.join(
localappdata,
"Programs",
"cursor",
"resources",
"app",
"out",
"main.js",
)
),
path(
os.path.join(
localappdata, "cursor", "resources", "app", "out", "main.js"
)
),
]
for p in paths:
info(f"检查路径: {p}")
if p.exists():
info(f"找到main.js: {p}")
return p
else:
warning(f"路径不存在: {p}")
elif SYSTEM == "Darwin": # macOS
paths = [
path("/Applications/Cursor.app/Contents/Resources/app/out/main.js"),
path(
os.path.expanduser(
"~/Applications/Cursor.app/Contents/Resources/app/out/main.js"
)
),
]
for p in paths:
if p.exists():
return p
elif SYSTEM == "Linux":
# Linux上常见的安装路径
paths = [
path("/usr/share/cursor/resources/app/out/main.js"),
path(os.path.expanduser("~/.local/share/cursor/resources/app/out/main.js")),
]
for p in paths:
if p.exists():
return p
raise FileNotFoundError("无法找到Cursor的main.js文件请手动指定路径")
def patch_cursor(
js_path=None, machine_id=None, mac_addr=None, sqm_id=None, dev_id=None
):
"""
修补Cursor的main.js文件替换机器ID等识别信息
参数:
js_path: main.js文件路径如果为None则自动查找
machine_id: 机器ID如果为None则随机生成
mac_addr: MAC地址如果为None则随机生成
sqm_id: Windows SQM ID如果为None则使用空字符串
dev_id: 设备ID如果为None则随机生成
返回:
bool: 是否成功
"""
try:
# 查找main.js文件
if not js_path:
js_path = find_main_js()
else:
js_path = path(js_path)
# 如果找不到main.js文件
if not js_path.exists():
print(f"错误: 找不到文件 {js_path}")
return False
print(f"找到main.js文件: {js_path}")
# 随机生成ID
machine_id = randomuuid(machine_id)
mac_addr = mac_addr or random_mac()
sqm_id = sqm_id or ""
dev_id = randomuuid(dev_id)
# 加载文件内容
data = load(js_path)
# 备份文件
backup(js_path)
# 替换机器ID
data = replace(
data,
r"=.{0,50}timeout.{0,10}5e3.*?,",
f'=/*csp1*/"{machine_id}"/*1csp*/,',
r"=/\*csp1\*/.*?/\*1csp\*/,",
)
# 替换MAC地址
data = replace(
data,
r"(function .{0,50}\{).{0,300}Unable to retrieve mac address.*?(\})",
f'\\1return/*csp2*/"{mac_addr}"/*2csp*/;\\2',
r"()return/\*csp2\*/.*?/\*2csp\*/;()",
)
# 替换SQM ID
data = replace(
data,
r'return.{0,50}\.GetStringRegKey.*?HKEY_LOCAL_MACHINE.*?MachineId.*?\|\|.*?""',
f'return/*csp3*/"{sqm_id}"/*3csp*/',
r"return/\*csp3\*/.*?/\*3csp\*/",
)
# 替换设备ID
data = replace(
data,
r"return.{0,50}vscode\/deviceid.*?getDeviceId\(\)",
f'return/*csp4*/"{dev_id}"/*4csp*/',
r"return/\*csp4\*/.*?/\*4csp\*/",
)
# 保存修改后的文件
save(js_path, data)
print(f"成功修补 {js_path}")
print(f"机器ID: {machine_id}")
print(f"MAC地址: {mac_addr}")
print(f"SQM ID: {sqm_id}")
print(f"设备ID: {dev_id}")
return True
except Exception as e:
print(f"错误: {str(e)}")
import traceback
traceback.print_exc()
return False
class CursorShadowPatcher:
"""Cursor机器标识修改器"""
@staticmethod
def reset_machine_ids():
"""重置所有机器标识"""
return patch_cursor()
if __name__ == "__main__":
# 作为独立脚本运行时,执行交互式修补
print(f"\n{'=' * 50}")
print("Cursor 机器标识重置工具 (Shadow Patch 增强版)")
print(f"{'=' * 50}")
js_path = input("请输入main.js路径 (留空=自动检测): ")
machine_id = input("机器ID (留空=随机生成): ")
mac_addr = input("MAC地址 (留空=随机生成): ")
sqm_id = input("Windows SQM ID (留空=使用空值): ")
dev_id = input("设备ID (留空=随机生成): ")
success = patch_cursor(js_path, machine_id, mac_addr, sqm_id, dev_id)
if success:
print(f"\n{'=' * 50}")
print("修补成功!")
else:
print(f"\n{'=' * 50}")
print("修补失败!")
input("按回车键退出...")