备份: 完整开发状态(含反混淆脚本和临时文件)
This commit is contained in:
213
deobfuscated_full/extension/out/utils/account.js
Normal file
213
deobfuscated_full/extension/out/utils/account.js
Normal 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;
|
||||
176
deobfuscated_full/extension/out/utils/sqlite.js
Normal file
176
deobfuscated_full/extension/out/utils/sqlite.js
Normal 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;
|
||||
Reference in New Issue
Block a user