289 lines
7.8 KiB
Python
289 lines
7.8 KiB
Python
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("按回车键退出...")
|