备份: 完整开发状态(含反混淆脚本和临时文件)

This commit is contained in:
ccdojox-crypto
2025-12-17 17:18:02 +08:00
parent 9e2333c90c
commit 7e9ea173a7
2872 changed files with 326818 additions and 249 deletions

228
extension_clean/LICENSE.txt Normal file
View File

@@ -0,0 +1,228 @@
MIT License
Copyright (c) 2024 CursorPro
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M12 2L2 7l10 5 10-5-10-5z"/>
<path d="M2 17l10 5 10-5"/>
<path d="M2 12l10 5 10-5"/>
</svg>

After

Width:  |  Height:  |  Size: 266 B

View File

@@ -0,0 +1,258 @@
'use strict';
// ============================================
// CursorPro API Client - 反混淆版本
// ============================================
Object.defineProperty(exports, "__esModule", { value: true });
const vscode = require('vscode');
// 默认 API 地址
const DEFAULT_API_URL = 'https://api.aicode.edu.pl';
const REQUEST_TIMEOUT = 15000; // 15秒超时
let isOnline = true;
let onlineStatusCallbacks = [];
/**
* 获取 API URL (从配置或使用默认值)
*/
function getApiUrl() {
const config = vscode.workspace.getConfiguration('cursorpro');
return config.get('apiUrl') || DEFAULT_API_URL;
}
exports.getApiUrl = getApiUrl;
/**
* 获取在线状态
*/
function getOnlineStatus() {
return isOnline;
}
exports.getOnlineStatus = getOnlineStatus;
/**
* 监听在线状态变化
*/
function onOnlineStatusChange(callback) {
onlineStatusCallbacks.push(callback);
return () => {
onlineStatusCallbacks = onlineStatusCallbacks.filter(cb => cb !== callback);
};
}
exports.onOnlineStatusChange = onOnlineStatusChange;
/**
* 设置在线状态
*/
function setOnlineStatus(status) {
if (isOnline !== status) {
isOnline = status;
onlineStatusCallbacks.forEach(callback => callback(status));
}
}
/**
* 带超时的 fetch
*/
async function fetchWithTimeout(url, options, timeout) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
try {
const response = await fetch(url, {
...options,
signal: controller.signal
});
clearTimeout(timeoutId);
return response;
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
}
/**
* 通用请求函数
*/
async function request(endpoint, method = 'GET', body) {
const url = `${getApiUrl()}${endpoint}`;
const options = {
method: method,
headers: {
'Content-Type': 'application/json'
}
};
if (body) {
options.body = JSON.stringify(body);
}
try {
const response = await fetchWithTimeout(url, options, REQUEST_TIMEOUT);
const data = await response.json();
setOnlineStatus(true);
if (!response.ok && data.error) {
data.success = false;
data.message = data.error;
}
return data;
} catch (error) {
// 检查是否是网络错误
const isNetworkError = error.name === 'AbortError' ||
error.name === 'TypeError' ||
error.message?.includes('fetch') ||
error.message?.includes('network') ||
error.message?.includes('ECONNREFUSED') ||
error.message?.includes('ENOTFOUND') ||
error.message?.includes('ETIMEDOUT');
if (isNetworkError) {
setOnlineStatus(false);
return {
success: false,
error: '网络连接失败,请检查网络',
isOffline: true
};
}
throw error;
}
}
/**
* 验证 Key
*/
async function verifyKey(key) {
return request('/api/verify-key', 'POST', { key });
}
exports.verifyKey = verifyKey;
/**
* 切换账号
*/
async function switchAccount(key) {
return request('/api/switch-account', 'POST', { key });
}
exports.switchAccount = switchAccount;
/**
* 获取代理配置
*/
async function getProxyConfig() {
return request('/api/proxy-config', 'GET');
}
exports.getProxyConfig = getProxyConfig;
/**
* 更新代理配置
*/
async function updateProxyConfig(isEnabled, proxyUrl) {
return request('/api/proxy-config', 'PUT', {
is_enabled: isEnabled,
proxy_url: proxyUrl
});
}
exports.updateProxyConfig = updateProxyConfig;
// ============================================
// 无感换号 (Seamless Mode) API
// ============================================
/**
* 获取无缝模式状态
*/
async function getSeamlessStatus() {
return request('/api/seamless/status');
}
exports.getSeamlessStatus = getSeamlessStatus;
/**
* 获取用户切换状态
*/
async function getUserSwitchStatus(userKey) {
return request('/api/seamless/user-status?userKey=' + encodeURIComponent(userKey));
}
exports.getUserSwitchStatus = getUserSwitchStatus;
/**
* 获取无缝配置
*/
async function getSeamlessConfig() {
return request('/api/seamless/config');
}
exports.getSeamlessConfig = getSeamlessConfig;
/**
* 更新无缝配置
*/
async function updateSeamlessConfig(config) {
return request('/api/seamless/config', 'POST', config);
}
exports.updateSeamlessConfig = updateSeamlessConfig;
/**
* 注入无缝模式
*/
async function injectSeamless(apiUrl, userKey) {
return request('/api/seamless/inject', 'POST', {
api_url: apiUrl,
user_key: userKey
});
}
exports.injectSeamless = injectSeamless;
/**
* 恢复无缝模式
*/
async function restoreSeamless() {
return request('/api/seamless/restore', 'POST');
}
exports.restoreSeamless = restoreSeamless;
/**
* 获取无缝账号列表
*/
async function getSeamlessAccounts() {
return request('/api/seamless/accounts');
}
exports.getSeamlessAccounts = getSeamlessAccounts;
/**
* 同步无缝账号
*/
async function syncSeamlessAccounts(accounts) {
return request('/api/seamless/sync-accounts', 'POST', { accounts });
}
exports.syncSeamlessAccounts = syncSeamlessAccounts;
/**
* 获取无缝 Token
*/
async function getSeamlessToken(userKey) {
return request('/api/seamless/get-token?userKey=' + encodeURIComponent(userKey));
}
exports.getSeamlessToken = getSeamlessToken;
/**
* 切换无缝 Token
*/
async function switchSeamlessToken(userKey) {
return request('/api/seamless/switch-token', 'POST', {
mode: 'manual',
userKey: userKey
});
}
exports.switchSeamlessToken = switchSeamlessToken;
/**
* 获取最新版本
*/
async function getLatestVersion() {
return request('/api/version');
}
exports.getLatestVersion = getLatestVersion;

View File

@@ -0,0 +1,221 @@
'use strict';
// ============================================
// CursorPro Extension - 反混淆版本
// ============================================
Object.defineProperty(exports, "__esModule", { value: true });
const vscode = require('vscode');
const provider_1 = require('./webview/provider');
const fs = require('fs');
const path = require('path');
let usageStatusBarItem;
// 创建输出通道
exports.outputChannel = vscode.window.createOutputChannel('CursorPro');
/**
* 日志函数
*/
function log(message) {
const timestamp = new Date().toLocaleTimeString();
exports.outputChannel.appendLine('[' + timestamp + '] ' + message);
console.log('[CursorPro] ' + message);
}
exports.log = log;
/**
* 清理 Service Worker 缓存
*/
function cleanServiceWorkerCache() {
try {
const platform = process.platform;
const cachePaths = [];
if (platform === 'win32') {
const appData = process.env.APPDATA || '';
const localAppData = process.env.LOCALAPPDATA || '';
cachePaths.push(
path.join(appData, 'Cursor', 'Service Worker'),
path.join(localAppData, 'Cursor', 'Service Worker'),
path.join(appData, 'Cursor', 'GPUCache'),
path.join(localAppData, 'Cursor', 'GPUCache')
);
} else if (platform === 'darwin') {
const home = process.env.HOME || '';
cachePaths.push(
path.join(home, 'Library', 'Application Support', 'Cursor', 'Service Worker'),
path.join(home, 'Library', 'Caches', 'Cursor', 'Service Worker')
);
} else {
const home = process.env.HOME || '';
cachePaths.push(
path.join(home, '.config', 'Cursor', 'Service Worker'),
path.join(home, '.cache', 'Cursor', 'Service Worker')
);
}
for (const cachePath of cachePaths) {
if (!fs.existsSync(cachePath)) continue;
// 清理 ScriptCache
const scriptCachePath = path.join(cachePath, 'ScriptCache');
if (fs.existsSync(scriptCachePath)) {
try {
const files = fs.readdirSync(scriptCachePath);
for (const file of files) {
try {
fs.unlinkSync(path.join(scriptCachePath, file));
} catch (e) {}
}
console.log('[CursorPro] Service Worker ScriptCache 已清理:', scriptCachePath);
} catch (e) {}
}
// 清理 CacheStorage
const cacheStoragePath = path.join(cachePath, 'CacheStorage');
if (fs.existsSync(cacheStoragePath)) {
try {
deleteFolderRecursive(cacheStoragePath);
console.log('[CursorPro] Service Worker CacheStorage 已清理:', cacheStoragePath);
} catch (e) {}
}
// 清理 Database
const databasePath = path.join(cachePath, 'Database');
if (fs.existsSync(databasePath)) {
try {
deleteFolderRecursive(databasePath);
console.log('[CursorPro] Service Worker Database 已清理:', databasePath);
} catch (e) {}
}
}
} catch (error) {
console.log('[CursorPro] 清理 Service Worker 缓存时出错:', error);
}
}
/**
* 递归删除文件夹
*/
function deleteFolderRecursive(folderPath) {
if (fs.existsSync(folderPath)) {
fs.readdirSync(folderPath).forEach(file => {
const curPath = path.join(folderPath, file);
if (fs.lstatSync(curPath).isDirectory()) {
deleteFolderRecursive(curPath);
} else {
try {
fs.unlinkSync(curPath);
} catch (e) {}
}
});
try {
fs.rmdirSync(folderPath);
} catch (e) {}
}
}
/**
* 激活扩展
*/
function activate(context) {
// 清理 Service Worker 缓存
cleanServiceWorkerCache();
// 创建 WebView Provider
const viewProvider = new provider_1.CursorProViewProvider(context.extensionUri, context);
// 注册 WebView
context.subscriptions.push(
vscode.window.registerWebviewViewProvider('cursorpro.mainView', viewProvider)
);
// 创建状态栏项
usageStatusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 100);
usageStatusBarItem.text = '$(dashboard) 用量: --';
usageStatusBarItem.tooltip = '点击查看账号用量详情';
usageStatusBarItem.command = 'cursorpro.showPanel';
usageStatusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.prominentBackground');
// 如果有保存的 key显示状态栏
const savedKey = context.globalState.get('cursorpro.key');
if (savedKey) {
usageStatusBarItem.show();
}
context.subscriptions.push(usageStatusBarItem);
// 设置同步的键
context.globalState.setKeysForSync(['cursorpro.key']);
// 注册显示面板命令
context.subscriptions.push(
vscode.commands.registerCommand('cursorpro.showPanel', () => {
vscode.commands.executeCommand('cursorpro.mainView.focus');
})
);
}
exports.activate = activate;
/**
* 停用扩展
*/
function deactivate() {
console.log('CursorPro 插件已停用');
}
exports.deactivate = deactivate;
/**
* 显示状态栏
*/
function showStatusBar() {
if (usageStatusBarItem) {
usageStatusBarItem.show();
}
}
exports.showStatusBar = showStatusBar;
/**
* 隐藏状态栏
*/
function hideStatusBar() {
if (usageStatusBarItem) {
usageStatusBarItem.hide();
}
}
exports.hideStatusBar = hideStatusBar;
/**
* 更新用量状态栏
* @param {number} requestCount - 请求次数
* @param {number|string} usageCost - 已用额度
*/
function updateUsageStatusBar(requestCount, usageCost) {
if (usageStatusBarItem) {
const count = typeof requestCount === 'number' ? requestCount : requestCount;
const cost = typeof usageCost === 'number' ? usageCost : parseFloat(usageCost.toString().replace('$', '')) || 0;
const costDisplay = typeof usageCost === 'number' ? '$' + usageCost.toFixed(2) : usageCost;
usageStatusBarItem.text = '$(dashboard) ' + count + '次 | ' + costDisplay;
usageStatusBarItem.tooltip = '请求次数: ' + count + '\n已用额度: ' + costDisplay + '\n点击查看详情';
// 根据用量设置颜色
if (cost >= 10) {
// 高用量 - 红色警告
usageStatusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.errorBackground');
usageStatusBarItem.color = undefined;
} else if (cost >= 5) {
// 中用量 - 黄色警告
usageStatusBarItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
usageStatusBarItem.color = undefined;
} else {
// 低用量 - 绿色
usageStatusBarItem.backgroundColor = undefined;
usageStatusBarItem.color = '#4ade80';
}
}
}
exports.updateUsageStatusBar = updateUsageStatusBar;

View File

@@ -0,0 +1,213 @@
'use strict';
// ============================================
// CursorPro Account Utils - 反混淆版本
// ============================================
Object.defineProperty(exports, "__esModule", { value: true });
const vscode = require('vscode');
const path = require('path');
const fs = require('fs');
const child_process = require('child_process');
const util = require('util');
const sqlite_1 = require('./sqlite');
const execAsync = util.promisify(child_process.exec);
/**
* 获取 Cursor 相关路径
* @returns {{dbPath: string, storagePath: string, machineidPath: string}}
*/
function getCursorPaths() {
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
if (process.platform === 'win32') {
const appData = process.env.APPDATA || '';
return {
dbPath: path.join(appData, 'Cursor', 'User', 'globalStorage', 'state.vscdb'),
storagePath: path.join(appData, 'Cursor', 'User', 'globalStorage', 'storage.json'),
machineidPath: path.join(appData, 'Cursor', 'machineid')
};
} else if (process.platform === 'darwin') {
return {
dbPath: path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'state.vscdb'),
storagePath: path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'User', 'globalStorage', 'storage.json'),
machineidPath: path.join(homeDir, 'Library', 'Application Support', 'Cursor', 'machineid')
};
} else {
// Linux
return {
dbPath: path.join(homeDir, '.config', 'Cursor', 'User', 'globalStorage', 'state.vscdb'),
storagePath: path.join(homeDir, '.config', 'Cursor', 'User', 'globalStorage', 'storage.json'),
machineidPath: path.join(homeDir, '.config', 'Cursor', 'machineid')
};
}
}
exports.getCursorPaths = getCursorPaths;
/**
* 将账号数据写入本地存储
* @param {Object} accountData - 账号数据
* @param {string} accountData.accessToken - 访问令牌
* @param {string} accountData.refreshToken - 刷新令牌
* @param {string} accountData.workosSessionToken - WorkOS 会话令牌
* @param {string} accountData.email - 邮箱
* @param {string} accountData.membership_type - 会员类型
* @param {string} accountData.machineId - 机器 ID
* @param {string} accountData.macMachineId - Mac 机器 ID
* @param {string} accountData.devDeviceId - 开发设备 ID
* @param {string} accountData.serviceMachineId - 服务机器 ID
* @returns {Promise<boolean>}
*/
async function writeAccountToLocal(accountData) {
try {
const cursorPaths = getCursorPaths();
const { dbPath, storagePath, machineidPath } = cursorPaths;
console.log('[CursorPro] 数据库路径:', dbPath);
console.log('[CursorPro] 数据库存在:', fs.existsSync(dbPath));
console.log('[CursorPro] 账号数据:', JSON.stringify({
hasAccessToken: !!accountData.accessToken,
hasRefreshToken: !!accountData.refreshToken,
hasWorkosToken: !!accountData.workosSessionToken,
email: accountData.email
}));
// 写入数据库
if (fs.existsSync(dbPath)) {
try {
const entries = [];
if (accountData.accessToken) {
entries.push(['cursorAuth/accessToken', accountData.accessToken]);
}
if (accountData.refreshToken) {
entries.push(['cursorAuth/refreshToken', accountData.refreshToken]);
}
if (accountData.workosSessionToken) {
entries.push(['cursorAuth/WorkosCursorSessionToken', accountData.workosSessionToken]);
}
if (accountData.email) {
entries.push(['cursorAuth/cachedEmail', accountData.email]);
}
if (accountData.membership_type) {
entries.push(['cursorAuth/stripeMembershipType', accountData.membership_type]);
}
if (accountData.devDeviceId) {
entries.push(['telemetry.devDeviceId', accountData.devDeviceId || 'default']);
}
if (accountData.serviceMachineId) {
entries.push(['serviceMachineId', accountData.serviceMachineId]);
}
console.log('[CursorPro] 准备写入', entries.length, '个字段');
const success = await sqlite_1.sqliteSetBatch(dbPath, entries);
if (!success) {
throw new Error('数据库写入失败');
}
console.log('[CursorPro] 已写入', entries.length, '个字段');
} catch (error) {
console.error('[CursorPro] 数据库写入错误:', error);
vscode.window.showErrorMessage('数据库写入失败: ' + error);
return false;
}
} else {
console.error('[CursorPro] 数据库文件不存在:', dbPath);
vscode.window.showErrorMessage('[CursorPro] 数据库文件不存在');
return false;
}
// 更新 storage.json
if (fs.existsSync(storagePath)) {
const storageData = JSON.parse(fs.readFileSync(storagePath, 'utf-8'));
if (accountData.machineId) {
storageData['telemetry.machineId'] = accountData.machineId;
}
if (accountData.macMachineId) {
storageData['telemetry.macMachineId'] = accountData.macMachineId;
}
if (accountData.devDeviceId) {
storageData['telemetry.devDeviceId'] = accountData.devDeviceId;
}
if (accountData.serviceMachineId) {
storageData['serviceMachineId'] = accountData.serviceMachineId;
}
fs.writeFileSync(storagePath, JSON.stringify(storageData, null, 4));
console.log('[CursorPro] storage.json 已更新');
}
// 更新 machineid 文件
if (accountData.machineId && machineidPath) {
const machineIdDir = path.dirname(machineidPath);
if (!fs.existsSync(machineIdDir)) {
fs.mkdirSync(machineIdDir, { recursive: true });
}
fs.writeFileSync(machineidPath, accountData.machineId);
console.log('[CursorPro] machineid 文件已更新');
}
// Windows: 更新注册表 (如果提供了 devDeviceId)
if (accountData.devDeviceId && process.platform === 'win32') {
try {
const regCommand = 'reg add "HKCU\\Software\\Cursor" /v devDeviceId /t REG_SZ /d "' + accountData.devDeviceId + '" /f';
await execAsync(regCommand);
console.log('[CursorPro] 注册表已更新');
} catch (error) {
console.warn('[CursorPro] 注册表写入失败(可能需要管理员权限):', error);
}
}
return true;
} catch (error) {
console.error('[CursorPro] writeAccountToLocal 错误:', error);
return false;
}
}
exports.writeAccountToLocal = writeAccountToLocal;
/**
* 关闭 Cursor 进程
*/
async function closeCursor() {
try {
if (process.platform === 'win32') {
await execAsync('taskkill /F /IM Cursor.exe').catch(() => {});
} else {
await execAsync('pkill -9 -f Cursor').catch(() => {});
}
} catch (error) {
console.warn('[CursorPro] 关闭 Cursor 失败:', error);
}
}
exports.closeCursor = closeCursor;
/**
* 提示重启 Cursor
* @param {string} message - 提示消息
*/
async function promptRestartCursor(message) {
const selection = await vscode.window.showInformationMessage(
message,
'立即重启',
'稍后'
);
if (selection === '立即重启') {
await closeCursor();
}
}
exports.promptRestartCursor = promptRestartCursor;

View File

@@ -0,0 +1,176 @@
'use strict';
// ============================================
// CursorPro SQLite Utils - 反混淆版本
// ============================================
Object.defineProperty(exports, "__esModule", { value: true });
const child_process = require('child_process');
const util = require('util');
const fs = require('fs');
const path = require('path');
const os = require('os');
const execAsync = util.promisify(child_process.exec);
/**
* 转义 SQL 字符串中的单引号
*/
function escapeSqlString(value) {
if (value === null || value === undefined) {
return '';
}
return String(value).replace(/'/g, "''");
}
/**
* 执行 SQLite 命令
*/
async function execSqlite(dbPath, sql) {
const isWindows = process.platform === 'win32';
try {
if (isWindows) {
// Windows: 直接使用 sqlite3 命令
const escapedSql = sql.replace(/"/g, '\\"');
const command = `sqlite3 "${dbPath}" "${escapedSql}"`;
const { stdout, stderr } = await execAsync(command, {
encoding: 'utf-8',
maxBuffer: 10 * 1024 * 1024
});
if (stderr && !stderr.includes('-- Loading')) {
console.warn('[SQLite] stderr:', stderr);
}
return stdout.trim();
} else {
// Unix/Mac: 使用临时文件避免命令行转义问题
const tmpFile = path.join(os.tmpdir(), 'cursor_sql_' + Date.now() + '.sql');
fs.writeFileSync(tmpFile, sql, 'utf-8');
try {
const command = `sqlite3 "${dbPath}" < "${tmpFile}"`;
const { stdout, stderr } = await execAsync(command, {
encoding: 'utf-8',
maxBuffer: 10 * 1024 * 1024,
shell: '/bin/bash'
});
if (stderr && !stderr.includes('-- Loading')) {
console.warn('[SQLite] stderr:', stderr);
}
return stdout.trim();
} finally {
try {
fs.unlinkSync(tmpFile);
} catch (e) {
// 忽略删除临时文件失败
}
}
}
} catch (error) {
// 检查是否是 sqlite3 不存在的错误
if (error.code === 'ENOENT' ||
error.message?.includes('not found') ||
error.message?.includes('not recognized')) {
throw new Error('sqlite3 命令未找到,请确保已安装 sqlite3');
}
throw error;
}
}
/**
* 从 SQLite 数据库读取值
*/
async function sqliteGet(dbPath, key) {
if (!fs.existsSync(dbPath)) {
console.warn('[SQLite] 数据库文件不存在:', dbPath);
return null;
}
try {
const sql = `SELECT value FROM ItemTable WHERE key = '${escapeSqlString(key)}';`;
const result = await execSqlite(dbPath, sql);
return result || null;
} catch (error) {
console.error('[SQLite] 读取失败:', error);
return null;
}
}
exports.sqliteGet = sqliteGet;
/**
* 向 SQLite 数据库写入值
*/
async function sqliteSet(dbPath, key, value) {
if (!fs.existsSync(dbPath)) {
console.warn('[SQLite] 数据库文件不存在:', dbPath);
return false;
}
try {
const sql = `INSERT OR REPLACE INTO ItemTable (key, value) VALUES ('${escapeSqlString(key)}', '${escapeSqlString(value)}');`;
await execSqlite(dbPath, sql);
return true;
} catch (error) {
console.error('[SQLite] 写入失败:', error);
return false;
}
}
exports.sqliteSet = sqliteSet;
/**
* 批量写入 SQLite 数据库
*/
async function sqliteSetBatch(dbPath, entries) {
if (!fs.existsSync(dbPath)) {
console.warn('[SQLite] 数据库文件不存在:', dbPath);
return false;
}
if (entries.length === 0) {
return true;
}
try {
const statements = entries.map(([key, value]) =>
`INSERT OR REPLACE INTO ItemTable (key, value) VALUES ('${escapeSqlString(key)}', '${escapeSqlString(value)}');`
);
const sql = 'BEGIN; ' + statements.join(' ') + ' COMMIT;';
await execSqlite(dbPath, sql);
return true;
} catch (error) {
console.error('[SQLite] 批量写入失败:', error);
return false;
}
}
exports.sqliteSetBatch = sqliteSetBatch;
/**
* 批量读取 SQLite 数据库
*/
async function sqliteGetBatch(dbPath, keys) {
const result = new Map();
if (!fs.existsSync(dbPath)) {
console.warn('[SQLite] 数据库文件不存在:', dbPath);
keys.forEach(key => result.set(key, null));
return result;
}
try {
for (const key of keys) {
const value = await sqliteGet(dbPath, key);
result.set(key, value);
}
return result;
} catch (error) {
console.error('[SQLite] 批量读取失败:', error);
keys.forEach(key => result.set(key, null));
return result;
}
}
exports.sqliteGetBatch = sqliteGetBatch;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,76 @@
{
"name": "hummingbird-cursorpro",
"displayName": "蜂鸟Pro",
"description": "蜂鸟Pro - Cursor 账号管理与智能换号工具",
"version": "2.0.0",
"publisher": "hummingbird",
"repository": {
"type": "git",
"url": "https://github.com/fnpro/fnpro-extension"
},
"engines": {
"vscode": "^1.80.0"
},
"categories": [
"Other"
],
"extensionKind": [
"ui"
],
"activationEvents": [
"onStartupFinished"
],
"main": "./out/extension.js",
"contributes": {
"commands": [
{
"command": "cursorpro.showPanel",
"title": "蜂鸟Pro: 打开控制面板"
},
{
"command": "cursorpro.switchAccount",
"title": "蜂鸟Pro: 立即换号"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "cursorpro-sidebar",
"title": "蜂鸟Pro",
"icon": "media/icon.svg"
}
]
},
"views": {
"cursorpro-sidebar": [
{
"type": "webview",
"id": "cursorpro.mainView",
"name": "控制面板"
}
]
},
"configuration": {
"title": "蜂鸟Pro",
"properties": {
"cursorpro.cursorPath": {
"type": "string",
"default": "",
"description": "手动设置 Cursor 安装路径如果自动检测失败。例如C:\\Program Files\\cursor 或 /Applications/Cursor.app"
}
}
}
},
"scripts": {
"vscode:prepublish": "echo skip",
"compile": "tsc -p ./",
"watch": "tsc -watch -p ./",
"lint": "eslint src --ext ts"
},
"devDependencies": {
"@types/node": "^20.0.0",
"@types/vscode": "^1.80.0",
"esbuild": "^0.27.0",
"typescript": "^5.0.0"
}
}

View File

@@ -0,0 +1,280 @@
#!/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 ""