| #!/usr/bin/env node |
|
|
| const fs = require('fs'); |
| const path = require('path'); |
| const readline = require('readline'); |
| const dotenv = require('dotenv'); |
|
|
| |
| const rl = readline.createInterface({ |
| input: process.stdin, |
| output: process.stdout |
| }); |
|
|
| |
| const ENV_TEMPLATE = `# 服务端口 |
| PORT=3010 |
| |
| # 日志格式 (tiny, combined, common, dev, short) |
| MORGAN_FORMAT=tiny |
| |
| # API Key与Cookie映射关系 (JSON格式) |
| # 格式: {"自定义API Key": "Cookie值"} 或 {"自定义API Key": ["Cookie值1", "Cookie值2"]} |
| API_KEYS={API_KEYS_PLACEHOLDER} |
| |
| # 轮询策略 (random 或 round-robin) |
| ROTATION_STRATEGY=round-robin |
| |
| # Cursor校验和 (可选) |
| # x-cursor-checksum=xxxxxxxx |
| |
| # 自动刷新Cookie设置 |
| # 是否启用自动刷新Cookie (true 或 false) |
| ENABLE_AUTO_REFRESH=true |
| |
| # 自动刷新Cookie的定时规则 (Cron表达式) |
| # 默认每6小时执行一次 |
| REFRESH_CRON=0 */6 * * * |
| |
| # 每个API Key最小Cookie数量 |
| # 当Cookie数量低于此值时,会自动尝试刷新 |
| MIN_COOKIE_COUNT=1000 |
| |
| # Cookie刷新模式 |
| # replace: 每次刷新都将现有cookie全部标记为无效并替换成新cookie(默认) |
| # append: 保留现有cookie,仅追加新cookie |
| COOKIE_REFRESH_MODE=replace |
| |
| # GitHub 仓库信息 |
| GITHUB_OWNER={GITHUB_OWNER_PLACEHOLDER} |
| GITHUB_REPO=Cursor-Register-fix |
| |
| # GitHub Token (用于从GitHub Actions下载Artifact) |
| # 需要有repo权限 |
| GITHUB_TOKEN={GITHUB_TOKEN_PLACEHOLDER} |
| |
| # GitHub Actions 工作流ID |
| # 用于触发工作流程 |
| GITHUB_WORKFLOW_ID=cursor_register.yml |
| |
| # 是否自动触发工作流 |
| # 设置为true时,会自动触发工作流而不是仅获取最新结果 |
| TRIGGER_WORKFLOW=true |
| |
| # 工作流参数设置 目前只支持gmail,outlook过于复杂,暂时不支持 |
| # 注册账号数量 |
| REGISTER_NUMBER=1 |
| # 最大并发工作线程数 |
| REGISTER_MAX_WORKERS=1 |
| # 邮箱服务器类型 (TempEmail 或 IMAP) |
| REGISTER_EMAIL_SERVER=IMAP |
| # 是否将账号令牌注入到OneAPI (true 或 false) |
| REGISTER_INGEST_TO_ONEAPI=false |
| # 是否上传账号信息到Artifact (true 或 false) |
| REGISTER_UPLOAD_ARTIFACT=true |
| # 是否从config.yaml读取邮箱配置 (true 或 false) |
| REGISTER_USE_CONFIG_FILE=false |
| # 邮箱配置JSON字符串(仅在REGISTER_USE_CONFIG_FILE=false时有效) |
| # 格式例如[{"email":"example@gmail.com","imap_server":"imap.gmail.com","imap_port":993,"username":"example@gmail.com","password":"your_app_password"}] |
| REGISTER_EMAIL_CONFIGS={EMAIL_CONFIGS_PLACEHOLDER} |
| `; |
|
|
| |
| console.log('===== Cursor-To-OpenAI 环境配置助手 ====='); |
| console.log('这个脚本将帮助你配置必要的环境变量\n'); |
|
|
| |
| function printAppPasswordInstructions() { |
| console.log('\n===== 如何创建谷歌应用密码 ====='); |
| console.log('1. 访问 https://myaccount.google.com/security'); |
| console.log('2. 在"登录Google"部分,点击"两步验证"'); |
| console.log(' (如果未启用两步验证,需要先启用)'); |
| console.log('3. 在页面底部找到"应用密码",点击进入'); |
| console.log('4. 在"选择应用"下拉菜单中选择"其他(自定义名称)"'); |
| console.log('5. 输入一个名称,例如"Cursor注册"'); |
| console.log('6. 点击"生成"'); |
| console.log('7. 复制生成的16位应用密码(格式如:xxxx xxxx xxxx xxxx)'); |
| console.log('8. 在下面的提示中输入这个密码'); |
| console.log('注意: 应用密码只会显示一次,请务必保存好\n'); |
| } |
|
|
| |
| function loadExistingConfig() { |
| const envPath = path.join(process.cwd(), '.env'); |
| let existingConfig = { |
| apiKeys: {}, |
| githubOwner: '', |
| githubToken: '', |
| emailConfigs: [], |
| cookieRefreshMode: 'append' |
| }; |
| |
| if (fs.existsSync(envPath)) { |
| console.log('发现现有的.env配置文件,将加载现有设置作为默认值'); |
| console.log('提示: 直接按回车将保留现有设置不变\n'); |
| |
| try { |
| |
| const envConfig = dotenv.parse(fs.readFileSync(envPath)); |
| |
| |
| if (envConfig.API_KEYS) { |
| try { |
| existingConfig.apiKeys = JSON.parse(envConfig.API_KEYS); |
| } catch (e) { |
| console.log('无法解析现有的API Keys配置,将使用默认设置'); |
| } |
| } |
| |
| |
| if (envConfig.GITHUB_OWNER) { |
| existingConfig.githubOwner = envConfig.GITHUB_OWNER; |
| } |
| |
| |
| if (envConfig.GITHUB_TOKEN) { |
| existingConfig.githubToken = envConfig.GITHUB_TOKEN; |
| } |
| |
| |
| if (envConfig.REGISTER_EMAIL_CONFIGS) { |
| try { |
| existingConfig.emailConfigs = JSON.parse(envConfig.REGISTER_EMAIL_CONFIGS); |
| } catch (e) { |
| console.log('无法解析现有的Email配置,将使用默认设置'); |
| } |
| } |
| |
| |
| if (envConfig.COOKIE_REFRESH_MODE) { |
| existingConfig.cookieRefreshMode = envConfig.COOKIE_REFRESH_MODE; |
| } |
| |
| console.log('成功加载现有配置'); |
| } catch (error) { |
| console.error('加载现有配置时出错:', error.message); |
| console.log('将使用默认设置'); |
| } |
| } else { |
| console.log('未找到现有的.env配置文件,将创建新的配置文件'); |
| } |
| |
| return existingConfig; |
| } |
|
|
| |
| function promptWithDefault(question, defaultValue) { |
| return new Promise((resolve) => { |
| const defaultText = defaultValue ? ` [${defaultValue}]` : ''; |
| rl.question(`${question}${defaultText}: `, (answer) => { |
| |
| resolve(answer.trim() || defaultValue || ''); |
| }); |
| }); |
| } |
|
|
| |
| async function collectConfig() { |
| |
| const existingConfig = loadExistingConfig(); |
| |
| const config = { |
| apiKeys: {}, |
| githubOwner: '', |
| githubToken: '', |
| emailConfigs: [], |
| cookieRefreshMode: 'replace' |
| }; |
|
|
| |
| config.githubOwner = await promptWithDefault('请输入你的GitHub用户名', existingConfig.githubOwner); |
|
|
| |
| config.githubToken = await promptWithDefault('请输入你的GitHub Token (具有repo权限)', existingConfig.githubToken); |
|
|
| |
| const existingApiKeys = Object.keys(existingConfig.apiKeys); |
| if (existingApiKeys.length > 0) { |
| console.log('\n现有的API Keys:'); |
| existingApiKeys.forEach(key => console.log(`- ${key}`)); |
| |
| const keepExistingApiKeys = await promptWithDefault('是否保留现有的API Keys? (y/n)', 'y'); |
| if (keepExistingApiKeys.toLowerCase() === 'y') { |
| config.apiKeys = { ...existingConfig.apiKeys }; |
| } |
| } |
|
|
| |
| const addNewApiKey = await promptWithDefault('是否添加新的API Key? (y/n)', existingApiKeys.length === 0 ? 'y' : 'n'); |
| if (addNewApiKey.toLowerCase() === 'y') { |
| const apiKey = await promptWithDefault('请输入自定义的API Key (不含sk-前缀,将自动添加)', ''); |
| if (apiKey) { |
| const fullApiKey = apiKey.startsWith('sk-') ? apiKey : `sk-${apiKey}`; |
| config.apiKeys[fullApiKey] = []; |
| } |
| } |
|
|
| |
| const refreshModePrompt = `选择Cookie刷新模式 [append/replace]`; |
| const defaultRefreshMode = existingConfig.cookieRefreshMode || 'replace'; |
| config.cookieRefreshMode = await promptWithDefault(refreshModePrompt, defaultRefreshMode); |
|
|
| |
| if (config.cookieRefreshMode.toLowerCase() === 'replace') { |
| config.cookieRefreshMode = 'replace'; |
| console.log('已选择替换模式: 每次刷新都将现有cookie全部标记为无效并替换成新cookie'); |
| } else { |
| config.cookieRefreshMode = 'append'; |
| console.log('已选择追加模式: 保留现有cookie,仅追加新cookie'); |
| } |
|
|
| |
| if (existingConfig.emailConfigs.length > 0) { |
| console.log('\n现有的Gmail账号:'); |
| existingConfig.emailConfigs.forEach((emailConfig, index) => { |
| console.log(`- ${index + 1}: ${emailConfig.email}`); |
| }); |
| |
| const keepExistingEmails = await promptWithDefault('是否保留现有的Gmail账号? (y/n)', 'y'); |
| if (keepExistingEmails.toLowerCase() === 'y') { |
| config.emailConfigs = [...existingConfig.emailConfigs]; |
| } |
| } |
|
|
| |
| const addNewGmail = await promptWithDefault('是否添加新的Gmail账号? (y/n)', existingConfig.emailConfigs.length === 0 ? 'y' : 'n'); |
| if (addNewGmail.toLowerCase() === 'y') { |
| printAppPasswordInstructions(); |
| await askForGmailAccount(config); |
| } else if (config.emailConfigs.length === 0 && existingConfig.emailConfigs.length === 0) { |
| console.log('\n⚠️ 警告: 未添加Gmail账号,自动刷新功能可能无法正常工作'); |
| console.log('你可以稍后在.env文件中手动配置REGISTER_EMAIL_CONFIGS\n'); |
| } |
|
|
| return config; |
| } |
|
|
| |
| async function askForGmailAccount(config) { |
| const addGmail = await promptWithDefault('\n是否添加Gmail账号用于注册? (y/n)', 'y'); |
| |
| if (addGmail.toLowerCase() === 'y') { |
| const email = await promptWithDefault('请输入Gmail地址', ''); |
| const password = await promptWithDefault('请输入Gmail的应用密码 (不是邮箱密码)', ''); |
| |
| if (email && password) { |
| |
| config.emailConfigs.push({ |
| email: email, |
| imap_server: "imap.gmail.com", |
| imap_port: 993, |
| username: email, |
| password: password |
| }); |
| } |
| |
| const continueAnswer = await promptWithDefault('是否继续添加另一个Gmail账号? (y/n)', 'n'); |
| if (continueAnswer.toLowerCase() === 'y') { |
| await askForGmailAccount(config); |
| } |
| } |
| |
| return config; |
| } |
|
|
| |
| function generateEnvFile(config) { |
| try { |
| |
| const apiKeysJson = JSON.stringify(config.apiKeys); |
| |
| |
| const emailConfigsJson = JSON.stringify(config.emailConfigs); |
| |
| |
| let envContent = ENV_TEMPLATE |
| .replace('{API_KEYS_PLACEHOLDER}', apiKeysJson) |
| .replace('{GITHUB_OWNER_PLACEHOLDER}', config.githubOwner) |
| .replace('{GITHUB_TOKEN_PLACEHOLDER}', config.githubToken) |
| .replace('{EMAIL_CONFIGS_PLACEHOLDER}', emailConfigsJson); |
| |
| |
| envContent = envContent.replace('COOKIE_REFRESH_MODE=append', `COOKIE_REFRESH_MODE=${config.cookieRefreshMode}`); |
| |
| |
| const envPath = path.join(process.cwd(), '.env'); |
| |
| |
| const backupPath = path.join(process.cwd(), '.env.backup'); |
| if (fs.existsSync(envPath)) { |
| |
| fs.copyFileSync(envPath, backupPath); |
| console.log(`\n✅ 已创建原配置文件备份: ${backupPath}`); |
| } |
| |
| fs.writeFileSync(envPath, envContent, 'utf8'); |
| console.log(`\n✅ 配置文件已生成: ${envPath}`); |
| |
| |
| const dataDir = path.join(process.cwd(), 'data'); |
| if (!fs.existsSync(dataDir)) { |
| fs.mkdirSync(dataDir, { recursive: true }); |
| console.log(`✅ 创建数据目录: ${dataDir}`); |
| } |
| |
| return true; |
| } catch (error) { |
| console.error('\n❌ 生成配置文件时出错:', error.message); |
| return false; |
| } |
| } |
|
|
| |
| async function main() { |
| try { |
| const config = await collectConfig(); |
| |
| if (generateEnvFile(config)) { |
| console.log('\n===== 配置完成 ====='); |
| console.log('你可以使用以下命令启动服务:'); |
| console.log(' npm start'); |
| console.log('\n如需手动获取cookie执行:'); |
| console.log(' npm run refresh-cookies'); |
| |
| |
| console.log(`\n当前Cookie刷新模式为: ${config.cookieRefreshMode}`); |
| if (config.cookieRefreshMode === 'replace') { |
| console.log('每次刷新都会将现有cookie全部标记为无效并替换成新cookie'); |
| } else { |
| console.log('刷新时会保留现有cookie,仅追加新cookie'); |
| } |
| console.log('你可以在.env文件中修改COOKIE_REFRESH_MODE设置'); |
| } |
| } catch (error) { |
| console.error('\n❌ 配置过程中出错:', error.message); |
| } finally { |
| rl.close(); |
| } |
| } |
|
|
| |
| main(); |