| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327 |
- 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')
- const PLATFORM_MAP = {
- win32: '-windows-x64.tar.gz',
- darwin: '-macosx-x64.tar.gz',
- linux: '-linux-x64.tar.gz'
- }
- class JavaGuard extends EventEmitter {
- /**
- * 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.<boolean>} 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<props.length; i++){
- if(props[i].indexOf('sun.arch.data.model') > -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.
- */
- 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
- }
- }
- /**
- * 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.<Set.<string>>} 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<regKeys.length; i++){
- const key = new Registry({
- hive: Registry.HKLM,
- key: regKeys[i],
- arch: 'x64'
- })
- key.keyExists((err, exists) => {
- 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<javaVers.length; j++){
- const javaVer = javaVers[j]
- const vKey = javaVer.key.substring(javaVer.key.lastIndexOf('\\')+1)
- // Only Java 8 is supported currently.
- if(parseFloat(vKey) === 1.8){
- javaVer.get('JavaHome', (err, res) => {
- 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<pathArr.length; i++) {
- let res = await JavaGuard._validateBinary(pathArr[i])
- if(res){
- return pathArr[i]
- }
- }
- // No suitable candidates found.
- return null;
- }
- /**
- * WIP -> 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)
- }
- })
- })
- }
- _headOracleJREDlSize(url){
- return new Promise((resolve, reject) => {
- request.head(url, (err, resp, body) => {
- if(err){
- reject(err)
- } else {
- resolve(resp.headers['content-length'])
- }
- })
- })
- }
- 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 JavaGuard.validate())
- const g = new JavaGuard()
- g._downloadJava('C:\\Users\\Asus\\Desktop\\LauncherElectron\\target\\')
- //console.log(JSON.stringify(await _latestJREOracle()))
- }
- test()
- module.exports = {
- JavaGuard
- }
|