javaguard.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. const cp = require('child_process')
  2. const fs = require('fs')
  3. const path = require('path')
  4. const Registry = require('winreg')
  5. /**
  6. * WIP -> get a valid x64 Java path on windows.
  7. */
  8. async function _win32Validate(){
  9. // Get possible paths from the registry.
  10. const pathSet = await _scanRegistry()
  11. console.log(Array.from(pathSet)) // DEBUGGING
  12. // Validate JAVA_HOME
  13. const jHome = _scanJavaHome()
  14. if(jHome != null && jHome.indexOf('(x86)') === -1){
  15. pathSet.add(jHome)
  16. }
  17. // Convert path set to an array for processing.
  18. const pathArr = Array.from(pathSet)
  19. console.log(pathArr) // DEBUGGING
  20. // TODO - Determine best candidate (based on version, etc).
  21. let res = await _validateBinary(pathArr[0]) // DEBUGGING
  22. console.log(res) // DEBUGGING
  23. }
  24. /**
  25. * Validates that a Java binary is at least 64 bit. This makes use of the non-standard
  26. * command line option -XshowSettings:properties. The output of this contains a property,
  27. * sun.arch.data.model = ARCH, in which ARCH is either 32 or 64. This option is supported
  28. * in Java 8 and 9. Since this is a non-standard option. This will resolve to true if
  29. * the function's code throws errors. That would indicate that the option is changed or
  30. * removed.
  31. *
  32. * @param {string} binaryPath Path to the root of the java binary we wish to validate.
  33. *
  34. * @returns {Promise.<boolean>} Resolves to false only if the test is successful and the result
  35. * is less than 64.
  36. */
  37. function _validateBinary(binaryPath){
  38. return new Promise((resolve, reject) => {
  39. const fBp = path.join(binaryPath, 'bin', 'java.exe')
  40. cp.exec('"' + fBp + '" -XshowSettings:properties', (err, stdout, stderr) => {
  41. try {
  42. // Output is stored in stderr?
  43. const res = stderr
  44. const props = res.split('\n')
  45. for(let i=0; i<props.length; i++){
  46. if(props[i].indexOf('sun.arch.data.model') > -1){
  47. let arch = props[i].split('=')[1].trim()
  48. console.log(props[i].trim() + ' for ' + binaryPath)
  49. resolve(parseInt(arch) >= 64)
  50. }
  51. }
  52. // sun.arch.data.model not found?
  53. // Disregard this test.
  54. resolve(true)
  55. } catch (err){
  56. // Output format might have changed, validation cannot be completed.
  57. // Disregard this test in that case.
  58. resolve(true)
  59. }
  60. })
  61. })
  62. }
  63. /**
  64. * Checks for the presence of the environment variable JAVA_HOME. If it exits, we will check
  65. * to see if the value points to a path which exists. If the path exits, the path is returned.
  66. *
  67. * @returns {string} The path defined by JAVA_HOME, if it exists. Otherwise null.
  68. */
  69. function _scanJavaHome(){
  70. const jHome = process.env.JAVA_HOME
  71. try {
  72. let res = fs.existsSync(jHome)
  73. return res ? jHome : null
  74. } catch (err) {
  75. // Malformed JAVA_HOME property.
  76. return null
  77. }
  78. }
  79. /**
  80. * Scans the registry for 64-bit Java entries. The paths of each entry are added to
  81. * a set and returned. Currently, only Java 8 (1.8) is supported.
  82. *
  83. * @returns {Promise.<Set.<string>>} A promise which resolves to a set of 64-bit Java root
  84. * paths found in the registry.
  85. */
  86. function _scanRegistry(){
  87. return new Promise((resolve, reject) => {
  88. // Keys for Java v9.0.0 and later:
  89. // 'SOFTWARE\\JavaSoft\\JRE'
  90. // 'SOFTWARE\\JavaSoft\\JDK'
  91. // Forge does not yet support Java 9, therefore we do not.
  92. let cbTracker = 0
  93. let cbAcc = 0
  94. // Keys for Java 1.8 and prior:
  95. const regKeys = [
  96. '\\SOFTWARE\\JavaSoft\\Java Runtime Environment',
  97. '\\SOFTWARE\\JavaSoft\\Java Development Kit'
  98. ]
  99. const candidates = new Set()
  100. for(let i=0; i<regKeys.length; i++){
  101. const key = new Registry({
  102. hive: Registry.HKLM,
  103. key: regKeys[i],
  104. arch: 'x64'
  105. })
  106. key.keys((err, javaVers) => {
  107. if(err){
  108. console.error(err)
  109. if(i === regKeys.length-1){
  110. resolve(candidates)
  111. }
  112. } else {
  113. cbTracker += javaVers.length
  114. if(i === regKeys.length-1 && cbTracker === cbAcc){
  115. resolve(candidates)
  116. }
  117. for(let j=0; j<javaVers.length; j++){
  118. const javaVer = javaVers[j]
  119. const vKey = javaVer.key.substring(javaVer.key.lastIndexOf('\\')+1)
  120. // Only Java 8 is supported currently.
  121. if(parseFloat(vKey) == 1.8){
  122. javaVer.get('JavaHome', (err, res) => {
  123. const jHome = res.value
  124. if(jHome.indexOf('(x86)') == -1){
  125. candidates.add(jHome)
  126. cbAcc++
  127. }
  128. if(cbAcc === cbTracker){
  129. resolve(candidates)
  130. }
  131. })
  132. }
  133. }
  134. }
  135. })
  136. }
  137. })
  138. }
  139. /**
  140. * WIP -> get a valid x64 Java path on macOS.
  141. */
  142. function _darwinValidate(){
  143. }
  144. /**
  145. * WIP -> get a valid x64 Java path on linux.
  146. */
  147. function _linuxValidate(){
  148. }
  149. // This will eventually return something.
  150. async function validate(){
  151. const opSys = process.platform
  152. if(opSys === 'win32'){
  153. await _win32Validate()
  154. } else if(opSys === 'darwin'){
  155. _darwinValidate()
  156. } else if(opSys === 'linux'){
  157. _linuxValidate()
  158. }
  159. }
  160. validate()
  161. module.exports = {
  162. validate
  163. }