javaguard.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. const cp = require('child_process')
  2. const fs = require('fs')
  3. const path = require('path')
  4. const Registry = require('winreg')
  5. const request = require('request')
  6. /**
  7. * Attempts to find a valid x64 installation of Java on Windows machines.
  8. * Possible paths will be pulled from the registry and the JAVA_HOME environment
  9. * variable. The paths will be sorted with higher versions preceeding lower, and
  10. * JREs preceeding JDKs. The binaries at the sorted paths will then be validated.
  11. * The first validated is returned.
  12. *
  13. * Higher versions > Lower versions
  14. * If versions are equal, JRE > JDK.
  15. *
  16. * @returns {string} The root path of a valid x64 Java installation. If none are
  17. * found, null is returned.
  18. */
  19. async function _win32Validate(){
  20. // Get possible paths from the registry.
  21. const pathSet = await _scanRegistry()
  22. console.log(Array.from(pathSet)) // DEBUGGING
  23. // Validate JAVA_HOME
  24. const jHome = _scanJavaHome()
  25. if(jHome != null && jHome.indexOf('(x86)') === -1){
  26. pathSet.add(jHome)
  27. }
  28. // Convert path set to an array for processing.
  29. let pathArr = Array.from(pathSet)
  30. console.log(pathArr) // DEBUGGING
  31. // Sorts array. Higher version numbers preceed lower. JRE preceeds JDK.
  32. pathArr = pathArr.sort((a, b) => {
  33. // Note that Java 9+ uses semver and that will need to be accounted for in
  34. // the future.
  35. const aVer = parseInt(a.split('_')[1])
  36. const bVer = parseInt(b.split('_')[1])
  37. if(bVer === aVer){
  38. return a.indexOf('jdk') > -1 ? 1 : 0
  39. } else {
  40. return bVer - aVer
  41. }
  42. })
  43. console.log(pathArr) // DEBUGGING
  44. // Validate that the binary is actually x64.
  45. for(let i=0; i<pathArr.length; i++) {
  46. let res = await _validateBinary(pathArr[i])
  47. if(res){
  48. return pathArr[i]
  49. }
  50. }
  51. // No suitable candidates found.
  52. return null;
  53. }
  54. /**
  55. * Validates that a Java binary is at least 64 bit. This makes use of the non-standard
  56. * command line option -XshowSettings:properties. The output of this contains a property,
  57. * sun.arch.data.model = ARCH, in which ARCH is either 32 or 64. This option is supported
  58. * in Java 8 and 9. Since this is a non-standard option. This will resolve to true if
  59. * the function's code throws errors. That would indicate that the option is changed or
  60. * removed.
  61. *
  62. * @param {string} binaryPath Path to the root of the java binary we wish to validate.
  63. *
  64. * @returns {Promise.<boolean>} Resolves to false only if the test is successful and the result
  65. * is less than 64.
  66. */
  67. function _validateBinary(binaryPath){
  68. return new Promise((resolve, reject) => {
  69. const fBp = path.join(binaryPath, 'bin', 'java.exe')
  70. if(fs.existsSync(fBp)){
  71. cp.exec('"' + fBp + '" -XshowSettings:properties', (err, stdout, stderr) => {
  72. try {
  73. // Output is stored in stderr?
  74. const res = stderr
  75. const props = res.split('\n')
  76. for(let i=0; i<props.length; i++){
  77. if(props[i].indexOf('sun.arch.data.model') > -1){
  78. let arch = props[i].split('=')[1].trim()
  79. console.log(props[i].trim() + ' for ' + binaryPath)
  80. resolve(parseInt(arch) >= 64)
  81. }
  82. }
  83. // sun.arch.data.model not found?
  84. // Disregard this test.
  85. resolve(true)
  86. } catch (err){
  87. // Output format might have changed, validation cannot be completed.
  88. // Disregard this test in that case.
  89. resolve(true)
  90. }
  91. })
  92. } else {
  93. resolve(false)
  94. }
  95. })
  96. }
  97. /**
  98. * Checks for the presence of the environment variable JAVA_HOME. If it exits, we will check
  99. * to see if the value points to a path which exists. If the path exits, the path is returned.
  100. *
  101. * @returns {string} The path defined by JAVA_HOME, if it exists. Otherwise null.
  102. */
  103. function _scanJavaHome(){
  104. const jHome = process.env.JAVA_HOME
  105. try {
  106. let res = fs.existsSync(jHome)
  107. return res ? jHome : null
  108. } catch (err) {
  109. // Malformed JAVA_HOME property.
  110. return null
  111. }
  112. }
  113. /**
  114. * Scans the registry for 64-bit Java entries. The paths of each entry are added to
  115. * a set and returned. Currently, only Java 8 (1.8) is supported.
  116. *
  117. * @returns {Promise.<Set.<string>>} A promise which resolves to a set of 64-bit Java root
  118. * paths found in the registry.
  119. */
  120. function _scanRegistry(){
  121. return new Promise((resolve, reject) => {
  122. // Keys for Java v9.0.0 and later:
  123. // 'SOFTWARE\\JavaSoft\\JRE'
  124. // 'SOFTWARE\\JavaSoft\\JDK'
  125. // Forge does not yet support Java 9, therefore we do not.
  126. let cbTracker = 0
  127. let cbAcc = 0
  128. // Keys for Java 1.8 and prior:
  129. const regKeys = [
  130. '\\SOFTWARE\\JavaSoft\\Java Runtime Environment',
  131. '\\SOFTWARE\\JavaSoft\\Java Development Kit'
  132. ]
  133. const candidates = new Set()
  134. for(let i=0; i<regKeys.length; i++){
  135. const key = new Registry({
  136. hive: Registry.HKLM,
  137. key: regKeys[i],
  138. arch: 'x64'
  139. })
  140. key.keys((err, javaVers) => {
  141. if(err){
  142. console.error(err)
  143. if(i === regKeys.length-1){
  144. resolve(candidates)
  145. }
  146. } else {
  147. cbTracker += javaVers.length
  148. if(i === regKeys.length-1 && cbTracker === cbAcc){
  149. resolve(candidates)
  150. }
  151. for(let j=0; j<javaVers.length; j++){
  152. const javaVer = javaVers[j]
  153. const vKey = javaVer.key.substring(javaVer.key.lastIndexOf('\\')+1)
  154. // Only Java 8 is supported currently.
  155. if(parseFloat(vKey) === 1.8){
  156. javaVer.get('JavaHome', (err, res) => {
  157. const jHome = res.value
  158. if(jHome.indexOf('(x86)') === -1){
  159. candidates.add(jHome)
  160. cbAcc++
  161. }
  162. if(cbAcc === cbTracker){
  163. resolve(candidates)
  164. }
  165. })
  166. }
  167. }
  168. }
  169. })
  170. }
  171. })
  172. }
  173. /**
  174. * WIP -> get a valid x64 Java path on macOS.
  175. */
  176. function _darwinValidate(){
  177. return null
  178. }
  179. /**
  180. * WIP -> get a valid x64 Java path on linux.
  181. */
  182. function _linuxValidate(){
  183. return null
  184. }
  185. // This will eventually return something.
  186. async function validate(){
  187. let res = null
  188. const opSys = process.platform
  189. if(opSys === 'win32'){
  190. res = await _win32Validate()
  191. } else if(opSys === 'darwin'){
  192. res = _darwinValidate()
  193. } else if(opSys === 'linux'){
  194. res = _linuxValidate()
  195. }
  196. return res;
  197. }
  198. const PLATFORM_MAP = {
  199. win32: '-windows-x64.tar.gz',
  200. darwin: '-macosx-x64.tar.gz',
  201. linux: '-linux-x64.tar.gz'
  202. }
  203. const BASE_URL = 'http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jre-8u161'
  204. function _downloadJava(acceptLicense, dir){
  205. if(!acceptLicense){
  206. return
  207. }
  208. // TODO -> Complete this code. See format used in assetguard.js#510
  209. const combined = BASE_URL + PLATFORM_MAP[process.platform]
  210. const name = combined.substring(combined.lastIndexOf('/')+1)
  211. const fDir = path.join(dir, name)
  212. const opts = {
  213. url: combined,
  214. headers: {
  215. 'Cookie': 'oraclelicense=accept-securebackup-cookie'
  216. }
  217. }
  218. const req = request(opts)
  219. let writeStream = fs.createWriteStream(fDir)
  220. req.pipe(writeStream)
  221. req.resume()
  222. }
  223. async function test(){
  224. console.log(await validate())
  225. }
  226. //test()
  227. _downloadJava(true, 'C:\\Users\\Asus\\Desktop\\LauncherElectron\\target\\')
  228. module.exports = {
  229. validate
  230. }