You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

win_verse.js 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  1. // win_verse
  2. const { any, Traq } = require('bbhverse');
  3. const fs = require('fs')
  4. var path = require('path');
  5. var {nodeShellExec, createTask} = require('./nodeshell');
  6. function elevatedRunIPCWriteMessage( target, m ) {
  7. fs.writeFileSync(target, ', ' + JSON.stringify( m ), { 'flag': 'a+' })
  8. }
  9. function toHTML(l, x, r, ol, or){
  10. ol = ol || '<div>'
  11. or = or || '</div>'
  12. l = l || '<div>'
  13. r = r || '</div>'
  14. if(Object.prototype.toString.call(x) === '[object Array]') {
  15. var ahtml = []
  16. x.forEach(xi => { ahtml.push( `${l}${xi}${r}` ) })
  17. return `${ol}${ahtml.join('')}${or}`
  18. }
  19. }
  20. var __isElevated = null;
  21. var shell_verse = {
  22. // getCommonTask is agnostic of whether we are running in an elevated shell or not. It runs in either case.
  23. init( o ){ Object.assign(this, o) }
  24. , downloadsdir : '../Downloads'
  25. , getCommonTask( taskToRun ){ return ()=>{ return shell_verse.runTask(taskToRun) }}
  26. , runTask : ( taskToRun ) => {
  27. if (__isElevated) return shell_verse.elevatedRunner( taskToRun )
  28. else return shell_verse.runNonElevated( taskToRun )
  29. }
  30. , elevatedRunner( taskToRun, inBatch ){
  31. // PB : TODO -- Should be called only when we are in an elevated shell that was already requested from an unelevated shell with a batch of tasks.
  32. try {
  33. var runlogjson = `${taskToRun.selectedinstance.root}/.elxr/run-${taskToRun.runtimestamp}/run.log`
  34. var __runasresult = null;
  35. return taskToRun().then((r)=>{
  36. // PB : TODO -- Every elevation should have its own messaging file. Async writes from multiple processes are a problem here...
  37. elevatedRunIPCWriteMessage( runlogjson, { info : taskToRun.info, success: true } )
  38. if(!inBatch) fs.writeFileSync(`${this.tempRunDir()}\\run.done`, 'success') // PB : TODO -- This should be done conditionally if we are running inproc.
  39. return __runasresult = r;
  40. })
  41. .catch((e) => {
  42. elevatedRunIPCWriteMessage( runlogjson, e)
  43. if(!inBatch)fs.writeFileSync(`${this.tempRunDir()}\\run.done`, 'failure')
  44. console.error(e)
  45. })
  46. .finally(() => {
  47. // if(__runasresult && !__runasresult.skipped) fs.unlinkSync(`${this.tempRunDir()}\\run.done`)
  48. })
  49. }
  50. catch (e) {
  51. console.error('Error Invalid command : ' + e)
  52. if(!inBatch) fs.writeFileSync(`${this.tempRunDir()}\\run.done`, 'error')
  53. }
  54. finally {
  55. }
  56. }
  57. , getElevatedTask : function( taskToRun ){ return ()=>{ return shell_verse.runElevated(taskToRun) }}
  58. , getElevatedTaskInBatch : function( taskToRun ){ return ()=>{ return shell_verse.runElevatedInBatch(taskToRun) }}
  59. , runElevatedInBatch : ( taskToRun ) => {
  60. if (__isElevated) return shell_verse.elevatedRunner(taskToRun, true)
  61. else return shell_verse.requestElevation(shell_verse.elevatedRunner, taskToRun)
  62. }
  63. , runElevated : function( taskToRun ){
  64. fs.writeFileSync( `${this.tempRunDir()}\\run.log`, ', ' + JSON.stringify({ taskstart : true }), {'flag':'a+'} )
  65. // Let shell_verse decide whether to Elevate Out of Proc or In Proc
  66. // taskToRun by default is the launched command and args. Specially in windows out of proc.
  67. // taskToRun = taskToRun || (()=>{ return op[processedArgs.label || processedArgs._[0] || 'undefined'](processedArgs) })
  68. if(taskToRun.processedArgs.skipelevated) return Promise.resolve({ skipped : true });
  69. if (__isElevated) {
  70. return shell_verse.elevatedRunner(taskToRun)
  71. }
  72. else {
  73. console.log('Requesting Elevated Privileges');
  74. // requesteElevation is acutally request elevation and run. Both In Proc and Out of Proc.
  75. // Linux doesnt require elevation for most commands...
  76. return shell_verse.requestElevation(shell_verse.elevatedRunner, taskToRun)
  77. }
  78. }
  79. , runElevatedBatch( batchToRun ){
  80. // In windows we don't need to run each task. We hand over to another shell which in elevated state rebuilds the whole batch and runs.
  81. // Irrespective of the batch we just call runElevated once.
  82. if (__isElevated) {
  83. return any(batchToRun).then((r)=>{
  84. // PB : TODO -- Every elevation should have its own messaging file. Async writes from multiple processes are a problem here...
  85. // fs.writeFileSync('run.log', ', ' + JSON.stringify( { info : taskToRun.info, success: true }), { 'flag': 'a+' })
  86. fs.writeFileSync(`${this.tempRunDir()}\\run.done`, 'success') // PB : TODO -- This should be done conditionally if we are running inproc.
  87. return __runasresult = r;
  88. })
  89. .catch((e) => {
  90. // fs.writeFileSync('run.log', ', ' + JSON.stringify(e), { 'flag': 'a+' })
  91. fs.writeFileSync(`${this.tempRunDir()}\\run.done`, 'failure')
  92. console.error(e)
  93. })
  94. // .finally(() => {
  95. // if(__runasresult && !__runasresult.skipped) fs.unlinkSync(`${this.tempRunDir()}\\run.done`)
  96. // });
  97. }
  98. else {
  99. return this.runElevated(batchToRun[0])
  100. }
  101. }
  102. , getNonElevatedTask : function( taskToRun ){ return ()=>{ return shell_verse.runNonElevated(taskToRun) } }
  103. , runNonElevated : ( taskToRun ) => {
  104. // Let shell_verse decide whether to Elevate Out of Proc or In Proc
  105. if(__isElevated) {
  106. return Promise.resolve( 'Skipping regular task in elevated shell.' ) // Regular tasks unless marked as common tasks should not run in elevated shell...
  107. }
  108. else {
  109. // taskToRun by default is the launched command and args.
  110. // taskToRun = taskToRun || (()=>{ return op[processedArgs.label || processedArgs._[0] || 'undefined'](processedArgs) })
  111. return taskToRun().then(r=>{
  112. taskToRun.statuslog.statuslog(null, taskToRun.info /*repo*/ )
  113. return r;
  114. }).catch((e) => {
  115. e.info = taskToRun.info;
  116. if(taskToRun.errHandler) throw taskToRun.errHandler(e)
  117. taskToRun.statuslog.statuslog(e); //
  118. // console.error(e)
  119. throw e;
  120. }).finally(()=>{})
  121. }
  122. }
  123. , isElevated : ()=>{
  124. return acquireElevationState().then( ()=>{
  125. shell_verse.isElevated = () => {
  126. return Promise.resolve(__isElevated)
  127. }
  128. return shell_verse.isElevated()
  129. })
  130. }
  131. // , isElevationOutOfProc : ()=>{ return true }
  132. , acquireElevationState : () => {
  133. return nodeShellExec("fsutil", ["dirty", "query", "C:"], {
  134. inherit: true
  135. // , shell: true
  136. , stdio: 'ignore'
  137. , env: process.env
  138. , title: `check privileged execution mode using "fsutil dirty query C:"`
  139. }).then((exitcode) => {
  140. console.log('Elevated')
  141. __isElevated = true;
  142. shell_verse.acquireElevationState = ()=> Promise.resolve(__isElevated);
  143. shell_verse.isElevated = () => { return Promise.resolve(__isElevated)}
  144. // fs.writeFileSync( `${this.tempRunDir()}\\run.log`, ', ' + JSON.stringify({ elevated : true}), {'flag':'a+'} )
  145. return __isElevated
  146. }).catch((e) => {
  147. __isElevated = false;
  148. shell_verse.acquireElevationState = ()=> Promise.resolve(__isElevated);
  149. shell_verse.isElevated = () => { return Promise.resolve(__isElevated)}
  150. console.log('Not Elevated');
  151. // fs.writeFileSync( `${this.tempRunDir()}\\run.log`, ', ' + JSON.stringify({ elevated : false}), {'flag':'a+'} )
  152. return __isElevated
  153. })
  154. // .finally(()=>{
  155. // shell_verse.acquireElevationState = ()=> Promise.resolve(__isElevated);
  156. // shell_verse.isElevated = () => { return Promise.resolve(__isElevated)}
  157. // // return __isElevated; // Value returned from finally is not supported by node.
  158. // })
  159. }
  160. , getTaskCheckExists : createTask('getTaskCheckExists', 'where')
  161. , getbash : ()=>{ return "C:\\Program Files\\Git\\bin\\sh.exe" }
  162. , createJuntionOrLink : (dirOrFile, target, opts) =>{
  163. return nodeShellExec('mklink', ['/J', dirOrFile, target], opts).catch((e) => { console.error(e)
  164. fs.writeFileSync( `${this.tempRunDir()}\\run.log`, ', ' + JSON.stringify({ e }), {'flag':'a+'} )
  165. })
  166. }
  167. , removeJuncionOrLink : ( junctionOrLink )=>{
  168. return nodeShellExec('rmdir', [junctionOrLink], { inherit: true, shell: true, env: process.env })
  169. }
  170. , tempRunDir : function(){ return `${this.selectedinstance.root}\\.elxr\\run-${this.runtimestamp}`}
  171. , requestElevation(elevatedRunner, taskToRun) {
  172. // PB : TODO -- Multiple parallel request elevations should be queued into a batch and serialized as a single promise.
  173. var processedArgs = taskToRun.processedArgs, statuslog = taskToRun.statuslog || Traq
  174. // Wait for the runas to complete before we read it.
  175. try {
  176. fs.unlinkSync(`${this.tempRunDir()}\\run.done`) // Need a unique file for aech elevated run.
  177. }
  178. catch (e) { } //Ignore
  179. // Find node path to send to hta.
  180. return nodeShellExec('where', ['node']).then(r => {
  181. var args = taskToRun.args
  182. var options = taskToRun.args ? taskToRun.args.pop() : {
  183. inherit: true
  184. , shell: true
  185. , env: taskToRun.ENV
  186. , runas: 'self'
  187. , title: `runas`
  188. }
  189. options.env = Object.assign({}, taskToRun.ENV, { wd : options.cwd })
  190. var spawntimestamp = (new Date()).getTime()
  191. if(!args) {
  192. var namedArgs = [];
  193. console.log('result : ' + JSON.stringify(r))
  194. Object.keys(processedArgs).forEach((v) => { v != '_' ? namedArgs.push('--' + v + '=' + processedArgs[v]) : null; })
  195. // PB : TODO -- Convert all the cli args back to string.
  196. args = [].concat(processedArgs._)
  197. namedArgs.length > 0 ? args = args.concat(namedArgs.join(' ')) : null;
  198. }
  199. else {
  200. // args = args.splice(-1) -- Already popped
  201. args.push(`--root=${selectedinstance.root}`);
  202. }
  203. args.splice(0,0, path.normalize(`${taskToRun.selectedinstance.root}/.elxr/run-${taskToRun.runtimestamp}/windowselevate.hta`))
  204. args.push('--runas=self');
  205. // args.debug = true
  206. if(args.debug) args.push(`--debug=${args.debug}`);
  207. args.push(`--runtimestamp=${this.runtimestamp}`);
  208. args.push(`--spawntimestamp=${spawntimestamp}`);
  209. // args.push(`--wd=${options.cwd}`);
  210. // args.push('--nodepath=' + r.messages[r.messages.length - 1])
  211. // if (!processedArgs.node_env) args.push('--node_env=' + ENV.NODE_ENV)
  212. // if (processedArgs.debug) args.push('--debug=true') // Enable to debug elevated..
  213. // console.dir(processedArgs._)
  214. // console.dir(namedArgs.join(' '))
  215. console.dir(args)
  216. // throw 'test'
  217. return nodeShellExec('MSHTA', [`"${args.join('" "')}"`], options ).then(() => {
  218. // runas returned.
  219. try {
  220. // PB : TODO -- Log is comma prefixed. Needs to be proper JSON.
  221. var runlogjson = `${taskToRun.selectedinstance.root}/.elxr/run-${this.runtimestamp}/run.log`
  222. var runaslog = JSON.parse('[ { "MSHTA" : "done", "success" : true }, ' + fs.readFileSync(runlogjson, { flags: 'a+' }) + ']');
  223. try { fs.unlinkSync(runlogjson) } catch(e){ } // PB : TODO -- Have a unique file for each elevated run.
  224. // console.log( "runaslog : " + runaslog.length )
  225. // Assemble elevated run results into the main run log
  226. runaslog.forEach((logEntry) => {
  227. statuslog.statuslog(logEntry.success ? null : logEntry, logEntry)
  228. logEntry.error ? (console.error(['error :' + logEntry.result]), console.error((logEntry.messages || []).join(' '))) :
  229. (console.log(['success :' + (logEntry.result || logEntry.success)]), console.log((logEntry.messages || []).join(' ')))
  230. })
  231. if(statuslog) fs.writeFileSync( `${this.tempRunDir()}\\run.log`, ', ' + JSON.stringify(statuslog), {'flag':'a+'} )
  232. }
  233. catch (e) {
  234. // We must have a runas log
  235. statuslog.statuslog(e)
  236. console.error('Run log error probably was not created by runas : ' + e)
  237. fs.writeFileSync( `${this.tempRunDir()}\\run.log`, ', ' + JSON.stringify(statuslog), {'flag':'a+'} )
  238. }
  239. })
  240. .catch(err => console.error('Elevation failed : ' + JSON.stringify(err)));
  241. })
  242. }
  243. , launchui() {
  244. // PB : TODO -- Multiple parallel requests should be queued into a batch and serialized as a single promise.
  245. // PB : TODO -- cleanup elevated execution code from here. This is a non elevated hta.
  246. var processedArgs = this.processedArgs
  247. // Wait for the runas to complete before we read it.
  248. try {
  249. fs.unlinkSync(`${this.tempRunDir()}\\run.done`) // Need a unique file for aech elevated run.
  250. }
  251. catch (e) { } //Ignore
  252. console.log(this.processedArgs.awaiturn)
  253. // Find node path to send to hta.
  254. return nodeShellExec('where', ['node']).then(r => {
  255. var namedArgs = [];
  256. console.log('result : ' + JSON.stringify(r))
  257. Object.keys(processedArgs).forEach((v) => { v != '_' ? namedArgs.push('--' + v + '=' + processedArgs[v]) : null; })
  258. // PB : TODO -- Convert all the cli args back to string.
  259. var _args = []
  260. if(processedArgs._[0] === 'launchui' ) { _args = processedArgs._.slice(1); _args.splice(0,0, 'pull') } // Default command.
  261. else _args = processedArgs._;
  262. var args = [ path.normalize(`${this.selectedinstance.root}/.elxr/run-${this.runtimestamp}/windowselevate.hta`) ].concat(_args)
  263. namedArgs.length > 0 ? args = args.concat(namedArgs.join(' ')) : null;
  264. // args.push('--runas=self');
  265. var spawntimestamp = (new Date()).getTime()
  266. args.push(`--runtimestamp=${this.runtimestamp}`);
  267. args.push(`--spawntimestamp=${spawntimestamp}`);
  268. // args.push('--nodepath=' + r.messages[r.messages.length - 1])
  269. // if (!processedArgs.node_env) args.push('--node_env=' + ENV.NODE_ENV)
  270. // if (processedArgs.debug) args.push('--debug=true') // Enable to debug elevated..
  271. // console.dir(processedArgs._)
  272. // console.dir(namedArgs.join(' '))
  273. console.dir(args)
  274. // throw 'test'
  275. return nodeShellExec('MSHTA', [`"${args.join('" "')}"`]
  276. , {
  277. inherit: true
  278. , shell: true
  279. , env: this.ENV
  280. // , runas: 'self'
  281. // , title: `runas`
  282. }
  283. ).then(() => {
  284. // runas returned.
  285. try {
  286. // PB : TODO -- Log is comma prefixed. Needs to be proper JSON.
  287. var runlogjson = `${this.selectedinstance.root}/.elxr/run-${this.runtimestamp}/run.log`
  288. var runaslog = JSON.parse('[' + fs.readFileSync(runlogjson, { flags: 'a+' }) + ']');
  289. try { fs.unlinkSync(runlogjson) } catch(e){ } // PB : TODO -- Have a unique file for each elevated run.
  290. // console.log( "runaslog : " + runaslog.length )
  291. // Assemble elevated run results into the main run log
  292. runaslog.forEach((logEntry) => {
  293. this.statuslog.statuslog(logEntry.success ? null : logEntry, logEntry)
  294. logEntry.success ? (console.log(['success :' + (logEntry.result || logEntry.success)]), console.log((logEntry.messages || []).join(' '))) : (console.error(['error :' + logEntry.result]), console.error((logEntry.messages || []).join(' ')))
  295. })
  296. }
  297. catch (e) {
  298. // We must have a runas log
  299. this.statuslog.statuslog(e)
  300. console.error('Run log error probably was not created by runas : ' + e)
  301. }
  302. })
  303. .catch(err => console.error('Elevation failed : ' + err));
  304. })
  305. }
  306. , ensureDirectoryExistence(filePath) {
  307. var dirname = path.dirname(filePath);
  308. if (fs.existsSync(dirname)) {
  309. return filePath;
  310. }
  311. this.ensureDirectoryExistence(dirname);
  312. fs.mkdirSync(dirname);
  313. return filePath;
  314. }
  315. , generateDependencies(){
  316. // PB : TODO -- Keep only the last n runs...
  317. // Currently it retains 2*n when proc needs to be relaunched in elevated mode !!!
  318. this.ensureDirectoryExistence(`${this.selectedinstance.root}/.elxr/run-${this.runtimestamp}/download.bat`)
  319. fs.writeFileSync(this.ensureDirectoryExistence(path.normalize(`${this.selectedinstance.root}/${this.downloadsdir}/readme.txt`)), `${this.getVersion()} Your local downloads for this instance`)
  320. // PB : TODO include and build from files... using rollup..
  321. var downloadbatch =
  322. `::**************************************************************************
  323. :Download_ <url> <File>
  324. Powershell.exe ^
  325. $AllProtocols = [System.Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'; ^
  326. [System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols; ^
  327. (New-Object System.Net.WebClient).DownloadFile('%1','%2')
  328. exit /b
  329. ::**************************************************************************`
  330. fs.writeFileSync(`${this.selectedinstance.root}/.elxr/run-${this.runtimestamp}/download.bat`, downloadbatch)
  331. var windowselevate =
  332. `
  333. <html><HTA:APPLICATION ID="windowselevate" icon="#"/>
  334. <script language="vbscript">
  335. document.title = "elxr control panel"
  336. self.ResizeTo 1024,1000
  337. Sub Window_Onload
  338. self.MoveTo (screen.availWidth - (screen.availWidth/2 + 40)),10
  339. End Sub
  340. Set objShell = CreateObject("WScript.Shell")
  341. Set objENV = objShell.Environment("Process")
  342. dim NODE_ENV
  343. NODE_ENV = objENV("NODE_ENV")
  344. </script>
  345. <script language="javascript">
  346. //WINDOWSTATE="minimize" SHOWINTASKBAR="no" SYSMENU="no" CAPTION="no"
  347. // https://devblogs.microsoft.com/scripting/how-can-i-pass-command-line-variables-to-an-hta-when-it-starts/
  348. // alert(windowselevate.commandLine)
  349. var args = windowselevate.commandLine.split('"').slice(3);
  350. // alert(args)
  351. var processedArgs = { _ : [] }
  352. var namedArgs = [];
  353. namedArgs.push('--wd=' + objENV('wd'))
  354. // alert(namedArgs)
  355. for(var item in args){
  356. if(args[item].charAt(0) === '-'){
  357. namedArgs.push(args[item])
  358. var split = args[item].split('=');
  359. processedArgs[split[0].slice(2)] = split[1] || true;
  360. }
  361. else processedArgs._.push(args[item]);
  362. }
  363. var awaitrun = true;
  364. if(!processedArgs.awaitrun) {
  365. awaitrun = false;
  366. delete processedArgs.awaitrun
  367. }
  368. // args = args.forEach(function(item){ })
  369. // alert('processedArgs._ : ' + processedArgs._);
  370. // alert(processedArgs.runas);
  371. // alert(objENV('wd'))
  372. // PB : TODO -- Convert all the cli args back to string.
  373. // __filename will sure we are launhed using the same entry point.
  374. var cargs = (processedArgs.debug ? '--inspect-brk=9226' : '') + ' ${this.selectedinstance.launchscript.replace(/\\/g, '\\\\')}' + ' ' + processedArgs._.join(' ') + ' ' + namedArgs.join(' ');
  375. // cargs = (processedArgs.debug ? '--inspect-brk=9226' : '') + ' ${__filename.replace(/\\/g, '\\\\').replace("win_verse", "index")}' + processedArgs._.join(' ') + ' ' + namedArgs.join(' ');
  376. // alert(cargs)
  377. var shell = new ActiveXObject('shell.application');
  378. // alert('launching node privilged. ' + processedArgs['nodepath'])
  379. // shell.ShellExecute('cmd.exe', '/k where node', '', '', 10);
  380. // shell.ShellExecute('cmd.exe', '/k notepad.exe', '', 'runas', 1);
  381. // shell.ShellExecute('cmd.exe ', '/k node ', '', 'runas', 1);
  382. // shell.ShellExecute('cmd.exe ', '/k node ' + cargs + '', '', 'runas', 1);
  383. // alert(cargs)
  384. function run(runas){ shell.ShellExecute('node', cargs, '', runas, 1); }
  385. if(!awaitrun) { run('runas') }
  386. var log = document.createElement('div');
  387. log.innerHTML='Please Wait';
  388. function l(msg){ log.innerHTML+= msg; };
  389. // log.style.color = 'blue';
  390. log.style.width = '95%';
  391. log.id = 'log';
  392. function endconsole(from){
  393. // alert('endconsole ' + from)
  394. if(fso.FileExists('${(this.tempRunDir()+'\\run.done').replace(/\\/g, '\\\\')}')) {
  395. fso.DeleteFile('${(this.tempRunDir()+'\\run.done').replace(/\\/g, '\\\\')}') // PB : TODO -- IPC through files is needed only for windows we need to do it per run...
  396. }
  397. // alert('closing window')
  398. window.close();
  399. };
  400. var timer = function(){
  401. // alert('here')
  402. l('.');
  403. l('endconsole ' + ' ' + '${(this.tempRunDir()+'\\run.done').replace(/\\/g, '\\\\')} <br/>')
  404. if(fso.FileExists('${(this.tempRunDir()+'\\run.done').replace(/\\/g, '\\\\')}')) {
  405. endconsole('timer')
  406. }
  407. else window.setTimeout(timer, 3000);
  408. };
  409. // alert('/k node ' + cargs + '')
  410. // shell.ShellExecute(processedArgs['nodepath'], cargs, '', 'runas', 1);
  411. var fso = new ActiveXObject('Scripting.FileSystemObject');
  412. function i(html){ var e = document.createElement('div'); e.innerHTML = html; document.body.appendChild(e); };
  413. // window.onbeforeunload = function (e) {
  414. // endconsole('onbeforeunload')
  415. // };
  416. window.onload = function() {
  417. document.body.style.backgroundColor = 'black';
  418. document.body.style.fontFamily = 'arial';
  419. document.body.style.color = 'cyan';
  420. var cmds = document.createElement('div');
  421. cmds.innerHTML = '';
  422. cmds.w = function(msg){ cmds.innerHTML+= msg; };
  423. cmds.w('<Br/>Current config : ')
  424. // cmds.w('<div style="width:50%" onclick="endconsole()">X</div>' )
  425. cmds.w('<input type="button" value="Close Console" onclick="endconsole()">')
  426. cmds.w('<Br/>NODE_ENV = ' + NODE_ENV)
  427. var namedArgs = [];
  428. for(var v in processedArgs){
  429. if(v != '_' && v!== 'runtimestamp') {
  430. namedArgs.push('--' + v + '=' + processedArgs[v])
  431. }
  432. }
  433. // cmds.w('<Br/>cmd = ' + processedArgs._.join(' ') + ' ' + namedArgs.join(' ') )
  434. cmds.w('<Br/><Br/>')
  435. cmds.w('cmd = <input style="width:80%" type="text" value="' + processedArgs._.join(' ') + ' ' + namedArgs.join(' ') + '"></input> <input type="button" value="Run" onclick="run()"></input>')
  436. cmds.w('${toHTML('<option>', Object.keys(this.cmds), '</option>', '<select>', '</select>')}');
  437. // cmds.style.color = 'blue';
  438. // processedArgs._[1] === 'use' ? l('<Br/>using = ' + processedArgs._[2]) : null;
  439. document.body.appendChild(cmds);
  440. document.body.appendChild(log);
  441. // alert(fso.GetAbsolutePathName("."))
  442. window.setTimeout(timer, 3000);
  443. };
  444. </script>
  445. </html>
  446. `
  447. fs.writeFileSync(`${this.selectedinstance.root}/.elxr/run-${this.runtimestamp}/windowselevate.hta`, windowselevate)
  448. }
  449. , getchrome(){
  450. // Chrome install location from registry.
  451. return shell_verse.regread("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\chrome.exe\\").then(chromepath => {
  452. // HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\chrome.exe
  453. console.log(chromepath)
  454. return chromepath
  455. });
  456. }
  457. , regread(s){
  458. var uniquerun = (new Date()).getTime()
  459. var out = `${this.selectedinstance.root}/.elxr/run-${this.runtimestamp}/${uniquerun}-regread.out`
  460. var outescaped = out.replace(/\\/g,"\\\\")
  461. // console.log('out ::: ' + out)
  462. fs.writeFileSync(`${this.selectedinstance.root}/.elxr/run-${this.runtimestamp}/${uniquerun}-regread.js`,
  463. `
  464. // WScript.Echo('------------UNNAMED-----------')
  465. // WScript.Echo(WScript.Arguments.Item(0))
  466. argEnumerator = new Enumerator(WScript.Arguments.Unnamed)
  467. var args = []
  468. for(; !argEnumerator.atEnd(); argEnumerator.moveNext()){
  469. args.push('' + argEnumerator.item() + '')
  470. // WScript.Echo('-arg-' + argEnumerator.item() + '-arg-') // Value
  471. }
  472. // WScript.Echo(args[0])
  473. var objShell = WScript.createobject("wscript.shell")
  474. if(!args[0]) {
  475. WScript.Echo( '' )
  476. }
  477. else {
  478. WScript.Echo(args[0])
  479. var read = objShell.RegRead(args[0])
  480. try {
  481. var fs = new ActiveXObject('Scripting.FileSystemObject');
  482. var fh = fs.CreateTextFile('${outescaped}', true);
  483. fh.WriteLine(read);
  484. fh.Close();
  485. }
  486. catch(e){ WScript.Echo(e.message) }
  487. // WScript.Echo( read )
  488. }
  489. `
  490. )
  491. return nodeShellExec('cscript', [path.normalize(`${this.selectedinstance.root}/.elxr/run-${this.runtimestamp}/${uniquerun}-regread.js`), `${s}`])
  492. .then(read => {
  493. // console.log("REGREAD RESULT : " + read)
  494. // console.dir(read)
  495. if(read.success) {
  496. return (fs.readFileSync(out) + "").trim()
  497. }
  498. else throw 'regread failed'
  499. })
  500. }
  501. , isWin(){ return true}
  502. , islin(){ return false}
  503. }
  504. module.exports = shell_verse