/**
 * 直接解码脚本 - 使用 RC4 + 非标准 Base64 算法
 * 不依赖沙盒执行，直接实现解码逻辑
 */
const fs = require('fs');
const path = require('path');

const baseDir = 'D:/temp/破解/cursorpro-0.4.5';

// 非标准 Base64 字母表 (小写在前)
const BASE64_CHARS = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';

/**
 * 非标准 Base64 解码
 */
function base64Decode(str) {
    let result = '';
    let buffer = 0;
    let bufferLen = 0;

    for (let i = 0; i < str.length; i++) {
        const char = str[i];
        const charIndex = BASE64_CHARS.indexOf(char);
        if (charIndex === -1) continue;
        if (charIndex === 64) continue; // '=' padding

        buffer = (buffer << 6) | charIndex;
        bufferLen += 6;

        if (bufferLen >= 8) {
            bufferLen -= 8;
            result += String.fromCharCode((buffer >> bufferLen) & 0xFF);
        }
    }

    return result;
}

/**
 * RC4 解密
 */
function rc4Decrypt(data, key) {
    // 初始化 S-box
    const s = [];
    for (let i = 0; i < 256; i++) {
        s[i] = i;
    }

    let j = 0;
    for (let i = 0; i < 256; i++) {
        j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;
        [s[i], s[j]] = [s[j], s[i]];
    }

    // 加密/解密
    let result = '';
    let i = 0;
    j = 0;

    for (let k = 0; k < data.length; k++) {
        i = (i + 1) % 256;
        j = (j + s[i]) % 256;
        [s[i], s[j]] = [s[j], s[i]];
        result += String.fromCharCode(data.charCodeAt(k) ^ s[(s[i] + s[j]) % 256]);
    }

    return result;
}

/**
 * 解码单个字符串
 */
function decodeString(encodedStr, key) {
    try {
        const base64Decoded = base64Decode(encodedStr);
        const decrypted = rc4Decrypt(base64Decoded, key);
        return decrypted;
    } catch (e) {
        return null;
    }
}

/**
 * 提取字符串数组
 */
function extractStringArray(code) {
    // 查找字符串数组 - 这是一个大的嵌套数组
    const arrayMatch = code.match(/return\s*\[([^\]]*(?:\]\.concat\(function\s*\(\)\s*\{\s*return\s*\[[^\]]*\][^\}]*\}\(\)\))*[^\]]*)\]/s);
    if (!arrayMatch) return null;

    // 提取所有字符串
    const strMatch = code.match(/return\s*\['([^']*)'(?:,'([^']*)')*\]/g);
    if (!strMatch) return null;

    const strings = [];
    const allStrings = code.match(/'[^']*'/g) || [];

    // 找到字符串数组的开始位置
    const arrayStart = code.indexOf("const _0x") || code.indexOf("function _0x");
    const arrayEnd = code.indexOf("Object.defineProperty(exports");

    if (arrayStart !== -1 && arrayEnd !== -1) {
        const arraySection = code.substring(arrayStart, arrayEnd);
        // 提取这个区域内所有带引号的字符串
        const stringMatches = arraySection.match(/'([^'\\]*(\\.[^'\\]*)*)'/g) || [];

        for (const match of stringMatches) {
            const str = match.slice(1, -1); // 移除引号
            if (str.length > 3 && /^[a-zA-Z0-9+/=]+$/.test(str)) {
                strings.push(str);
            }
        }
    }

    console.log(`  提取了 ${strings.length} 个候选编码字符串`);
    return strings;
}

/**
 * 为文件生成解码映射
 */
function generateDecodeMapForFile(code, filename) {
    console.log(`\n处理: ${filename}`);
    console.log('='.repeat(50));

    // 找到所有解码函数调用
    const callPattern = /(_0x[a-f0-9]+)\s*\(\s*(0x[a-f0-9]+)\s*,\s*'([^']*)'\s*\)/g;
    const calls = new Map();
    let match;

    while ((match = callPattern.exec(code)) !== null) {
        const fullMatch = match[0];
        const funcName = match[1];
        const numHex = match[2];
        const key = match[3];

        calls.set(fullMatch, { funcName, numHex, key, num: parseInt(numHex, 16) });
    }

    console.log(`  找到 ${calls.size} 个唯一调用`);

    // 提取字符串数组
    // 找到类似这样的模式：
    // return [vip, 'encodedStr1', 'encodedStr2', ...]
    const stringArrayMatch = code.match(/return\s*\[\s*vip\s*,\s*('[^']*'(?:\s*,\s*'[^']*')*)\s*\]/);
    let stringArray = ['cursor']; // vip = 'cursor'

    if (stringArrayMatch) {
        const stringsSection = stringArrayMatch[1];
        const strings = stringsSection.match(/'([^']*)'/g);
        if (strings) {
            for (const s of strings) {
                stringArray.push(s.slice(1, -1));
            }
        }
        console.log(`  提取了 ${stringArray.length} 个数组元素`);
    } else {
        // 尝试另一种模式 - concat 嵌套数组
        const concatPattern = /return\s*\[([^\]]*)\]\.concat/g;
        const allArrays = [];
        let cm;
        while ((cm = concatPattern.exec(code)) !== null) {
            const content = cm[1];
            const strings = content.match(/'([^']*)'/g);
            if (strings) {
                for (const s of strings) {
                    allArrays.push(s.slice(1, -1));
                }
            }
        }
        if (allArrays.length > 0) {
            stringArray = ['cursor', ...allArrays];
            console.log(`  通过 concat 提取了 ${stringArray.length} 个数组元素`);
        }
    }

    // 如果无法提取数组，返回空
    if (stringArray.length < 10) {
        console.log('  无法提取足够的字符串数组');
        return null;
    }

    // 尝试解码
    const decodeMap = {};
    let successCount = 0;

    for (const [fullMatch, info] of calls) {
        const { num, key } = info;

        // 计算实际索引（减去偏移量）
        // 不同文件的偏移量不同，需要尝试
        for (let offset = 0; offset <= 0x200; offset += 0x10) {
            const adjustedIndex = num - offset;
            if (adjustedIndex >= 0 && adjustedIndex < stringArray.length) {
                const encodedStr = stringArray[adjustedIndex];
                const decoded = decodeString(encodedStr, key);
                if (decoded && decoded.length > 0 && /^[\x20-\x7E\u4e00-\u9fff]+$/.test(decoded)) {
                    decodeMap[fullMatch] = decoded;
                    successCount++;
                    break;
                }
            }
        }
    }

    console.log(`  成功解码: ${successCount}/${calls.size}`);

    return decodeMap;
}

/**
 * 使用已有的解码器脚本为每个文件生成映射
 */
async function generateWithExistingDecoder(inputPath, outputPath, filename) {
    console.log(`\n处理: ${filename}`);
    console.log('='.repeat(50));

    if (fs.existsSync(outputPath)) {
        const existing = JSON.parse(fs.readFileSync(outputPath, 'utf8'));
        console.log(`  已存在: ${Object.keys(existing).length} 条映射`);
        return existing;
    }

    // 读取代码
    const code = fs.readFileSync(inputPath, 'utf8');

    // 查找解码器函数名
    const decoderMatch = code.match(/function\s+(_0x[a-f0-9]+)\s*\(\s*_0x[a-f0-9]+\s*,\s*_0x[a-f0-9]+\s*\)\s*\{/);
    if (!decoderMatch) {
        console.log('  未找到解码函数');
        return null;
    }
    const decoderFuncName = decoderMatch[1];
    console.log(`  解码函数: ${decoderFuncName}`);

    // 收集所有调用
    const callPattern = new RegExp(
        `(_0x[a-f0-9]+)\\s*\\(\\s*(0x[a-f0-9]+)\\s*,\\s*'([^']*)'\\s*\\)`,
        'g'
    );

    const calls = new Set();
    let match;
    while ((match = callPattern.exec(code)) !== null) {
        calls.add(match[0]);
    }

    console.log(`  找到 ${calls.size} 个调用`);

    // 对于没有映射的文件，我们需要用不同的方法
    // 使用之前成功的解码器代码片段

    return { size: calls.size, decoder: decoderFuncName };
}

// 主函数
async function main() {
    console.log('╔════════════════════════════════════════════════════╗');
    console.log('║           直接解码映射生成器                         ║');
    console.log('║         使用 RC4 + 非标准 Base64                    ║');
    console.log('╚════════════════════════════════════════════════════╝');

    const files = [
        { input: '原版本/extension/out/utils/account.js', output: 'account_decoded_map.json' },
        { input: '原版本/extension/out/utils/sqlite.js', output: 'sqlite_decoded_map.json' },
        { input: '原版本/extension/out/api/client.js', output: 'client_decoded_map.json' }
    ];

    for (const file of files) {
        const inputPath = path.join(baseDir, file.input);
        const outputPath = path.join(baseDir, file.output);

        if (!fs.existsSync(inputPath)) {
            console.log(`\n跳过: ${file.input} (不存在)`);
            continue;
        }

        const code = fs.readFileSync(inputPath, 'utf8');
        const decodeMap = generateDecodeMapForFile(code, file.input);

        if (decodeMap && Object.keys(decodeMap).length > 0) {
            fs.writeFileSync(outputPath, JSON.stringify(decodeMap, null, 2));
            console.log(`  已保存: ${outputPath}`);
        }
    }

    console.log('\n完成！');
}

main().catch(console.error);
