diff --git a/app/assets/js/javaguard.js b/app/assets/js/javaguard.js index cf30ab28..89c08bfa 100644 --- a/app/assets/js/javaguard.js +++ b/app/assets/js/javaguard.js @@ -1,274 +1,315 @@ const cp = require('child_process') +const EventEmitter = require('events') const fs = require('fs') const path = require('path') const Registry = require('winreg') const request = require('request') -/** - * Attempts to find a valid x64 installation of Java on Windows machines. - * Possible paths will be pulled from the registry and the JAVA_HOME environment - * variable. The paths will be sorted with higher versions preceeding lower, and - * JREs preceeding JDKs. The binaries at the sorted paths will then be validated. - * The first validated is returned. - * - * Higher versions > Lower versions - * If versions are equal, JRE > JDK. - * - * @returns {string} The root path of a valid x64 Java installation. If none are - * found, null is returned. - */ -async function _win32Validate(){ - - // Get possible paths from the registry. - const pathSet = await _scanRegistry() - - console.log(Array.from(pathSet)) // DEBUGGING - - // Validate JAVA_HOME - const jHome = _scanJavaHome() - if(jHome != null && jHome.indexOf('(x86)') === -1){ - pathSet.add(jHome) - } - - // Convert path set to an array for processing. - let pathArr = Array.from(pathSet) - - console.log(pathArr) // DEBUGGING - - // Sorts array. Higher version numbers preceed lower. JRE preceeds JDK. - pathArr = pathArr.sort((a, b) => { - // Note that Java 9+ uses semver and that will need to be accounted for in - // the future. - const aVer = parseInt(a.split('_')[1]) - const bVer = parseInt(b.split('_')[1]) - if(bVer === aVer){ - return a.indexOf('jdk') > -1 ? 1 : 0 - } else { - return bVer - aVer - } - }) - - console.log(pathArr) // DEBUGGING - - // Validate that the binary is actually x64. - for(let i=0; i} Resolves to false only if the test is successful and the result - * is less than 64. - */ -function _validateBinary(binaryPath){ - - return new Promise((resolve, reject) => { - const fBp = path.join(binaryPath, 'bin', 'java.exe') - if(fs.existsSync(fBp)){ - cp.exec('"' + fBp + '" -XshowSettings:properties', (err, stdout, stderr) => { - - try { - // Output is stored in stderr? - const res = stderr - const props = res.split('\n') - for(let i=0; i -1){ - let arch = props[i].split('=')[1].trim() - console.log(props[i].trim() + ' for ' + binaryPath) - resolve(parseInt(arch) >= 64) - } - } - - // sun.arch.data.model not found? - // Disregard this test. - resolve(true) - - } catch (err){ - - // Output format might have changed, validation cannot be completed. - // Disregard this test in that case. - resolve(true) - } - }) - } else { - resolve(false) - } - }) - -} - -/** - * Checks for the presence of the environment variable JAVA_HOME. If it exits, we will check - * to see if the value points to a path which exists. If the path exits, the path is returned. - * - * @returns {string} The path defined by JAVA_HOME, if it exists. Otherwise null. - */ -function _scanJavaHome(){ - const jHome = process.env.JAVA_HOME - try { - let res = fs.existsSync(jHome) - return res ? jHome : null - } catch (err) { - // Malformed JAVA_HOME property. - return null - } -} - -/** - * Scans the registry for 64-bit Java entries. The paths of each entry are added to - * a set and returned. Currently, only Java 8 (1.8) is supported. - * - * @returns {Promise.>} A promise which resolves to a set of 64-bit Java root - * paths found in the registry. - */ -function _scanRegistry(){ - - return new Promise((resolve, reject) => { - // Keys for Java v9.0.0 and later: - // 'SOFTWARE\\JavaSoft\\JRE' - // 'SOFTWARE\\JavaSoft\\JDK' - // Forge does not yet support Java 9, therefore we do not. - - let cbTracker = 0 - let cbAcc = 0 - - // Keys for Java 1.8 and prior: - const regKeys = [ - '\\SOFTWARE\\JavaSoft\\Java Runtime Environment', - '\\SOFTWARE\\JavaSoft\\Java Development Kit' - ] - - const candidates = new Set() - - for(let i=0; i { - if(err){ - console.error(err) - if(i === regKeys.length-1){ - resolve(candidates) - } - } else { - cbTracker += javaVers.length - if(i === regKeys.length-1 && cbTracker === cbAcc){ - resolve(candidates) - } - for(let j=0; j { - const jHome = res.value - if(jHome.indexOf('(x86)') === -1){ - candidates.add(jHome) - cbAcc++ - } - if(cbAcc === cbTracker){ - resolve(candidates) - } - }) - } - } - } - }) - } - - }) - -} - -/** - * WIP -> get a valid x64 Java path on macOS. - */ -function _darwinValidate(){ - return null -} - -/** - * WIP -> get a valid x64 Java path on linux. - */ -function _linuxValidate(){ - return null -} - -// This will eventually return something. -async function validate(){ - - let res = null - - const opSys = process.platform - if(opSys === 'win32'){ - res = await _win32Validate() - } else if(opSys === 'darwin'){ - res = _darwinValidate() - } else if(opSys === 'linux'){ - res = _linuxValidate() - } - - return res; - -} - const PLATFORM_MAP = { win32: '-windows-x64.tar.gz', darwin: '-macosx-x64.tar.gz', linux: '-linux-x64.tar.gz' } -const BASE_URL = 'http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jre-8u161' +class JavaGuard extends EventEmitter { -function _downloadJava(acceptLicense, dir){ - if(!acceptLicense){ - return + /** + * Validates that a Java binary is at least 64 bit. This makes use of the non-standard + * command line option -XshowSettings:properties. The output of this contains a property, + * sun.arch.data.model = ARCH, in which ARCH is either 32 or 64. This option is supported + * in Java 8 and 9. Since this is a non-standard option. This will resolve to true if + * the function's code throws errors. That would indicate that the option is changed or + * removed. + * + * @param {string} binaryPath Path to the root of the java binary we wish to validate. + * + * @returns {Promise.} Resolves to false only if the test is successful and the result + * is less than 64. + */ + static _validateBinary(binaryPath){ + + return new Promise((resolve, reject) => { + const fBp = path.join(binaryPath, 'bin', 'java.exe') + if(fs.existsSync(fBp)){ + cp.exec('"' + fBp + '" -XshowSettings:properties', (err, stdout, stderr) => { + + try { + // Output is stored in stderr? + const res = stderr + const props = res.split('\n') + for(let i=0; i -1){ + let arch = props[i].split('=')[1].trim() + console.log(props[i].trim() + ' for ' + binaryPath) + resolve(parseInt(arch) >= 64) + } + } + + // sun.arch.data.model not found? + // Disregard this test. + resolve(true) + + } catch (err){ + + // Output format might have changed, validation cannot be completed. + // Disregard this test in that case. + resolve(true) + } + }) + } else { + resolve(false) + } + }) + } - // TODO -> Complete this code. See format used in assetguard.js#510 - - const combined = BASE_URL + PLATFORM_MAP[process.platform] - const name = combined.substring(combined.lastIndexOf('/')+1) - const fDir = path.join(dir, name) - - const opts = { - url: combined, - headers: { - 'Cookie': 'oraclelicense=accept-securebackup-cookie' + /** + * Checks for the presence of the environment variable JAVA_HOME. If it exits, we will check + * to see if the value points to a path which exists. If the path exits, the path is returned. + * + * @returns {string} The path defined by JAVA_HOME, if it exists. Otherwise null. + */ + static _scanJavaHome(){ + const jHome = process.env.JAVA_HOME + try { + let res = fs.existsSync(jHome) + return res ? jHome : null + } catch (err) { + // Malformed JAVA_HOME property. + return null } } - const req = request(opts) - let writeStream = fs.createWriteStream(fDir) - req.pipe(writeStream) - req.resume() + /** + * Scans the registry for 64-bit Java entries. The paths of each entry are added to + * a set and returned. Currently, only Java 8 (1.8) is supported. + * + * @returns {Promise.>} A promise which resolves to a set of 64-bit Java root + * paths found in the registry. + */ + static _scanRegistry(){ + + return new Promise((resolve, reject) => { + // Keys for Java v9.0.0 and later: + // 'SOFTWARE\\JavaSoft\\JRE' + // 'SOFTWARE\\JavaSoft\\JDK' + // Forge does not yet support Java 9, therefore we do not. + + let cbTracker = 0 + let cbAcc = 0 + + // Keys for Java 1.8 and prior: + const regKeys = [ + '\\SOFTWARE\\JavaSoft\\Java Runtime Environment', + '\\SOFTWARE\\JavaSoft\\Java Development Kit' + ] + + const candidates = new Set() + + for(let i=0; i { + if(exists) { + key.keys((err, javaVers) => { + if(err){ + console.error(err) + if(i === regKeys.length-1 && cbAcc === cbTracker){ + resolve(candidates) + } + } else { + cbTracker += javaVers.length + if(i === regKeys.length-1 && cbTracker === cbAcc){ + resolve(candidates) + } else { + for(let j=0; j { + const jHome = res.value + if(jHome.indexOf('(x86)') === -1){ + candidates.add(jHome) + + } + cbAcc++ + if(i === regKeys.length-1 && cbAcc === cbTracker){ + resolve(candidates) + } + }) + } else { + cbAcc++ + if(i === regKeys.length-1 && cbAcc === cbTracker){ + resolve(candidates) + } + } + } + } + } + }) + } else { + if(i === regKeys.length-1 && cbAcc === cbTracker){ + resolve(candidates) + } + } + }) + } + + }) + + } + + /** + * Attempts to find a valid x64 installation of Java on Windows machines. + * Possible paths will be pulled from the registry and the JAVA_HOME environment + * variable. The paths will be sorted with higher versions preceeding lower, and + * JREs preceeding JDKs. The binaries at the sorted paths will then be validated. + * The first validated is returned. + * + * Higher versions > Lower versions + * If versions are equal, JRE > JDK. + * + * @returns {string} The root path of a valid x64 Java installation. If none are + * found, null is returned. + */ + static async _win32Validate(){ + + // Get possible paths from the registry. + const pathSet = await JavaGuard._scanRegistry() + + console.log(Array.from(pathSet)) // DEBUGGING + + // Validate JAVA_HOME + const jHome = JavaGuard._scanJavaHome() + if(jHome != null && jHome.indexOf('(x86)') === -1){ + pathSet.add(jHome) + } + + // Convert path set to an array for processing. + let pathArr = Array.from(pathSet) + + console.log(pathArr) // DEBUGGING + + // Sorts array. Higher version numbers preceed lower. JRE preceeds JDK. + pathArr = pathArr.sort((a, b) => { + // Note that Java 9+ uses semver and that will need to be accounted for in + // the future. + const aVer = parseInt(a.split('_')[1]) + const bVer = parseInt(b.split('_')[1]) + if(bVer === aVer){ + return a.indexOf('jdk') > -1 ? 1 : 0 + } else { + return bVer - aVer + } + }) + + console.log(pathArr) // DEBUGGING + + // Validate that the binary is actually x64. + for(let i=0; i get a valid x64 Java path on macOS. + */ + static async _darwinValidate(){ + return null + } + + /** + * WIP -> get a valid x64 Java path on linux. + */ + static async _linuxValidate(){ + return null + } + + static async validate(){ + return await JavaGuard['_' + process.platform + 'Validate']() + } + + // WIP -> Downloading Suite + + static _latestJREOracle(){ + + const url = 'http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html' + const regex = /http:\/\/.+?(?=\/java)\/java\/jdk\/([0-9]+u[0-9]+)-(b[0-9]+)\/([a-f0-9]{32})?\/jre-\1/ + + return new Promise((resolve, reject) => { + request(url, (err, resp, body) => { + if(!err){ + const arr = body.match(regex) + const verSplit = arr[1].split('u') + resolve({ + uri: arr[0], + version: { + major: verSplit[0], + update: verSplit[1], + build: arr[2] + } + }) + } else { + resolve(null) + } + }) + }) + } + + async _downloadOracleJRE(acceptLicense, dir){ + + if(!acceptLicense){ + return + } + + // TODO -> Complete this code. See format used in assetguard.js#510 + + const latestData = await JavaGuard._latestJREOracle() + + const combined = latestData.uri + PLATFORM_MAP[process.platform] + const name = combined.substring(combined.lastIndexOf('/')+1) + const fDir = path.join(dir, name) + + const opts = { + url: combined, + headers: { + 'Cookie': 'oraclelicense=accept-securebackup-cookie' + } + } + + const req = request(opts) + let writeStream = fs.createWriteStream(fDir) + req.pipe(writeStream) + req.resume() + + } + + _downloadJava(dir){ + this._downloadOracleJRE(true, dir) + } + } async function test(){ - console.log(await validate()) + //console.log(await JavaGuard.validate()) + const g = new JavaGuard() + g._downloadJava('C:\\Users\\Asus\\Desktop\\LauncherElectron\\target\\') + //console.log(JSON.stringify(await _latestJREOracle())) } -//test() -_downloadJava(true, 'C:\\Users\\Asus\\Desktop\\LauncherElectron\\target\\') +test() module.exports = { - validate + JavaGuard } \ No newline at end of file diff --git a/app/assets/westeroscraft.json b/app/assets/westeroscraft.json index 4dc353c4..a9668516 100644 --- a/app/assets/westeroscraft.json +++ b/app/assets/westeroscraft.json @@ -5,6 +5,9 @@ "smallImageText": "WesterosCraft", "smallImageKey": "seal-circle" }, + "java": { + "oracle": "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html" + }, "servers": [ { "id": "WesterosCraft-1.11.2",