Spaces:
Sleeping
Sleeping
File size: 7,831 Bytes
1e3f1ee e7ba391 ecc3587 e7ba391 1e3f1ee e7ba391 1e3f1ee e7ba391 171abdd e7ba391 171abdd e7ba391 53da9ca 989adf8 bb8b08c 989adf8 bb8b08c f8b7647 7bc4d06 db1caa1 e7ba391 989adf8 e7ba391 766be0f db1caa1 e7ba391 48f38e0 1ce2ae6 f8b7647 48f38e0 e7ba391 edd6767 e7ba391 48f38e0 e7ba391 7bc4d06 e7ba391 989adf8 1ce2ae6 f8b7647 1ce2ae6 f8b7647 db1caa1 edd6767 db1caa1 bb8b08c db1caa1 bb8b08c f8b7647 db1caa1 f8b7647 db1caa1 0a16ed6 989adf8 db1caa1 0a16ed6 db1caa1 e7ba391 db1caa1 766be0f e7ba391 989adf8 766be0f e7ba391 1e3f1ee 989adf8 db1caa1 | 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 | const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const { execSync } = require('child_process');
const path = require('path');
const fs = require('fs');
const archiver = require('archiver');
const app = express();
app.use(bodyParser.json({ limit: '100mb' }));
const DUMMY_ZIP = 'dummy_lite.zepeto.zip';
if (!fs.existsSync('uploads')) fs.mkdirSync('uploads', { recursive: true });
function getTS() { return new Date().toLocaleTimeString(); }
function findPath(base, targetName, isFolder = false) {
if (!fs.existsSync(base)) return null;
const items = fs.readdirSync(base);
for (const item of items) {
const fullPath = path.join(base, item);
const stat = fs.lstatSync(fullPath);
if (isFolder && stat.isDirectory() && item.toLowerCase() === targetName.toLowerCase()) return fullPath;
if (!isFolder && stat.isFile() && item.toLowerCase().endsWith(targetName.toLowerCase())) return fullPath;
if (stat.isDirectory()) {
const found = findPath(fullPath, targetName, isFolder);
if (found) return found;
}
}
return null;
}
function createZepetoFile(sourceDir, outPath) {
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(outPath);
const archive = archiver('zip', { zlib: { level: 6 } });
output.on('close', resolve);
archive.on('error', reject);
archive.pipe(output);
archive.directory(sourceDir, false);
archive.finalize();
});
}
app.post('/convert', async (req, res) => {
const logs = [];
const logMsg = (msg) => {
const line = `[${getTS()}] ${msg}`;
console.log(line);
logs.push(line);
};
const targetFilename = req.body.filename || 'result.zepeto';
logMsg(`Mulai Konversi (Ultimate Sync Mode): ${targetFilename}`);
const timeId = Date.now();
const tempHP = path.join(__dirname, 'uploads', `hp_${timeId}.zepeto`);
const extDummy = path.join(__dirname, 'uploads', `ext_dummy_${timeId}`);
const extHP = path.join(__dirname, 'uploads', `ext_hp_${timeId}`);
const stagePath = path.join(__dirname, 'uploads', `stage_${timeId}`);
const finalOut = path.join(__dirname, 'uploads', `final_${timeId}.zepeto`);
try {
logMsg(`[STEP 1] Mendownload file High Poly...`);
const response = await axios({ method: 'GET', url: req.body.file_url, responseType: 'stream' });
const writer = fs.createWriteStream(tempHP);
response.data.pipe(writer);
writer.on('finish', async () => {
try {
logMsg(`[STEP 2] Ekstraksi Dummy dan High Poly...`);
fs.mkdirSync(extDummy, { recursive: true });
fs.mkdirSync(extHP, { recursive: true });
fs.mkdirSync(stagePath, { recursive: true });
execSync(`unzip -q -o "${DUMMY_ZIP}" -d "${extDummy}"`);
execSync(`unzip -q -o "${tempHP}" -d "${extHP}"`);
logMsg(`[STEP 3] Analisis Struktur & Penyelarasan GUID Mutlak...`);
// 1. Ekstrak GUID dari Meta Dummy (KTP Target)
const dummyMetaPath = findPath(extDummy, '.prefab.meta', false);
if (!dummyMetaPath) throw new Error("File .meta Dummy tidak ditemukan!");
const dummyPrefabName = path.basename(dummyMetaPath, '.meta');
const dummyMetaContent = fs.readFileSync(dummyMetaPath, 'utf8');
const dummyGuidMatch = dummyMetaContent.match(/guid:\s*([a-f0-9]+)/);
if (!dummyGuidMatch) throw new Error("Gagal membaca GUID dari Dummy!");
const dummyGuid = dummyGuidMatch[1];
// 2. Ekstrak GUID dari Meta Raksasa (KTP Asli Raksasa)
const hpMetaPath = findPath(extHP, '.prefab.meta', false);
if (!hpMetaPath) throw new Error("File .meta Raksasa tidak ditemukan!");
const hpMetaContent = fs.readFileSync(hpMetaPath, 'utf8');
const hpGuidMatch = hpMetaContent.match(/guid:\s*([a-f0-9]+)/);
if (!hpGuidMatch) throw new Error("Gagal membaca GUID dari Raksasa!");
const hpGuid = hpGuidMatch[1];
const stageBundles = path.join(stagePath, 'assetbundles');
fs.mkdirSync(stageBundles, { recursive: true });
// 3. Pasang KTP Dummy (.meta) ke Stage Root
fs.copyFileSync(dummyMetaPath, path.join(stagePath, dummyPrefabName + '.meta'));
logMsg(`KTP Dummy diamankan. GUID: ${dummyGuid}`);
// 4. Eksekusi Pencucian Otak: Timpa GUID di dalam Kertas Blueprint Raksasa
const hpPrefabPath = findPath(extHP, '.prefab', false);
let prefabContent = fs.readFileSync(hpPrefabPath, 'utf8');
// Operasi Mutlak: Ganti GUID Raksasa di dalam m_RenderDataKey menjadi GUID Dummy
prefabContent = prefabContent.split(hpGuid).join(dummyGuid);
fs.writeFileSync(path.join(stagePath, dummyPrefabName), prefabContent);
logMsg(`Pencucian otak Blueprint sukses! Mengganti ${hpGuid} -> ${dummyGuid}`);
// 5. Eksekusi Python untuk mencuci identitas CAB Biner
const hpBundleDir = findPath(extHP, 'assetbundles', true);
const dummyBundleDir = findPath(extDummy, 'assetbundles', true);
if (!hpBundleDir || !dummyBundleDir) throw new Error("Folder assetbundles tidak ditemukan!");
logMsg(`[STEP 4] Memanggil Python untuk Surgical Patching CAB...`);
try {
const pyLog = execSync(`python3 uabe_packer.py "${dummyBundleDir}" "${hpBundleDir}" "${stageBundles}"`).toString();
pyLog.split('\n').forEach(line => { if(line.trim()) logMsg(`[PY] ${line}`); });
if (!pyLog.includes('Injeksi selesai 100%')) throw new Error("Python gagal melakukan patching.");
logMsg(`[STEP 5] Repacking ZIP (Flat Root Strategy)...`);
const output = fs.createWriteStream(finalOut);
const archive = archiver('zip', { zlib: { level: 6 } });
output.on('close', () => {
logMsg(`[FINISH] Bypass Sempurna. Ukuran: ${fs.statSync(finalOut).size} bytes.`);
res.download(finalOut, targetFilename, () => {
try {
fs.rmSync(extDummy, { recursive: true, force: true });
fs.rmSync(extHP, { recursive: true, force: true });
fs.rmSync(stagePath, { recursive: true, force: true });
fs.unlinkSync(tempHP);
fs.unlinkSync(finalOut);
} catch (e) {}
});
});
archive.pipe(output);
archive.directory(stagePath, false);
archive.finalize();
} catch (pyErr) {
logMsg(`[CRASH] Kesalahan Python: ${pyErr.message}`);
res.status(500).json({ error: pyErr.message, logs });
}
} catch (err) {
logMsg(`[ERROR] ${err.message}`);
res.status(500).json({ error: err.message, logs });
}
});
} catch (err) {
logMsg(`[ERROR] Download gagal: ${err.message}`);
res.status(500).json({ error: err.message, logs });
}
});
const PORT = 7860;
app.listen(PORT, () => console.log(`[${getTS()}] 🚀 Server Ultimate Sync Bypass Aktif di Port ${PORT}`)); |