index.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. var fs = require('fs')
  2. var util = require('util')
  3. var childProcess = require('child_process')
  4. var path = require('path')
  5. var debug = require('debug')('regedit')
  6. var errors = require('./errors.js')
  7. var os = require('os')
  8. var StreamSlicer = require('stream-slicer')
  9. var through2 = require('through2')
  10. var helper = require('./lib/helper.js')
  11. var execFile = require('./lib/execFile.js')()
  12. var cscript = require('./lib/cscript.js')
  13. /*
  14. * Access the registry without using a specific os architecture, this means that on a 32bit process on a 64bit machine
  15. * when we access hklm\software we will actually be accessing hklm\software\wow6432node.
  16. */
  17. var OS_ARCH_AGNOSTIC = 'A'
  18. /*
  19. * Access the registry using a specific os architecture, but determine what the architecture is automatically
  20. * This means that accessing in order to access the 32bit software registry on a 64bit machine we will need to
  21. * use the key hklm\software\wow6432node
  22. */
  23. var OS_ARCH_SPECIFIC = 'S'
  24. /*
  25. * Access the registry using 32bit os architecture
  26. */
  27. var OS_ARCH_32BIT = '32'
  28. /*
  29. * Access the registry using 64bit os architecture, this will have no effect on 32bit process/machines
  30. */
  31. var OS_ARCH_64BIT = '64'
  32. /*
  33. * If this value is set the module will change directory of the VBS to the appropriate location instead of the local VBS folder
  34. */
  35. var externalVBSFolderLocation = undefined;
  36. module.exports.setExternalVBSLocation = function (newLocation) {
  37. if (fs.existsSync(newLocation)) {
  38. externalVBSFolderLocation = newLocation;
  39. return 'Folder found and set';
  40. }
  41. else{
  42. return 'Folder not found';
  43. }
  44. }
  45. module.exports.list = function (keys, architecture, callback) {
  46. //console.log('list with callback will be deprecated in future versions, use list streaming interface')
  47. if (architecture === undefined) {
  48. callback = undefined
  49. architecture = OS_ARCH_AGNOSTIC
  50. }
  51. else if (typeof architecture === 'function') {
  52. callback = architecture
  53. architecture = OS_ARCH_AGNOSTIC
  54. }
  55. if (typeof keys === 'string') {
  56. keys = [keys]
  57. }
  58. if (typeof callback === 'function') {
  59. execute(toCommandArgs('regList.wsf', architecture, keys), callback)
  60. }
  61. else {
  62. var outputStream = through2.obj(helper.vbsOutputTransform)
  63. cscript.init(function (err) {
  64. if (err) {
  65. return outputStream.emit('error', err)
  66. }
  67. var args = baseCommand('regListStream.wsf', architecture)
  68. var child = execFile(cscript.path(), args, {encoding: 'utf8'}, function(err) {
  69. if (err) {
  70. outputStream.emit('error', err)
  71. }
  72. })
  73. child.stderr.pipe(process.stderr)
  74. var slicer = new StreamSlicer({sliceBy: helper.WIN_EOL})
  75. child.stdout.pipe(slicer).pipe(outputStream)
  76. helper.writeArrayToStream(keys, child.stdin)
  77. })
  78. return outputStream
  79. }
  80. }
  81. module.exports.createKey = function (keys, architecture, callback) {
  82. if (typeof architecture === 'function') {
  83. callback = architecture
  84. architecture = OS_ARCH_AGNOSTIC
  85. }
  86. if (typeof keys === 'string') {
  87. keys = [keys]
  88. }
  89. var args = baseCommand('regCreateKey.wsf', architecture)
  90. spawnEx(args, keys, callback)
  91. }
  92. module.exports.deleteKey = function (keys, architecture, callback) {
  93. if (typeof architecture === 'function') {
  94. callback = architecture
  95. architecture = OS_ARCH_AGNOSTIC
  96. }
  97. if (typeof keys === 'string') {
  98. keys = [keys]
  99. }
  100. var args = baseCommand('regDeleteKey.wsf', architecture)
  101. spawnEx(args, keys, callback)
  102. }
  103. module.exports.putValue = function(map, architecture, callback) {
  104. if (typeof architecture === 'function') {
  105. callback = architecture
  106. architecture = OS_ARCH_AGNOSTIC
  107. }
  108. var args = baseCommand('regPutValue.wsf', architecture)
  109. var values = []
  110. for (var key in map) {
  111. var keyValues = map[key]
  112. for (var valueName in keyValues) {
  113. var entry = keyValues[valueName]
  114. // helper writes the array to the stream in reversed order
  115. values.push(entry.type)
  116. values.push(renderValueByType(entry.value, entry.type))
  117. values.push(valueName)
  118. values.push(key)
  119. }
  120. }
  121. spawnEx(args, values, callback)
  122. }
  123. module.exports.arch = {}
  124. module.exports.arch.list = function(keys, callback) {
  125. return module.exports.list(keys, OS_ARCH_SPECIFIC, callback)
  126. }
  127. module.exports.arch.list32 = function (keys, callback) {
  128. return module.exports.list(keys, OS_ARCH_32BIT, callback)
  129. }
  130. module.exports.arch.list64 = function (keys, callback) {
  131. return module.exports.list(keys, OS_ARCH_64BIT, callback)
  132. }
  133. module.exports.arch.createKey = function (keys, callback) {
  134. return module.exports.createKey(keys, OS_ARCH_SPECIFIC, callback)
  135. }
  136. module.exports.arch.createKey32 = function (keys, callback) {
  137. return module.exports.createKey(keys, OS_ARCH_32BIT, callback)
  138. }
  139. module.exports.arch.createKey64 = function (keys, callback) {
  140. return module.exports.createKey(keys, OS_ARCH_64BIT, callback)
  141. }
  142. module.exports.arch.deleteKey = function (keys, callback) {
  143. return module.exports.deleteKey(keys, OS_ARCH_SPECIFIC, callback)
  144. }
  145. module.exports.arch.deleteKey32 = function (keys, callback) {
  146. return module.exports.deleteKey(keys, OS_ARCH_32BIT, callback)
  147. }
  148. module.exports.arch.deleteKey64 = function (keys, callback) {
  149. return module.exports.deleteKey(keys, OS_ARCH_64BIT, callback)
  150. }
  151. module.exports.arch.putValue = function (keys, callback) {
  152. return module.exports.putValue(keys, OS_ARCH_SPECIFIC, callback)
  153. }
  154. module.exports.arch.putValue32 = function (keys, callback) {
  155. return module.exports.putValue(keys, OS_ARCH_32BIT, callback)
  156. }
  157. module.exports.arch.putValue64 = function (keys, callback) {
  158. return module.exports.putValue(keys, OS_ARCH_64BIT, callback)
  159. }
  160. function execute(args, callback) {
  161. if (typeof callback !== 'function') {
  162. throw new Error('missing callback')
  163. }
  164. debug(args)
  165. cscript.init(function (err) {
  166. if (err) {
  167. return callback(err)
  168. }
  169. childProcess.execFile(cscript.path(), args, function (err, stdout, stderr) {
  170. if (err) {
  171. if (stdout) {
  172. console.log(stdout)
  173. }
  174. if (stderr) {
  175. console.error(stderr)
  176. }
  177. if (err.code in errors) {
  178. return callback(errors[err.code])
  179. }
  180. return callback(err)
  181. }
  182. // in case we have stuff in stderr but no real error
  183. if (stderr) {
  184. return callback(new Error(stderr))
  185. }
  186. if (!stdout) {
  187. return callback()
  188. }
  189. debug(stdout)
  190. var result
  191. err = null
  192. try {
  193. result = JSON.parse(stdout)
  194. }
  195. catch (e) {
  196. e.stdout = stdout
  197. err = e
  198. }
  199. callback(err, result)
  200. })
  201. })
  202. }
  203. function spawnEx(args, keys, callback) {
  204. cscript.init(function (err) {
  205. if (err) {
  206. return callback(err)
  207. }
  208. debug(args)
  209. var child = execFile(cscript.path(), args, {encoding: 'utf8'})
  210. handleErrorsAndClose(child, callback)
  211. helper.writeArrayToStream(keys, child.stdin)
  212. })
  213. }
  214. function handleErrorsAndClose (child, callback) {
  215. var error
  216. child.once('error', function(e) {
  217. debug('process error %s', e)
  218. error = e
  219. })
  220. child.once('close', function (code) {
  221. debug('process exit with code %d', code)
  222. if (error) {
  223. if (error.code in errors) {
  224. return callback(errors[error.code])
  225. }
  226. return callback(error)
  227. }
  228. if (code !== 0) {
  229. if (code in errors) {
  230. return callback(errors[code])
  231. }
  232. return callback(new Error('vbscript process reported unknown error code ' + code))
  233. }
  234. callback()
  235. })
  236. }
  237. //TODO: move to helper.js?
  238. function renderValueByType(value, type) {
  239. type = type.toUpperCase()
  240. switch (type) {
  241. case 'REG_BINARY':
  242. if (!util.isArray(value)) {
  243. throw new Error('invalid value type ' + typeof (value) + ' for registry type REG_BINARY, please use an array of numbers')
  244. }
  245. return value.join(',')
  246. case 'REG_MULTI_SZ':
  247. if (!util.isArray(value)) {
  248. throw new Error('invalid value type ' + typeof (value) + ' for registry type REG_BINARY, please use an array of strings')
  249. }
  250. return value.join(',')
  251. case 'REG_SZ':
  252. if (value === '') {
  253. return '\0'
  254. }
  255. return value
  256. default:
  257. return value
  258. }
  259. }
  260. //TODO: move to helper.js?
  261. function toCommandArgs(cmd, arch, keys) {
  262. var result = baseCommand(cmd, arch)
  263. if (typeof keys === 'string') {
  264. result.push(keys)
  265. }
  266. else if (util.isArray(keys)) {
  267. result = result.concat(keys)
  268. }
  269. else {
  270. debug('creating command without using keys %s', keys ? keys : '')
  271. }
  272. return result
  273. }
  274. //TODO: move to helper.js?
  275. function baseCommand(cmd, arch) {
  276. var scriptPath
  277. // test undefined, null and empty string
  278. if (externalVBSFolderLocation && typeof(externalVBSFolderLocation) === 'string') {
  279. scriptPath = externalVBSFolderLocation
  280. } else {
  281. scriptPath = path.join(__dirname, 'vbs')
  282. }
  283. return ['//Nologo', path.join(scriptPath, cmd), arch]
  284. }