/** * Localhost/Local Development Code Backup * * This file contains code removed from clientPatcher.js that was used for local development. * To re-enable local dev mode, merge this code back into clientPatcher.js. * * Backed up: 2026-01-28 */ // ============================================================================= // LOCAL PATCHER PATHS (was in ensurePatcherDownloaded method) // ============================================================================= // Check for local patcher (for local development) const localPatcherPaths = [ path.join(__dirname, '..', '..', '..', 'hytale-auth-server', 'patcher', 'DualAuthPatcher.java'), path.join(__dirname, '..', '..', '..', '..', 'hytale-auth-server', 'patcher', 'DualAuthPatcher.java'), '/Users/sanasol/code/pterodactyl-hytale/hytale-auth-server/patcher/DualAuthPatcher.java' ]; // Check if we should use local patcher (localhost domain = local dev) const domain = getTargetDomain(); const isLocalDev = domain.startsWith('localhost') || domain.startsWith('127.0.0.1'); if (isLocalDev) { for (const localPath of localPatcherPaths) { if (fs.existsSync(localPath)) { console.log(`Using local DualAuthPatcher: ${localPath}`); // Always copy fresh for local dev to pick up changes fs.copyFileSync(localPath, patcherJava); // Delete compiled class to force recompile const patcherClass = path.join(patcherDir, 'DualAuthPatcher.class'); if (fs.existsSync(patcherClass)) { fs.unlinkSync(patcherClass); } return; } } console.log('Local patcher not found, falling back to download...'); } // ============================================================================= // LEGACY SERVER PATCHER (was patchServerLegacy method) // ============================================================================= /** * Legacy server patcher (simple domain replacement, no dual auth) * Use patchServer() for full dual auth support */ async patchServerLegacy(serverPath, progressCallback) { const newDomain = this.getNewDomain(); const strategy = this.getDomainStrategy(newDomain); console.log('=== Legacy Server Patcher ==='); console.log(`Target: ${serverPath}`); console.log(`Domain: ${newDomain} (${newDomain.length} chars)`); if (!fs.existsSync(serverPath)) { return { success: false, error: `Server JAR not found: ${serverPath}` }; } if (progressCallback) progressCallback('Patching server...', 20); console.log('Opening server JAR...'); const zip = new AdmZip(serverPath); const entries = zip.getEntries(); let totalCount = 0; const oldUtf8 = this.stringToUtf8(ORIGINAL_DOMAIN); for (const entry of entries) { const name = entry.entryName; if (name.endsWith('.class') || name.endsWith('.properties') || name.endsWith('.json') || name.endsWith('.xml') || name.endsWith('.yml')) { const data = entry.getData(); if (data.includes(oldUtf8)) { const { buffer: patchedData, count } = this.findAndReplaceDomainUtf8(data, ORIGINAL_DOMAIN, strategy.mainDomain); if (count > 0) { zip.updateFile(entry.entryName, patchedData); totalCount += count; } } } } if (totalCount > 0) { zip.writeZip(serverPath); } if (progressCallback) progressCallback('Complete', 100); return { success: true, patchCount: totalCount }; } // ============================================================================= // DUALAUTHPATCHER FLOW FOR NON-STANDARD DOMAINS (was in patchServer method) // ============================================================================= // For non-standard domains, use DualAuthPatcher for proper bytecode patching const isStandardDomain = newDomain === 'auth.sanasol.ws' || newDomain === 'sanasol.ws'; if (!isStandardDomain) { console.log(`Non-standard domain "${newDomain}" - using DualAuthPatcher`); // Find Java const java = this.findJava(); if (!java) { console.error('Java not found - cannot run DualAuthPatcher'); console.error('Please install Java or use the bundled JRE'); return { success: false, error: 'Java not found for DualAuthPatcher' }; } console.log(` Using Java: ${java}`); // Setup patcher directory const patcherDir = path.join(path.dirname(serverPath), '.patcher'); const libDir = path.join(patcherDir, 'lib'); try { // Download patcher and libraries if (progressCallback) progressCallback('Downloading DualAuthPatcher...', 20); await this.ensurePatcherDownloaded(patcherDir); if (progressCallback) progressCallback('Downloading ASM libraries...', 30); await this.ensureAsmLibraries(libDir); // Compile patcher if (progressCallback) progressCallback('Compiling patcher...', 40); const compileResult = await this.compileDualAuthPatcher(java, patcherDir, libDir); if (!compileResult.success) { return { success: false, error: compileResult.error }; } // Build classpath const classpath = [ patcherDir, path.join(libDir, 'asm-9.6.jar'), path.join(libDir, 'asm-tree-9.6.jar'), path.join(libDir, 'asm-util-9.6.jar') ].join(process.platform === 'win32' ? ';' : ':'); // Run DualAuthPatcher with custom domain if (progressCallback) progressCallback('Running DualAuthPatcher...', 60); console.log(` Running DualAuthPatcher with domain: ${newDomain}`); const patchResult = await this.runDualAuthPatcher(java, classpath, serverPath, newDomain); if (patchResult.success) { // Mark as patched fs.writeFileSync(patchFlagFile, JSON.stringify({ domain: newDomain, patchedAt: new Date().toISOString(), patcher: 'DualAuthPatcher', output: patchResult.stdout }, null, 2)); if (progressCallback) progressCallback('Server patching complete', 100); console.log('=== Server Patching Complete (DualAuthPatcher) ==='); return { success: true, patchCount: 1 }; } else { console.error('DualAuthPatcher failed:', patchResult.error); return { success: false, error: patchResult.error }; } } catch (err) { console.error('Failed to run DualAuthPatcher:', err.message); return { success: false, error: err.message }; } } // ============================================================================= // HELPER METHODS FOR DUALAUTHPATCHER (keep if re-enabling non-standard domains) // ============================================================================= /** * Find Java executable - uses bundled JRE first (same as game uses) * Falls back to system Java if bundled not available */ findJava() { // 1. Try bundled JRE first (comes with the game) try { const bundled = getBundledJavaPath(JRE_DIR); if (bundled && fs.existsSync(bundled)) { console.log(`Using bundled Java: ${bundled}`); return bundled; } } catch (e) { // Bundled not available } // 2. Try javaManager's getJavaExec (handles all fallbacks) try { const javaExec = getJavaExec(JRE_DIR); if (javaExec && fs.existsSync(javaExec)) { console.log(`Using Java from javaManager: ${javaExec}`); return javaExec; } } catch (e) { // Not available } // 3. Check JAVA_HOME if (process.env.JAVA_HOME) { const javaHome = process.env.JAVA_HOME; const javaBin = path.join(javaHome, 'bin', process.platform === 'win32' ? 'java.exe' : 'java'); if (fs.existsSync(javaBin)) { console.log(`Using Java from JAVA_HOME: ${javaBin}`); return javaBin; } } // 4. Try 'java' from PATH try { execSync('java -version 2>&1', { encoding: 'utf8' }); console.log('Using Java from PATH'); return 'java'; } catch (e) { // Not in PATH } return null; } /** * Get DualAuthPatcher - downloads from GitHub */ async ensurePatcherDownloaded(patcherDir) { const patcherJava = path.join(patcherDir, 'DualAuthPatcher.java'); const patcherUrl = 'https://raw.githubusercontent.com/sanasol/hytale-auth-server/master/patcher/DualAuthPatcher.java'; if (!fs.existsSync(patcherDir)) { fs.mkdirSync(patcherDir, { recursive: true }); } if (!fs.existsSync(patcherJava)) { console.log('Downloading DualAuthPatcher from hytale-auth-server...'); try { const https = require('https'); await new Promise((resolve, reject) => { const file = fs.createWriteStream(patcherJava); https.get(patcherUrl, (response) => { if (response.statusCode === 302 || response.statusCode === 301) { https.get(response.headers.location, (redirectResponse) => { redirectResponse.pipe(file); file.on('finish', () => { file.close(); resolve(); }); }).on('error', reject); } else { response.pipe(file); file.on('finish', () => { file.close(); resolve(); }); } }).on('error', (err) => { fs.unlink(patcherJava, () => {}); reject(err); }); }); console.log(' Downloaded DualAuthPatcher.java'); } catch (e) { console.error(` Failed to download DualAuthPatcher: ${e.message}`); throw e; } } } /** * Download ASM libraries if not present */ async ensureAsmLibraries(libDir) { if (!fs.existsSync(libDir)) { fs.mkdirSync(libDir, { recursive: true }); } const libs = [ { name: 'asm-9.6.jar', url: 'https://repo1.maven.org/maven2/org/ow2/asm/asm/9.6/asm-9.6.jar' }, { name: 'asm-tree-9.6.jar', url: 'https://repo1.maven.org/maven2/org/ow2/asm/asm-tree/9.6/asm-tree-9.6.jar' }, { name: 'asm-util-9.6.jar', url: 'https://repo1.maven.org/maven2/org/ow2/asm/asm-util/9.6/asm-util-9.6.jar' } ]; for (const lib of libs) { const libPath = path.join(libDir, lib.name); if (!fs.existsSync(libPath)) { console.log(`Downloading ${lib.name}...`); try { const https = require('https'); await new Promise((resolve, reject) => { const file = fs.createWriteStream(libPath); https.get(lib.url, (response) => { response.pipe(file); file.on('finish', () => { file.close(); resolve(); }); }).on('error', (err) => { fs.unlink(libPath, () => {}); reject(err); }); }); console.log(` Downloaded ${lib.name}`); } catch (e) { console.error(` Failed to download ${lib.name}: ${e.message}`); throw e; } } } } /** * Compile DualAuthPatcher if needed */ async compileDualAuthPatcher(java, patcherDir, libDir) { const patcherClass = path.join(patcherDir, 'DualAuthPatcher.class'); const patcherJava = path.join(patcherDir, 'DualAuthPatcher.java'); if (fs.existsSync(patcherClass)) { const classTime = fs.statSync(patcherClass).mtime; const javaTime = fs.statSync(patcherJava).mtime; if (classTime > javaTime) { console.log('DualAuthPatcher already compiled'); return { success: true }; } } console.log('Compiling DualAuthPatcher...'); const javac = java.replace(/java(\.exe)?$/, 'javac$1'); const classpath = [ path.join(libDir, 'asm-9.6.jar'), path.join(libDir, 'asm-tree-9.6.jar'), path.join(libDir, 'asm-util-9.6.jar') ].join(process.platform === 'win32' ? ';' : ':'); try { const execOptions = { stdio: 'pipe', cwd: patcherDir, env: { ...process.env } }; if (process.platform === 'win32') { const systemRoot = process.env.SystemRoot || 'C:\\WINDOWS'; const systemPath = `${systemRoot}\\system32;${systemRoot};${systemRoot}\\System32\\Wbem`; execOptions.env.PATH = execOptions.env.PATH ? `${systemPath};${execOptions.env.PATH}` : systemPath; execOptions.shell = true; } execSync(`"${javac}" -cp "${classpath}" -d "${patcherDir}" "${patcherJava}"`, execOptions); console.log(' Compilation successful'); return { success: true }; } catch (e) { const error = `Failed to compile DualAuthPatcher: ${e.message}`; console.error(error); if (e.stderr) console.error(e.stderr.toString()); return { success: false, error }; } } /** * Run DualAuthPatcher on the server JAR */ async runDualAuthPatcher(java, classpath, serverPath, domain) { return new Promise((resolve) => { const args = ['-cp', classpath, 'DualAuthPatcher', serverPath]; const env = { ...process.env, HYTALE_AUTH_DOMAIN: domain }; console.log(`Running: java ${args.join(' ')}`); console.log(` HYTALE_AUTH_DOMAIN=${domain}`); const proc = spawn(java, args, { env, stdio: ['pipe', 'pipe', 'pipe'] }); let stdout = ''; let stderr = ''; proc.stdout.on('data', (data) => { const str = data.toString(); stdout += str; console.log(str.trim()); }); proc.stderr.on('data', (data) => { const str = data.toString(); stderr += str; console.error(str.trim()); }); proc.on('close', (code) => { if (code === 0) { resolve({ success: true, stdout }); } else { resolve({ success: false, error: `Patcher exited with code ${code}: ${stderr}` }); } }); proc.on('error', (err) => { resolve({ success: false, error: `Failed to run patcher: ${err.message}` }); }); }); }