Browse Source

```

feat(cursor): 改进Linux和Mac平台ID修改脚本的兼容性和稳定性

- 重构Linux脚本的用户检测逻辑,支持sudo、root和容器环境的用户识别
- 添加get_user_home_dir和get_user_primary_group函数,统一处理目标用户Home目录和主组获取
- 替换硬编码的$HOME路径为统一的$TARGET_HOME变量,提高跨环境兼容性
- 优化随机ID生成函数,添加generate_hex_bytes和generate_uuid的多重备选方案
- 改进进程检测机制,使用get_cursor_pids函数替代简单ps命令,支持多种发行版
- 修复chown命令中组名获取的兼容性问题,统一使用预获取的CURRENT_GROUP变量
- 更新路径搜索逻辑,确保在不同安装方式下都能正确定位Cursor相关文件
- 增强UUID生成的可靠性,优先使用系统工具,缺失时使用Python作为备选
```
master
煎饼果子卷鲨鱼辣椒 2 weeks ago
parent
commit
207e5fe196
  1. 281
      scripts/run/cursor_linux_id_modifier.sh
  2. 55
      scripts/run/cursor_mac_id_modifier.sh

281
scripts/run/cursor_linux_id_modifier.sh

@ -116,11 +116,80 @@ sed_inplace() {
# 获取当前用户 # 获取当前用户
get_current_user() { get_current_user() {
if [ "$EUID" -eq 0 ]; then
# sudo 场景:优先以 SUDO_USER 作为目标用户(Cursor 通常运行在该用户下)
if [ "$EUID" -eq 0 ] && [ -n "${SUDO_USER:-}" ]; then
echo "$SUDO_USER" echo "$SUDO_USER"
else
echo "$USER"
return 0
fi
# 普通/直跑 root 场景:使用当前有效用户
if command -v id >/dev/null 2>&1; then
id -un 2>/dev/null && return 0
fi
echo "${USER:-}"
}
# 获取指定用户的 Home 目录(兼容 sudo/root/容器等场景)
get_user_home_dir() {
local user="$1"
local home=""
if command -v getent >/dev/null 2>&1; then
home=$(getent passwd "$user" 2>/dev/null | awk -F: '{print $6}' | head -n 1)
fi
if [ -z "$home" ] && [ -f /etc/passwd ]; then
home=$(awk -F: -v u="$user" '$1==u {print $6; exit}' /etc/passwd 2>/dev/null)
fi
if [ -z "$home" ]; then
home=$(eval echo "~$user" 2>/dev/null)
fi
# 兜底:无法解析时使用当前环境 HOME
if [ -z "$home" ] || [[ "$home" == "~"* ]]; then
home="${HOME:-}"
fi
echo "$home"
}
# 获取指定用户的主组(chown 需要 user:group;不同发行版 id 参数/输出可能存在差异)
get_user_primary_group() {
local user="$1"
local group=""
local gid=""
# 优先:直接获取主组名(最简洁)
if command -v id >/dev/null 2>&1; then
group=$(id -gn "$user" 2>/dev/null | tr -d '\r\n') || true
if [ -n "$group" ]; then
echo "$group"
return 0
fi
# 回退:先取 gid,再映射为组名(映射失败则直接返回 gid,chown 同样可用)
gid=$(id -g "$user" 2>/dev/null | tr -d '\r\n') || true
fi
if [ -n "$gid" ]; then
if command -v getent >/dev/null 2>&1; then
group=$(getent group "$gid" 2>/dev/null | awk -F: '{print $1}' | head -n 1) || true
fi
if [ -z "$group" ] && [ -f /etc/group ]; then
group=$(awk -F: -v g="$gid" '$3==g {print $1; exit}' /etc/group 2>/dev/null) || true
fi
if [ -n "$group" ]; then
echo "$group"
return 0
fi fi
echo "$gid"
return 0
fi
# 最后兜底:返回用户本身(少数系统允许 user:user)
echo "$user"
return 0
} }
CURRENT_USER=$(get_current_user) CURRENT_USER=$(get_current_user)
@ -129,8 +198,26 @@ if [ -z "$CURRENT_USER" ]; then
exit 1 exit 1
fi fi
# 🎯 统一“目标用户/目标 Home”:后续所有 Cursor 用户数据路径均基于该 Home
TARGET_HOME=$(get_user_home_dir "$CURRENT_USER")
if [ -z "$TARGET_HOME" ]; then
log_error "无法解析目标用户 Home 目录: $CURRENT_USER"
exit 1
fi
log_info "目标用户: $CURRENT_USER"
log_info "目标用户 Home: $TARGET_HOME"
# 🎯 统一“目标用户主组”:chown 时不再依赖 id -g -n 的兼容性
CURRENT_GROUP=$(get_user_primary_group "$CURRENT_USER")
if [ -z "$CURRENT_GROUP" ]; then
CURRENT_GROUP="$CURRENT_USER"
log_warn "无法解析目标用户主组,已回退为: $CURRENT_GROUP(后续 chown 可能失败)"
else
log_info "目标用户主组: $CURRENT_GROUP"
fi
# 定义Linux下的Cursor路径 # 定义Linux下的Cursor路径
CURSOR_CONFIG_DIR="$HOME/.config/Cursor"
CURSOR_CONFIG_DIR="$TARGET_HOME/.config/Cursor"
STORAGE_FILE="$CURSOR_CONFIG_DIR/User/globalStorage/storage.json" STORAGE_FILE="$CURSOR_CONFIG_DIR/User/globalStorage/storage.json"
BACKUP_DIR="$CURSOR_CONFIG_DIR/User/globalStorage/backups" BACKUP_DIR="$CURSOR_CONFIG_DIR/User/globalStorage/backups"
@ -157,7 +244,7 @@ CURSOR_BIN_PATHS=(
"/usr/bin/cursor" "/usr/bin/cursor"
"/usr/local/bin/cursor" "/usr/local/bin/cursor"
"$INSTALL_DIR/cursor" # 添加标准安装路径 "$INSTALL_DIR/cursor" # 添加标准安装路径
"$HOME/.local/bin/cursor"
"$TARGET_HOME/.local/bin/cursor"
"/snap/bin/cursor" "/snap/bin/cursor"
) )
@ -181,7 +268,7 @@ find_cursor_path() {
fi fi
# 尝试查找可能的安装路径 (限制搜索范围和类型) # 尝试查找可能的安装路径 (限制搜索范围和类型)
local cursor_paths=$(find /usr /opt $HOME/.local -path "$INSTALL_DIR/cursor" -o -name "cursor" -type f -executable 2>/dev/null)
local cursor_paths=$(find /usr /opt "$TARGET_HOME/.local" -path "$INSTALL_DIR/cursor" -o -name "cursor" -type f -executable 2>/dev/null)
if [ -n "$cursor_paths" ]; then if [ -n "$cursor_paths" ]; then
# 优先选择标准安装路径 # 优先选择标准安装路径
local standard_path=$(echo "$cursor_paths" | grep "$INSTALL_DIR/cursor" | head -1) local standard_path=$(echo "$cursor_paths" | grep "$INSTALL_DIR/cursor" | head -1)
@ -207,7 +294,7 @@ find_cursor_resources() {
"$INSTALL_DIR" # 添加标准安装路径 "$INSTALL_DIR" # 添加标准安装路径
"/usr/lib/cursor" "/usr/lib/cursor"
"/usr/share/cursor" "/usr/share/cursor"
"$HOME/.local/share/cursor"
"$TARGET_HOME/.local/share/cursor"
) )
for path in "${resource_paths[@]}"; do for path in "${resource_paths[@]}"; do
@ -351,7 +438,7 @@ install_cursor_appimage() {
if mv "$cursor_source_dir" "$INSTALL_DIR"; then if mv "$cursor_source_dir" "$INSTALL_DIR"; then
log_info "成功将文件移动到 '$INSTALL_DIR'" log_info "成功将文件移动到 '$INSTALL_DIR'"
# 确保安装目录及其内容归属当前用户(如果需要) # 确保安装目录及其内容归属当前用户(如果需要)
chown -R "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$INSTALL_DIR" || log_warn "设置 '$INSTALL_DIR' 文件所有权失败,可能需要手动调整"
chown -R "$CURRENT_USER":"$CURRENT_GROUP" "$INSTALL_DIR" || log_warn "设置 '$INSTALL_DIR' 文件所有权失败,可能需要手动调整"
chmod -R u+rwX,go+rX,go-w "$INSTALL_DIR" || log_warn "设置 '$INSTALL_DIR' 文件权限失败,可能需要手动调整" chmod -R u+rwX,go+rX,go-w "$INSTALL_DIR" || log_warn "设置 '$INSTALL_DIR' 文件权限失败,可能需要手动调整"
else else
log_error "移动文件到安装目录 '$INSTALL_DIR' 失败" log_error "移动文件到安装目录 '$INSTALL_DIR' 失败"
@ -410,30 +497,96 @@ install_cursor_appimage() {
# --- 结束:安装函数 --- # --- 结束:安装函数 ---
# 检查并关闭 Cursor 进程 # 检查并关闭 Cursor 进程
# 获取 Cursor 相关进程 PID(兼容 pgrep/ps 多种实现)
get_cursor_pids() {
local self_pid="$$"
local pids=""
# 优先使用 pgrep(更稳定):仅按进程名匹配,避免误匹配到脚本命令行(例如 sudo bash ...cursor_linux_id_modifier.sh)
if command -v pgrep >/dev/null 2>&1; then
pids=$(pgrep -i "cursor" 2>/dev/null || true)
if [ -z "$pids" ]; then
pids=$(pgrep "cursor" 2>/dev/null || true)
fi
if [ -z "$pids" ]; then
pids=$(pgrep "Cursor" 2>/dev/null || true)
fi
if [ -n "$pids" ]; then
echo "$pids" | awk -v self="$self_pid" '$1 ~ /^[0-9]+$/ && $1 != self {print $1}' | sort -u
return 0
fi
fi
# 回退:兼容不同 ps 实现(BusyBox 可能不支持 aux / -ef)
if ps aux >/dev/null 2>&1; then
ps aux 2>/dev/null \
| grep -i '[c]ursor' \
| grep -v "cursor_linux_id_modifier.sh" \
| awk '{print $2}' \
| awk -v self="$self_pid" '$1 ~ /^[0-9]+$/ && $1 != self {print $1}' \
| sort -u
return 0
fi
if ps -ef >/dev/null 2>&1; then
ps -ef 2>/dev/null \
| grep -i '[c]ursor' \
| grep -v "cursor_linux_id_modifier.sh" \
| awk '{print $2}' \
| awk -v self="$self_pid" '$1 ~ /^[0-9]+$/ && $1 != self {print $1}' \
| sort -u
return 0
fi
ps 2>/dev/null \
| grep -i '[c]ursor' \
| grep -v "cursor_linux_id_modifier.sh" \
| awk '{print $1}' \
| awk -v self="$self_pid" '$1 ~ /^[0-9]+$/ && $1 != self {print $1}' \
| sort -u
return 0
}
# 打印 Cursor 相关进程详情(用于排障;不依赖固定列结构)
print_cursor_process_details() {
log_debug "正在获取 Cursor 进程详细信息:"
if ps aux >/dev/null 2>&1; then
ps aux 2>/dev/null | grep -i '[c]ursor' | grep -v "cursor_linux_id_modifier.sh" || true
return 0
fi
if ps -ef >/dev/null 2>&1; then
ps -ef 2>/dev/null | grep -i '[c]ursor' | grep -v "cursor_linux_id_modifier.sh" || true
return 0
fi
ps 2>/dev/null | grep -i '[c]ursor' | grep -v "cursor_linux_id_modifier.sh" || true
return 0
}
check_and_kill_cursor() { check_and_kill_cursor() {
log_info "检查 Cursor 进程..." log_info "检查 Cursor 进程..."
local attempt=1 local attempt=1
local max_attempts=5 local max_attempts=5
# 函数:获取进程详细信息
get_process_details() {
local process_name="$1"
log_debug "正在获取 $process_name 进程详细信息:"
ps aux | grep -i "cursor" | grep -v grep | grep -v "cursor_linux_id_modifier.sh"
}
while [ $attempt -le $max_attempts ]; do while [ $attempt -le $max_attempts ]; do
# 使用更精确的匹配来获取 Cursor 进程,排除当前脚本和grep进程
CURSOR_PIDS=$(ps aux | grep -i "cursor" | grep -v "grep" | grep -v "cursor_linux_id_modifier.sh" | awk '{print $2}' || true)
# 跨发行版兼容:优先 pgrep,其次兼容 ps aux/ps -ef/ps 的 PID 列差异
local cursor_pids_raw
cursor_pids_raw=$(get_cursor_pids || true)
# 将换行分隔的 PID 列表转换为空格分隔,便于传给 kill(避免依赖 xargs)
CURSOR_PIDS=$(echo "$cursor_pids_raw" | tr '\n' ' ' | sed 's/[[:space:]][[:space:]]*/ /g; s/^ //; s/ $//' || true)
if [ -z "$CURSOR_PIDS" ]; then if [ -z "$CURSOR_PIDS" ]; then
log_info "未发现运行中的 Cursor 进程" log_info "未发现运行中的 Cursor 进程"
return 0 return 0
fi fi
log_warn "发现 Cursor 进程正在运行"
get_process_details "cursor"
log_warn "发现 Cursor 进程正在运行: $CURSOR_PIDS"
print_cursor_process_details
log_warn "尝试关闭 Cursor 进程..." log_warn "尝试关闭 Cursor 进程..."
@ -446,8 +599,8 @@ check_and_kill_cursor() {
sleep 1 sleep 1
# 再次检查进程是否还在运行,排除当前脚本和grep进程
if ! ps aux | grep -i "cursor" | grep -v "grep" | grep -v "cursor_linux_id_modifier.sh" > /dev/null; then
# 再次检查进程是否还在运行
if [ -z "$(get_cursor_pids | head -n 1)" ]; then
log_info "Cursor 进程已成功关闭" log_info "Cursor 进程已成功关闭"
return 0 return 0
fi fi
@ -457,7 +610,7 @@ check_and_kill_cursor() {
done done
log_error "$max_attempts 次尝试后仍无法关闭 Cursor 进程" log_error "$max_attempts 次尝试后仍无法关闭 Cursor 进程"
get_process_details "cursor"
print_cursor_process_details
log_error "请手动关闭进程后重试" log_error "请手动关闭进程后重试"
exit 1 exit 1
} }
@ -475,7 +628,7 @@ backup_config() {
if cp "$STORAGE_FILE" "$backup_file"; then if cp "$STORAGE_FILE" "$backup_file"; then
chmod 644 "$backup_file" chmod 644 "$backup_file"
# 确保备份文件归属正确用户 # 确保备份文件归属正确用户
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$backup_file" || log_warn "设置备份文件所有权失败: $backup_file"
chown "$CURRENT_USER":"$CURRENT_GROUP" "$backup_file" || log_warn "设置备份文件所有权失败: $backup_file"
log_info "配置已备份到: $backup_file" log_info "配置已备份到: $backup_file"
else else
log_error "备份失败: $STORAGE_FILE" log_error "备份失败: $STORAGE_FILE"
@ -485,9 +638,35 @@ backup_config() {
} }
# 生成随机 ID # 生成随机 ID
generate_hex_bytes() {
local bytes="$1"
# 优先使用 openssl
if command -v openssl >/dev/null 2>&1; then
openssl rand -hex "$bytes"
return 0
fi
# 兜底:/dev/urandom + od(多数发行版可用)
if [ -r /dev/urandom ] && command -v od >/dev/null 2>&1; then
# 使用更通用的 od 参数写法,兼容更多发行版实现
od -An -N "$bytes" -t x1 /dev/urandom | tr -d ' \n'
return 0
fi
# 最后兜底:如果 python3 可用
if command -v python3 >/dev/null 2>&1; then
python3 -c 'import os, sys; print(os.urandom(int(sys.argv[1])).hex())' "$bytes"
return 0
fi
log_error "缺少 openssl/od/python3,无法生成随机数(bytes=$bytes"
return 1
}
generate_random_id() { generate_random_id() {
# 生成32字节(64个十六进制字符)的随机数 # 生成32字节(64个十六进制字符)的随机数
openssl rand -hex 32
generate_hex_bytes 32
} }
# 生成随机 UUID # 生成随机 UUID
@ -500,8 +679,10 @@ generate_uuid() {
if [ -f /proc/sys/kernel/random/uuid ]; then if [ -f /proc/sys/kernel/random/uuid ]; then
cat /proc/sys/kernel/random/uuid cat /proc/sys/kernel/random/uuid
else else
# 最后备选方案:使用openssl生成
openssl rand -hex 16 | sed 's/\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)\\(..\\)/\\1\\2\\3\\4-\\5\\6-\\7\\8-\\9\\10-\\11\\12\\13\\14\\15\\16/'
# 最后备选方案:使用随机 16 bytes 并格式化(避免 sed 捕获组超 9 的兼容性问题)
local hex
hex=$(generate_hex_bytes 16) || return 1
echo "${hex:0:8}-${hex:8:4}-${hex:12:4}-${hex:16:4}-${hex:20:12}"
fi fi
fi fi
} }
@ -593,9 +774,9 @@ PY
# 仅用于JS注入的ID生成(不写配置) # 仅用于JS注入的ID生成(不写配置)
generate_ids_for_js_only() { generate_ids_for_js_only() {
CURSOR_ID_MACHINE_ID=$(openssl rand -hex 32)
CURSOR_ID_MACHINE_ID=$(generate_random_id)
CURSOR_ID_MACHINE_GUID=$(generate_uuid) CURSOR_ID_MACHINE_GUID=$(generate_uuid)
CURSOR_ID_MAC_MACHINE_ID=$(openssl rand -hex 32)
CURSOR_ID_MAC_MACHINE_ID=$(generate_random_id)
CURSOR_ID_DEVICE_ID=$(generate_uuid) CURSOR_ID_DEVICE_ID=$(generate_uuid)
CURSOR_ID_SQM_ID="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}" CURSOR_ID_SQM_ID="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}"
CURSOR_ID_FIRST_SESSION_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") CURSOR_ID_FIRST_SESSION_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
@ -711,7 +892,7 @@ modify_or_add_config() {
rm -f "$temp_file" rm -f "$temp_file"
# 设置所有者和基础权限(root执行时目标文件是用户家目录下的) # 设置所有者和基础权限(root执行时目标文件是用户家目录下的)
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$file" || log_warn "设置文件所有权失败: $file"
chown "$CURRENT_USER":"$CURRENT_GROUP" "$file" || log_warn "设置文件所有权失败: $file"
chmod 644 "$file" || log_warn "设置文件权限失败: $file" # 用户读写,组和其他读 chmod 644 "$file" || log_warn "设置文件权限失败: $file" # 用户读写,组和其他读
return 0 return 0
@ -733,7 +914,7 @@ generate_new_config() {
# 确保配置文件目录存在 # 确保配置文件目录存在
mkdir -p "$(dirname "$STORAGE_FILE")" mkdir -p "$(dirname "$STORAGE_FILE")"
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$(dirname "$STORAGE_FILE")" || log_warn "设置配置目录所有权失败: $(dirname "$STORAGE_FILE")"
chown "$CURRENT_USER":"$CURRENT_GROUP" "$(dirname "$STORAGE_FILE")" || log_warn "设置配置目录所有权失败: $(dirname "$STORAGE_FILE")"
chmod 755 "$(dirname "$STORAGE_FILE")" || log_warn "设置配置目录权限失败: $(dirname "$STORAGE_FILE")" chmod 755 "$(dirname "$STORAGE_FILE")" || log_warn "设置配置目录权限失败: $(dirname "$STORAGE_FILE")"
# 处理用户选择 - 索引0对应"不重置"选项,索引1对应"重置"选项 # 处理用户选择 - 索引0对应"不重置"选项,索引1对应"重置"选项
@ -752,13 +933,13 @@ generate_new_config() {
# 生成并设置新的设备ID # 生成并设置新的设备ID
local new_device_id=$(generate_uuid) local new_device_id=$(generate_uuid)
local new_machine_id=$(openssl rand -hex 32)
local new_machine_id=$(generate_random_id)
# 🔧 新增: serviceMachineId (用于 storage.serviceMachineId) # 🔧 新增: serviceMachineId (用于 storage.serviceMachineId)
local new_service_machine_id=$(generate_uuid) local new_service_machine_id=$(generate_uuid)
# 🔧 新增: firstSessionDate (重置首次会话日期) # 🔧 新增: firstSessionDate (重置首次会话日期)
local new_first_session_date=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") local new_first_session_date=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
# 🔧 新增: macMachineId 和 sqmId # 🔧 新增: macMachineId 和 sqmId
local new_mac_machine_id=$(openssl rand -hex 32 2>/dev/null || head -c 32 /dev/urandom | xxd -p | tr -d '\n')
local new_mac_machine_id=$(generate_random_id)
local new_sqm_id="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}" local new_sqm_id="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}"
CURSOR_ID_MACHINE_ID="$new_machine_id" CURSOR_ID_MACHINE_ID="$new_machine_id"
@ -799,7 +980,7 @@ generate_new_config() {
# 🔧 新增: 修改 machineid 文件 # 🔧 新增: 修改 machineid 文件
log_info "🔧 [machineid] 正在修改 machineid 文件..." log_info "🔧 [machineid] 正在修改 machineid 文件..."
local machineid_file_path="$HOME/.config/Cursor/machineid"
local machineid_file_path="$CURSOR_CONFIG_DIR/machineid"
if [ -f "$machineid_file_path" ]; then if [ -f "$machineid_file_path" ]; then
# 备份原始 machineid 文件 # 备份原始 machineid 文件
local machineid_backup="$BACKUP_DIR/machineid.backup_$(date +%Y%m%d_%H%M%S)" local machineid_backup="$BACKUP_DIR/machineid.backup_$(date +%Y%m%d_%H%M%S)"
@ -819,7 +1000,7 @@ generate_new_config() {
# 🔧 新增: 修改 .updaterId 文件(更新器设备标识符) # 🔧 新增: 修改 .updaterId 文件(更新器设备标识符)
log_info "🔧 [updaterId] 正在修改 .updaterId 文件..." log_info "🔧 [updaterId] 正在修改 .updaterId 文件..."
local updater_id_file_path="$HOME/.config/Cursor/.updaterId"
local updater_id_file_path="$CURSOR_CONFIG_DIR/.updaterId"
if [ -f "$updater_id_file_path" ]; then if [ -f "$updater_id_file_path" ]; then
# 备份原始 .updaterId 文件 # 备份原始 .updaterId 文件
local updater_id_backup="$BACKUP_DIR/.updaterId.backup_$(date +%Y%m%d_%H%M%S)" local updater_id_backup="$BACKUP_DIR/.updaterId.backup_$(date +%Y%m%d_%H%M%S)"
@ -980,7 +1161,7 @@ modify_cursor_js_files() {
local ids_missing=false local ids_missing=false
if [ -z "$machine_id" ]; then if [ -z "$machine_id" ]; then
machine_id=$(openssl rand -hex 32)
machine_id=$(generate_random_id)
ids_missing=true ids_missing=true
fi fi
if [ -z "$machine_guid" ]; then if [ -z "$machine_guid" ]; then
@ -992,7 +1173,7 @@ modify_cursor_js_files() {
ids_missing=true ids_missing=true
fi fi
if [ -z "$mac_machine_id" ]; then if [ -z "$mac_machine_id" ]; then
mac_machine_id=$(openssl rand -hex 32)
mac_machine_id=$(generate_random_id)
ids_missing=true ids_missing=true
fi fi
if [ -z "$sqm_id" ]; then if [ -z "$sqm_id" ]; then
@ -1031,7 +1212,7 @@ modify_cursor_js_files() {
log_info " sqmId: $sqm_id" log_info " sqmId: $sqm_id"
# 每次执行都删除旧配置并重新生成,确保获得新的设备标识符 # 每次执行都删除旧配置并重新生成,确保获得新的设备标识符
local ids_config_path="$HOME/.cursor_ids.json"
local ids_config_path="$TARGET_HOME/.cursor_ids.json"
if [ -f "$ids_config_path" ]; then if [ -f "$ids_config_path" ]; then
rm -f "$ids_config_path" rm -f "$ids_config_path"
log_info "🗑️ [清理] 已删除旧的 ID 配置文件" log_info "🗑️ [清理] 已删除旧的 ID 配置文件"
@ -1049,11 +1230,11 @@ modify_cursor_js_files() {
"createdAt": "$first_session_date" "createdAt": "$first_session_date"
} }
EOF EOF
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$ids_config_path" 2>/dev/null || true
chown "$CURRENT_USER":"$CURRENT_GROUP" "$ids_config_path" 2>/dev/null || true
log_info "💾 [保存] 新的 ID 配置已保存到: $ids_config_path" log_info "💾 [保存] 新的 ID 配置已保存到: $ids_config_path"
# 部署外置 Hook 文件(供 Loader Stub 加载,支持多域名备用下载) # 部署外置 Hook 文件(供 Loader Stub 加载,支持多域名备用下载)
local hook_target_path="$HOME/.cursor_hook.js"
local hook_target_path="$TARGET_HOME/.cursor_hook.js"
local script_dir local script_dir
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
local hook_source_path="$script_dir/../hook/cursor_hook.js" local hook_source_path="$script_dir/../hook/cursor_hook.js"
@ -1072,7 +1253,7 @@ EOF
if [ -f "$hook_source_path" ]; then if [ -f "$hook_source_path" ]; then
if cp "$hook_source_path" "$hook_target_path"; then if cp "$hook_source_path" "$hook_target_path"; then
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$hook_target_path" 2>/dev/null || true
chown "$CURRENT_USER":"$CURRENT_GROUP" "$hook_target_path" 2>/dev/null || true
log_info "✅ [Hook] 外置 Hook 已部署: $hook_target_path" log_info "✅ [Hook] 外置 Hook 已部署: $hook_target_path"
else else
log_warn "⚠️ [Hook] 本地 Hook 复制失败,尝试在线下载..." log_warn "⚠️ [Hook] 本地 Hook 复制失败,尝试在线下载..."
@ -1091,7 +1272,7 @@ EOF
index=$((index + 1)) index=$((index + 1))
log_info "⏳ [Hook] ($index/$total_urls) 当前下载节点: $url" log_info "⏳ [Hook] ($index/$total_urls) 当前下载节点: $url"
if curl -fL --progress-bar "$url" -o "$hook_target_path"; then if curl -fL --progress-bar "$url" -o "$hook_target_path"; then
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$hook_target_path" 2>/dev/null || true
chown "$CURRENT_USER":"$CURRENT_GROUP" "$hook_target_path" 2>/dev/null || true
log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path" log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
hook_downloaded=true hook_downloaded=true
break break
@ -1106,7 +1287,7 @@ EOF
index=$((index + 1)) index=$((index + 1))
log_info "⏳ [Hook] ($index/$total_urls) 当前下载节点: $url" log_info "⏳ [Hook] ($index/$total_urls) 当前下载节点: $url"
if wget --progress=bar:force -O "$hook_target_path" "$url"; then if wget --progress=bar:force -O "$hook_target_path" "$url"; then
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$hook_target_path" 2>/dev/null || true
chown "$CURRENT_USER":"$CURRENT_GROUP" "$hook_target_path" 2>/dev/null || true
log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path" log_info "✅ [Hook] 外置 Hook 已在线下载: $hook_target_path"
hook_downloaded=true hook_downloaded=true
break break
@ -1150,7 +1331,7 @@ EOF
log_warn "⚠️ [警告] 文件已被修改但无原始备份,将使用当前版本作为基础" log_warn "⚠️ [警告] 文件已被修改但无原始备份,将使用当前版本作为基础"
fi fi
cp "$file" "$original_backup" cp "$file" "$original_backup"
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$original_backup" 2>/dev/null || true
chown "$CURRENT_USER":"$CURRENT_GROUP" "$original_backup" 2>/dev/null || true
chmod 444 "$original_backup" 2>/dev/null || true chmod 444 "$original_backup" 2>/dev/null || true
log_info "✅ [备份] 原始备份创建成功: $file_name" log_info "✅ [备份] 原始备份创建成功: $file_name"
else else
@ -1166,7 +1347,7 @@ EOF
file_modification_status+=("'$(basename "$file")': Backup Failed") file_modification_status+=("'$(basename "$file")': Backup Failed")
continue continue
fi fi
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$backup_file" 2>/dev/null || true
chown "$CURRENT_USER":"$CURRENT_GROUP" "$backup_file" 2>/dev/null || true
chmod 444 "$backup_file" 2>/dev/null || true chmod 444 "$backup_file" 2>/dev/null || true
chmod u+w "$file" || { chmod u+w "$file" || {
@ -1484,7 +1665,7 @@ try{
file_modification_status+=("'$(basename "$file")': Success") file_modification_status+=("'$(basename "$file")': Success")
chmod u-w,go-w "$file" 2>/dev/null || true chmod u-w,go-w "$file" 2>/dev/null || true
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$file" 2>/dev/null || true
chown "$CURRENT_USER":"$CURRENT_GROUP" "$file" 2>/dev/null || true
else else
log_error "Hook注入失败 (无法移动临时文件)" log_error "Hook注入失败 (无法移动临时文件)"
rm -f "$temp_file" rm -f "$temp_file"
@ -1534,8 +1715,8 @@ disable_auto_update() {
update_configs+=("$INSTALL_DIR/resources/app-update.yml") update_configs+=("$INSTALL_DIR/resources/app-update.yml")
update_configs+=("$INSTALL_DIR/app-update.yml") update_configs+=("$INSTALL_DIR/app-update.yml")
fi fi
# $HOME/.local/share
update_configs+=("$HOME/.local/share/cursor/update-config.json")
# $TARGET_HOME/.local/share
update_configs+=("$TARGET_HOME/.local/share/cursor/update-config.json")
local disabled_count=0 local disabled_count=0
@ -1561,7 +1742,7 @@ disable_auto_update() {
elif [[ "$config" == *update-config.json ]]; then elif [[ "$config" == *update-config.json ]]; then
# 直接覆盖 update-config.json # 直接覆盖 update-config.json
echo '{"autoCheck": false, "autoDownload": false}' > "$config" echo '{"autoCheck": false, "autoDownload": false}' > "$config"
chown "$CURRENT_USER":"$(id -g -n "$CURRENT_USER")" "$config" || log_warn "设置所有权失败: $config"
chown "$CURRENT_USER":"$CURRENT_GROUP" "$config" || log_warn "设置所有权失败: $config"
chmod 644 "$config" || log_warn "设置权限失败: $config" chmod 644 "$config" || log_warn "设置权限失败: $config"
((disabled_count++)) ((disabled_count++))
log_info "已覆盖更新配置文件: $config" log_info "已覆盖更新配置文件: $config"
@ -1596,7 +1777,7 @@ disable_auto_update() {
updater_paths+=($(find "$INSTALL_DIR" -name "updater" -type f -executable 2>/dev/null)) updater_paths+=($(find "$INSTALL_DIR" -name "updater" -type f -executable 2>/dev/null))
updater_paths+=($(find "$INSTALL_DIR" -name "CursorUpdater" -type f -executable 2>/dev/null)) updater_paths+=($(find "$INSTALL_DIR" -name "CursorUpdater" -type f -executable 2>/dev/null))
fi fi
updater_paths+=("$HOME/.config/Cursor/updater") # 旧位置?
updater_paths+=("$CURSOR_CONFIG_DIR/updater") # 旧位置?
for updater in "${updater_paths[@]}"; do for updater in "${updater_paths[@]}"; do
if [ -f "$updater" ] && [ -x "$updater" ]; then if [ -f "$updater" ] && [ -x "$updater" ]; then
@ -1727,7 +1908,7 @@ select_menu_option() {
# 新增 Cursor 初始化清理函数 # 新增 Cursor 初始化清理函数
cursor_initialize_cleanup() { cursor_initialize_cleanup() {
log_info "正在执行 Cursor 初始化清理..." log_info "正在执行 Cursor 初始化清理..."
# CURSOR_CONFIG_DIR 在脚本全局已定义: $HOME/.config/Cursor
# CURSOR_CONFIG_DIR 在脚本全局已定义: $TARGET_HOME/.config/Cursor
local USER_CONFIG_BASE_PATH="$CURSOR_CONFIG_DIR/User" local USER_CONFIG_BASE_PATH="$CURSOR_CONFIG_DIR/User"
log_debug "用户配置基础路径: $USER_CONFIG_BASE_PATH" log_debug "用户配置基础路径: $USER_CONFIG_BASE_PATH"

55
scripts/run/cursor_mac_id_modifier.sh

@ -105,6 +105,27 @@ log_cmd_output() {
echo "" >> "$LOG_FILE" echo "" >> "$LOG_FILE"
} }
# 生成指定字节长度的十六进制串(2*bytes 个字符),优先 openssl,缺失时使用 python3 兜底
generate_hex_bytes() {
local bytes="$1"
if command -v openssl >/dev/null 2>&1; then
openssl rand -hex "$bytes"
return 0
fi
# mac 脚本已要求 python3,可作为兜底
python3 -c 'import os, sys; print(os.urandom(int(sys.argv[1])).hex())' "$bytes"
}
# 生成随机 UUID(小写),优先 uuidgen,缺失时使用 python3 兜底
generate_uuid() {
if command -v uuidgen >/dev/null 2>&1; then
uuidgen | tr '[:upper:]' '[:lower:]'
return 0
fi
# mac 脚本已要求 python3,可作为兜底
python3 -c 'import uuid; print(str(uuid.uuid4()))'
}
# 🚀 新增 Cursor 防掉试用Pro删除文件夹功能 # 🚀 新增 Cursor 防掉试用Pro删除文件夹功能
remove_cursor_trial_folders() { remove_cursor_trial_folders() {
echo echo
@ -486,12 +507,12 @@ modify_machine_code_config() {
log_info "⏳ [进度] 1/5 - 生成新的设备标识符..." log_info "⏳ [进度] 1/5 - 生成新的设备标识符..."
# 生成新的ID # 生成新的ID
local MAC_MACHINE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
local UUID=$(uuidgen | tr '[:upper:]' '[:lower:]')
local MACHINE_ID=$(openssl rand -hex 32)
local SQM_ID="{$(uuidgen | tr '[:lower:]' '[:upper:]')}"
local MAC_MACHINE_ID=$(generate_uuid)
local UUID=$(generate_uuid)
local MACHINE_ID=$(generate_hex_bytes 32)
local SQM_ID="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}"
# 🔧 新增: serviceMachineId (用于 storage.serviceMachineId) # 🔧 新增: serviceMachineId (用于 storage.serviceMachineId)
local SERVICE_MACHINE_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
local SERVICE_MACHINE_ID=$(generate_uuid)
# 🔧 新增: firstSessionDate (重置首次会话日期) # 🔧 新增: firstSessionDate (重置首次会话日期)
local FIRST_SESSION_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z") local FIRST_SESSION_DATE=$(date -u +"%Y-%m-%dT%H:%M:%S.000Z")
@ -500,7 +521,7 @@ modify_machine_code_config() {
CURSOR_ID_DEVICE_ID="$UUID" CURSOR_ID_DEVICE_ID="$UUID"
CURSOR_ID_SQM_ID="$SQM_ID" CURSOR_ID_SQM_ID="$SQM_ID"
CURSOR_ID_FIRST_SESSION_DATE="$FIRST_SESSION_DATE" CURSOR_ID_FIRST_SESSION_DATE="$FIRST_SESSION_DATE"
CURSOR_ID_SESSION_ID=$(uuidgen | tr '[:upper:]' '[:lower:]')
CURSOR_ID_SESSION_ID=$(generate_uuid)
CURSOR_ID_MAC_ADDRESS="${CURSOR_ID_MAC_ADDRESS:-00:11:22:33:44:55}" CURSOR_ID_MAC_ADDRESS="${CURSOR_ID_MAC_ADDRESS:-00:11:22:33:44:55}"
log_info "✅ [进度] 1/5 - 设备标识符生成完成" log_info "✅ [进度] 1/5 - 设备标识符生成完成"
@ -711,7 +732,7 @@ modify_machine_code_config() {
log_info "💾 [备份] .updaterId 文件已备份: $updater_id_backup" log_info "💾 [备份] .updaterId 文件已备份: $updater_id_backup"
fi fi
# 生成新的 updaterId(UUID格式) # 生成新的 updaterId(UUID格式)
local new_updater_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
local new_updater_id=$(generate_uuid)
if echo -n "$new_updater_id" > "$updater_id_file_path" 2>/dev/null; then if echo -n "$new_updater_id" > "$updater_id_file_path" 2>/dev/null; then
log_info "✅ [updaterId] .updaterId 文件修改成功: $new_updater_id" log_info "✅ [updaterId] .updaterId 文件修改成功: $new_updater_id"
# 设置 .updaterId 文件为只读 # 设置 .updaterId 文件为只读
@ -1640,27 +1661,27 @@ modify_cursor_js_files() {
local ids_missing=false local ids_missing=false
if [ -z "$machine_id" ]; then if [ -z "$machine_id" ]; then
machine_id=$(openssl rand -hex 32)
machine_id=$(generate_hex_bytes 32)
ids_missing=true ids_missing=true
fi fi
if [ -z "$machine_guid" ]; then if [ -z "$machine_guid" ]; then
machine_guid=$(uuidgen | tr '[:upper:]' '[:lower:]')
machine_guid=$(generate_uuid)
ids_missing=true ids_missing=true
fi fi
if [ -z "$device_id" ]; then if [ -z "$device_id" ]; then
device_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
device_id=$(generate_uuid)
ids_missing=true ids_missing=true
fi fi
if [ -z "$mac_machine_id" ]; then if [ -z "$mac_machine_id" ]; then
mac_machine_id=$(openssl rand -hex 32)
mac_machine_id=$(generate_hex_bytes 32)
ids_missing=true ids_missing=true
fi fi
if [ -z "$sqm_id" ]; then if [ -z "$sqm_id" ]; then
sqm_id="{$(uuidgen | tr '[:lower:]' '[:upper:]')}"
sqm_id="{$(generate_uuid | tr '[:lower:]' '[:upper:]')}"
ids_missing=true ids_missing=true
fi fi
if [ -z "$session_id" ]; then if [ -z "$session_id" ]; then
session_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
session_id=$(generate_uuid)
ids_missing=true ids_missing=true
fi fi
if [ -z "$first_session_date" ]; then if [ -z "$first_session_date" ]; then
@ -2635,10 +2656,10 @@ if (typeof window !== 'undefined') {
console.log('Cursor全局设备标识符拦截已激活 - ES模块版本'); console.log('Cursor全局设备标识符拦截已激活 - ES模块版本');
" "
# 将代码注入到文件开头 # 将代码注入到文件开头
local new_uuid=$(uuidgen | tr '[:upper:]' '[:lower:]')
local machine_id="auth0|user_$(openssl rand -hex 16)"
local device_id=$(uuidgen | tr '[:upper:]' '[:lower:]')
local mac_machine_id=$(openssl rand -hex 32)
local new_uuid=$(generate_uuid)
local machine_id="auth0|user_$(generate_hex_bytes 16)"
local device_id=$(generate_uuid)
local mac_machine_id=$(generate_hex_bytes 32)
inject_universal_code=${inject_universal_code//\$\{new_uuid\}/$new_uuid} inject_universal_code=${inject_universal_code//\$\{new_uuid\}/$new_uuid}
inject_universal_code=${inject_universal_code//\$\{machine_id\}/$machine_id} inject_universal_code=${inject_universal_code//\$\{machine_id\}/$machine_id}

Loading…
Cancel
Save