forked from Angels-Ray/fake-rosrus
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathextension.js
305 lines (262 loc) · 8.59 KB
/
extension.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
const vscode = require('vscode');
const fs = require('fs').promises;
const path = require('path');
const os = require('os');
const crypto = require('crypto');
const { v4: uuidv4 } = require('uuid');
const initSqlJs = require('sql.js');
/**
* 激活扩展时调用的方法
* @param {vscode.ExtensionContext} context - VSCode扩展上下文
*/
function activate(context) {
console.log('Extension "fake-cursor" is now active!');
context.subscriptions.push(
vscode.commands.registerCommand('fake-cursor.regenerateId', handleRegenerateId),
vscode.commands.registerCommand('fake-cursor.setToken', handleSetToken),
vscode.commands.registerCommand('fake-cursor.readToken', handleReadToken)
);
}
/**
* 处理重新生成设备ID的命令
*/
async function handleRegenerateId() {
try {
const confirm = await vscode.window.showWarningMessage(
'此操作将重新生成设备ID并清空认证信息,是否继续?',
{
modal: true,
detail: '将会备份原有配置文件,但建议手动备份以防万一。'
},
'继续',
'取消'
);
if (confirm !== '继续') {
console.log('操作已取消');
return;
}
const paths = await getStoragePath();
await updateDeviceIds(paths.storagePath, paths.dbPath);
} catch (error) {
vscode.window.showErrorMessage(`操作失败: ${error.message}`);
console.error('详细错误:', error);
}
}
/**
* 处理设置Token的命令
*/
async function handleSetToken() {
try {
const token = await vscode.window.showInputBox({
prompt: '请输入 Access Token',
password: true,
placeHolder: '输入 Access Token'
});
if (!token) {
console.log('操作已取消');
return;
}
const confirm = await vscode.window.showWarningMessage(
'此操作将重新生成设备ID并设置新的Token,是否继续?',
{
modal: true,
detail: '将会备份原有配置文件,但建议手动备份以防万一。'
},
'继续',
'取消'
);
if (confirm !== '继续') {
console.log('操作已取消');
return;
}
const paths = await getStoragePath();
await updateDeviceIds(paths.storagePath, paths.dbPath, token);
} catch (error) {
vscode.window.showErrorMessage(`操作失败: ${error.message}`);
console.error('详细错误:', error);
}
}
/**
* 获取存储文件的路径
* @returns {Promise<{storagePath: string, dbPath: string}>} 返回存储文件和数据库的路径
*/
async function getStoragePath() {
const config = vscode.workspace.getConfiguration('fake-cursor');
const customPath = config.get('storagePath');
const basePath = customPath || path.join(
os.homedir(),
...{
'win32': ['AppData', 'Roaming'],
'darwin': ['Library', 'Application Support'],
'linux': ['.config']
}[os.platform()] || (() => { throw new Error('不支持的操作系统'); })(),
'Cursor', 'User', 'globalStorage'
);
return validatePaths(
path.join(basePath, 'storage.json'),
path.join(basePath, 'state.vscdb')
);
}
/**
* 验证存储文件和数据库路径
* @param {string} storagePath - 存储文件路径
* @param {string} dbPath - 数据库文件路径
* @returns {Promise<{storagePath: string, dbPath: string}>} 返回验证后的路径
*/
async function validatePaths(storagePath, dbPath) {
async function checkPaths(storage, db) {
const storageExists = await pathExists(storage);
const dbExists = await pathExists(db);
if (!storageExists || !dbExists) {
const missingFiles = [
!storageExists && 'storage_fake.json',
!dbExists && 'state_fake.vscdb'
].filter(Boolean).join(' 和 ');
throw new Error(`所选文件夹中缺少: ${missingFiles}`);
}
return { storagePath: storage, dbPath: db };
}
try {
return await checkPaths(storagePath, dbPath);
} catch (error) {
const choice = await vscode.window.showInformationMessage(
error.message,
'手动选择文件夹'
);
if (choice !== '手动选择文件夹') {
throw new Error('操作已取消');
}
const fileUri = await vscode.window.showOpenDialog({
canSelectFiles: false,
canSelectFolders: true,
canSelectMany: false,
title: '选择配置文件所在文件夹'
});
if (!fileUri?.length) {
throw new Error('未选择文件夹');
}
const selectedDir = fileUri[0].fsPath;
const newPaths = {
storagePath: path.join(selectedDir, 'storage_fake.json'),
dbPath: path.join(selectedDir, 'state_fake.vscdb')
};
// 验证新选择的文件夹
return await checkPaths(newPaths.storagePath, newPaths.dbPath);
}
}
/**
* 更新设备ID并创建备份
* @param {string} storagePath - 存储文件路径
* @param {string} dbPath - 数据库文件路径
* @param {string} [accessToken] - 可选的访问令牌
*/
async function updateDeviceIds(storagePath, dbPath, accessToken) {
// 创建备份
await Promise.all([
fs.copyFile(storagePath, `${storagePath}.backup`).catch(() => {}),
fs.copyFile(dbPath, `${dbPath}.backup`).catch(() => {})
]);
// 生成新ID
const newIds = {
devDeviceId: uuidv4(),
machineId: crypto.randomBytes(43).toString('hex').substring(0, 86),
sqmId: `{${uuidv4().toUpperCase()}}`,
macMachineId: crypto.randomBytes(32).toString('hex')
};
try {
// 写入 devDeviceId 到 machineid 文件
const machineIdPath = path.join(path.dirname(path.dirname(path.dirname(storagePath))), 'machineid');
await fs.writeFile(machineIdPath, newIds.devDeviceId, 'utf8');
} catch {
// 忽略任何路径计算或写入过程中的错误
console.log('写入 machineid 文件失败,继续执行...');
}
// 更新JSON配置
const jsonConfig = JSON.parse(await fs.readFile(storagePath, 'utf8'));
const oldIds = Object.fromEntries(
Object.keys(newIds).map(key => [key, jsonConfig[`telemetry.${key}`] || '无'])
);
Object.entries(newIds).forEach(([key, value]) => {
jsonConfig[`telemetry.${key}`] = value;
});
await fs.writeFile(storagePath, JSON.stringify(jsonConfig, null, 2));
// 数据库操作结果
let dbUpdateResult = '';
// 更新数据库
try {
const SQL = await initSqlJs();
const dbBuffer = await fs.readFile(dbPath);
const db = new SQL.Database(dbBuffer);
// 更新设备ID
db.run('UPDATE ItemTable SET value = ? WHERE key = ?',
[newIds.devDeviceId, 'storage.serviceMachineId']);
// 处理认证信息和会员类型
const updates = [
['cursorAuth/accessToken', accessToken || ''],
['cursorAuth/refreshToken', accessToken || ''],
['cursorAuth/cachedEmail', accessToken ? 'admin@cursor.sh' : ''],
['cursorAuth/cachedSignUpType', accessToken ? 'Auth_0' : ''],
['cursorAuth/stripeMembershipType', accessToken ? 'pro' : 'free_trial']
];
updates.forEach(([key, value]) => {
db.run('UPDATE ItemTable SET value = ? WHERE key = ?', [value, key]);
});
// 保存数据库文件
const data = db.export();
await fs.writeFile(dbPath, Buffer.from(data));
db.close();
dbUpdateResult = accessToken
? '✅ 数据库更新成功\n✅ Token已更新\n✅ 会员类型已设置为 pro'
: '✅ 数据库更新成功\n✅ 认证信息已清空\n✅ 会员类型已设置为 free_trial';
} catch (error) {
dbUpdateResult = '❌ 数据库更新失败,请手动更新 state.vscdb';
console.error('更新数据库失败:', error);
}
// 显示结果并退出 Cursor
await vscode.window.showInformationMessage(
Object.entries(newIds)
.map(([key, value]) => `${key}:\n旧: ${oldIds[key]}\n新: ${value}`)
.join('\n\n') +
'\n\n数据库状态:\n' + dbUpdateResult +
'\n\n✅ 操作已完成,Cursor 将立即退出',
{ modal: true }
).then(() => {
// 使用 process.exit() 强制退出
vscode.commands.executeCommand('workbench.action.quit').then(() => {
setTimeout(() => process.exit(0), 100);
});
});
}
async function pathExists(path) {
try {
await fs.access(path);
return true;
} catch {
return false;
}
}
/**
* 处理获取Token的命令
*/
async function handleReadToken() {
try {
const paths = await getStoragePath();
const SQL = await initSqlJs();
const dbBuffer = await fs.readFile(paths.dbPath);
const db = new SQL.Database(dbBuffer);
const result = db.exec('SELECT value FROM ItemTable WHERE key = "cursorAuth/accessToken"');
db.close();
if (result.length > 0 && result[0].values.length > 0) {
vscode.window.showInformationMessage(`Access Token: ${result[0].values[0][0]}`);
} else {
vscode.window.showInformationMessage('未找到 Access Token');
}
} catch (error) {
vscode.window.showErrorMessage(`操作失败: ${error.message}`);
console.error('详细错误:', error);
}
}
function deactivate() {}
module.exports = { activate, deactivate };