#!/bin/bash # ============================================== # CursorPro - macOS 机器码重置脚本 # 一次授权,永久免密 # 纯 Shell 实现,不依赖 Python # ============================================== # 颜色定义 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # 路径定义 CURSOR_APP="/Applications/Cursor.app" CURSOR_OUT="$CURSOR_APP/Contents/Resources/app/out" MAIN_JS="$CURSOR_OUT/main.js" UUID_PLIST="/Library/Preferences/SystemConfiguration/com.apple.platform.uuid.plist" # 用户数据路径 USER_HOME="$HOME" CURSOR_DATA="$USER_HOME/Library/Application Support/Cursor" STORAGE_JSON="$CURSOR_DATA/User/globalStorage/storage.json" STATE_VSCDB="$CURSOR_DATA/User/globalStorage/state.vscdb" MACHINEID_FILE="$CURSOR_DATA/machineid" # 备份目录 BACKUP_DIR="$USER_HOME/CursorPro_backups" echo "" echo -e "${BLUE}======================================${NC}" echo -e "${BLUE} CursorPro macOS 机器码重置工具${NC}" echo -e "${BLUE}======================================${NC}" echo "" # 检查 Cursor 是否安装 if [ ! -d "$CURSOR_APP" ]; then echo -e "${RED}错误: 未找到 Cursor 应用${NC}" echo "请确保 Cursor 安装在 /Applications/Cursor.app" exit 1 fi # 创建备份目录 mkdir -p "$BACKUP_DIR" 2>/dev/null # ============================================ # 第一步:检测并设置权限(一次性) # ============================================ echo -e "${YELLOW}[步骤 1/7] 检查权限...${NC}" NEED_SUDO=false # 检查 main.js 权限 if [ ! -w "$MAIN_JS" ] 2>/dev/null; then NEED_SUDO=true echo " - main.js: 需要授权" else echo -e " - main.js: ${GREEN}已有权限${NC}" fi # 检查 UUID plist 权限(文件可能不存在) if [ -f "$UUID_PLIST" ]; then if [ ! -w "$UUID_PLIST" ] 2>/dev/null; then NEED_SUDO=true echo " - UUID plist: 需要授权" else echo -e " - UUID plist: ${GREEN}已有权限${NC}" fi else echo -e " - UUID plist: ${YELLOW}文件不存在,跳过${NC}" fi # 如果需要授权 if [ "$NEED_SUDO" = true ]; then echo "" echo -e "${YELLOW}首次运行,需要管理员权限${NC}" echo -e "${YELLOW}授权后以后重置不再需要输入密码${NC}" echo "" # 请求 sudo 权限 sudo -v || { echo -e "${RED}授权失败${NC}"; exit 1; } # 修改 Cursor 目录权限 if [ ! -w "$MAIN_JS" ] 2>/dev/null; then echo " 正在修改 Cursor 目录权限..." sudo chown -R $(whoami) "$CURSOR_OUT" 2>/dev/null || true sudo chmod -R u+rw "$CURSOR_OUT" 2>/dev/null || true echo -e " ${GREEN}✓ Cursor 目录权限已修改${NC}" fi # 修改 UUID plist 权限(如果文件存在) if [ -f "$UUID_PLIST" ] && [ ! -w "$UUID_PLIST" ] 2>/dev/null; then echo " 正在修改 UUID plist 权限..." sudo chown $(whoami) "$UUID_PLIST" 2>/dev/null || true echo -e " ${GREEN}✓ UUID plist 权限已修改${NC}" fi echo "" echo -e "${GREEN}✓ 权限设置完成!以后重置不再需要密码${NC}" fi echo "" # ============================================ # 第二步:关闭 Cursor # ============================================ echo -e "${YELLOW}[步骤 2/7] 关闭 Cursor...${NC}" if pgrep -x "Cursor" > /dev/null; then killall Cursor 2>/dev/null || true echo " 等待 Cursor 完全退出..." sleep 3 echo -e " ${GREEN}✓ Cursor 已关闭${NC}" else echo -e " ${GREEN}✓ Cursor 未运行${NC}" fi echo "" # ============================================ # 第三步:Patch main.js # ============================================ echo -e "${YELLOW}[步骤 3/7] Patch main.js...${NC}" if [ ! -f "$MAIN_JS" ]; then echo -e " ${RED}警告: 未找到 main.js${NC}" else # 检查是否已经 patch 过 if grep -q 'uuidgen' "$MAIN_JS" 2>/dev/null; then echo -e " ${GREEN}✓ main.js 已经 Patch 过,跳过${NC}" else # 检查目标字符串 if grep -q 'ioreg -rd1 -c IOPlatformExpertDevice' "$MAIN_JS"; then # 备份到用户目录 BACKUP_FILE="$BACKUP_DIR/main.js.backup_$(date +%s)" cp "$MAIN_JS" "$BACKUP_FILE" 2>/dev/null if [ $? -eq 0 ]; then echo " 备份已创建: $BACKUP_FILE" fi # 使用 perl 替换(macOS 自带,比 sed 更可靠处理特殊字符) perl -i -pe 's/ioreg -rd1 -c IOPlatformExpertDevice/UUID=\$(uuidgen | tr '"'"'[:upper:]'"'"' '"'"'[:lower:]'"'"');echo "IOPlatformUUID = "\$UUID";/g' "$MAIN_JS" 2>/dev/null if [ $? -eq 0 ]; then echo -e " ${GREEN}✓ main.js Patch 成功${NC}" else echo -e " ${RED}✗ main.js Patch 失败${NC}" fi else echo -e " ${YELLOW}警告: 未找到目标字符串,可能已 patch 或版本不兼容${NC}" fi fi fi echo "" # ============================================ # 第四步:重置系统 UUID # ============================================ echo -e "${YELLOW}[步骤 4/7] 重置系统 UUID...${NC}" if [ ! -f "$UUID_PLIST" ]; then echo -e " ${YELLOW}提示: UUID plist 文件不存在,跳过${NC}" else NEW_SYS_UUID=$(uuidgen | tr '[:upper:]' '[:lower:]') /usr/libexec/PlistBuddy -c "Set :IOPlatformUUID $NEW_SYS_UUID" "$UUID_PLIST" 2>/dev/null || \ /usr/libexec/PlistBuddy -c "Add :IOPlatformUUID string $NEW_SYS_UUID" "$UUID_PLIST" 2>/dev/null || true echo -e " ${GREEN}✓ 系统 UUID 已重置: $NEW_SYS_UUID${NC}" fi echo "" # ============================================ # 第五步:重置 storage.json # ============================================ echo -e "${YELLOW}[步骤 5/7] 重置 storage.json...${NC}" # 生成新的机器码(64位十六进制) NEW_MACHINE_ID=$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]')$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]') NEW_MAC_MACHINE_ID=$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]')$(uuidgen | tr -d '-' | tr '[:upper:]' '[:lower:]') NEW_DEV_DEVICE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]') NEW_SQM_ID="{$(uuidgen | tr '[:lower:]' '[:upper:]')}" if [ -f "$STORAGE_JSON" ]; then # 备份 cp "$STORAGE_JSON" "$BACKUP_DIR/storage.json.backup_$(date +%s)" 2>/dev/null # 使用 sed 替换 JSON 中的值(macOS sed 语法) # machineId sed -i '' "s/\"telemetry\.machineId\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"telemetry.machineId\": \"$NEW_MACHINE_ID\"/g" "$STORAGE_JSON" 2>/dev/null # macMachineId sed -i '' "s/\"telemetry\.macMachineId\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"telemetry.macMachineId\": \"$NEW_MAC_MACHINE_ID\"/g" "$STORAGE_JSON" 2>/dev/null # devDeviceId sed -i '' "s/\"telemetry\.devDeviceId\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"telemetry.devDeviceId\": \"$NEW_DEV_DEVICE_ID\"/g" "$STORAGE_JSON" 2>/dev/null # sqmId sed -i '' "s/\"telemetry\.sqmId\"[[:space:]]*:[[:space:]]*\"[^\"]*\"/\"telemetry.sqmId\": \"$NEW_SQM_ID\"/g" "$STORAGE_JSON" 2>/dev/null echo -e " ${GREEN}✓ storage.json 已更新 (4个ID)${NC}" else echo -e " ${YELLOW}警告: 未找到 storage.json${NC}" fi echo "" # ============================================ # 第六步:重置 SQLite 数据库 # ============================================ echo -e "${YELLOW}[步骤 6/7] 重置 SQLite 数据库...${NC}" NEW_SERVICE_MACHINE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]') if [ -f "$STATE_VSCDB" ]; then # 备份 cp "$STATE_VSCDB" "$BACKUP_DIR/state.vscdb.backup_$(date +%s)" 2>/dev/null # 使用 sqlite3 命令(macOS 自带) sqlite3 "$STATE_VSCDB" "UPDATE ItemTable SET value = '$NEW_SERVICE_MACHINE_ID' WHERE key = 'storage.serviceMachineId';" 2>/dev/null if [ $? -eq 0 ]; then echo -e " ${GREEN}✓ state.vscdb 已更新 (serviceMachineId)${NC}" else # 如果更新失败,尝试插入 sqlite3 "$STATE_VSCDB" "INSERT OR REPLACE INTO ItemTable (key, value) VALUES ('storage.serviceMachineId', '$NEW_SERVICE_MACHINE_ID');" 2>/dev/null echo -e " ${GREEN}✓ state.vscdb 已更新${NC}" fi else echo -e " ${YELLOW}警告: 未找到 state.vscdb${NC}" fi # 更新 machineid 文件 echo "" if [ -d "$(dirname "$MACHINEID_FILE")" ]; then echo "${NEW_MACHINE_ID:0:64}" > "$MACHINEID_FILE" echo -e " ${GREEN}✓ machineid 文件已更新${NC}" else echo -e " ${YELLOW}警告: 未找到 machineid 目录${NC}" fi # 清理缓存 rm -rf "$CURSOR_DATA/Cache" 2>/dev/null || true rm -rf "$CURSOR_DATA/CachedData" 2>/dev/null || true rm -rf "$CURSOR_DATA/GPUCache" 2>/dev/null || true echo -e " ${GREEN}✓ 缓存已清理${NC}" echo "" # ============================================ # 第七步:重新打开 Cursor # ============================================ echo -e "${YELLOW}[步骤 7/7] 重新打开 Cursor...${NC}" sleep 1 open "$CURSOR_APP" echo -e " ${GREEN}✓ Cursor 已启动${NC}" echo "" echo -e "${GREEN}======================================${NC}" echo -e "${GREEN} ✅ 机器码重置完成!${NC}" echo -e "${GREEN}======================================${NC}" echo "" echo "已重置的内容:" echo " ✓ main.js (ioreg patch)" echo " ✓ storage.json (4个ID)" echo " ✓ state.vscdb (serviceMachineId)" echo " ✓ machineid 文件" echo " ✓ 缓存已清理" echo "" echo "新机器码信息:" echo " machineId: ${NEW_MACHINE_ID:0:32}..." echo " devDeviceId: $NEW_DEV_DEVICE_ID" echo " serviceMachineId: $NEW_SERVICE_MACHINE_ID" echo "" echo "备份位置: $BACKUP_DIR" echo "" echo -e "${BLUE}此窗口可以关闭${NC}" echo ""