Added polyfill for Array.find() when missing, needed for Windows/Temp self update

Bryan Roe committed Jun 4, 2021 at 11:46 UTC ab8b3095dd0f79ae9b3d291adda84befd9ed7244
1 file changed +218 -31
agents/recoverycore.js
+218 -31
@@ -6,9 +6,104 @@ var nextTunnelIndex = 1;
6 var tunnels = {};
7 var fs = require('fs');
8
9 -if (require('MeshAgent').ARCHID == null) {
9 +try
10 +{
11 + Object.defineProperty(Array.prototype, 'find', {
12 + value: function (func)
13 + {
14 + var i = 0;
15 + for(i=0;i<this.length;++i)
16 + {
17 + if(func(this[i]))
18 + {
19 + return (this[i]);
20 + }
21 + }
22 + return (null);
23 + }
24 + });
25 +}
26 +catch(x)
27 +{
28 +
29 +}
30 +
31 +function _getPotentialServiceNames()
32 +{
33 + var registry = require('win-registry');
34 + var ret = [];
35 + var K = registry.QueryKey(registry.HKEY.LocalMachine, 'SYSTEM\\CurrentControlSet\\Services');
36 + var service, s;
37 + while (K.subkeys.length > 0)
38 + {
39 + service = K.subkeys.shift();
40 + try
41 + {
42 + s = registry.QueryKey(registry.HKEY.LocalMachine, 'SYSTEM\\CurrentControlSet\\Services\\' + service, 'ImagePath');
43 + if (s.startsWith(process.execPath) || s.startsWith('"' + process.execPath + '"'))
44 + {
45 + ret.push(service);
46 + }
47 + }
48 + catch (x)
49 + {
50 + }
51 + }
52 + return (ret);
53 +}
54 +function _verifyServiceName(names)
55 +{
56 + var i;
57 + var s;
58 + var ret = null;
59 + for (i = 0; i < names.length; ++i)
60 + {
61 + try
62 + {
63 + s = require('service-manager').manager.getService(names[i]);
64 + if (s.isMe())
65 + {
66 + ret = names[i];
67 + s.close();
68 + break;
69 + }
70 + s.close();
71 + }
72 + catch (z) { }
73 + }
74 + return (ret);
75 +}
76 +
77 +function windows_getCommandLine()
78 +{
79 + var parms = [];
80 + var GM = require('_GenericMarshal');
81 + var k32 = GM.CreateNativeProxy('kernel32.dll');
82 + var s32 = GM.CreateNativeProxy('shell32.dll');
83 + k32.CreateMethod('GetCommandLineW');
84 + k32.CreateMethod('LocalFree');
85 + s32.CreateMethod('CommandLineToArgvW');
86 + var v = k32.GetCommandLineW();
87 + var i;
88 + var len = GM.CreateVariable(4);
89 + var val = s32.CommandLineToArgvW(v, len);
90 + len = len.toBuffer().readInt32LE(0);
91 + if (len > 0)
92 + {
93 + for (i = 0; i < len; ++i)
94 + {
95 + parms.push(val.Deref(i * GM.PointerSize, GM.PointerSize).Deref().Wide2UTF8);
96 + }
97 + }
98 + k32.LocalFree(val);
99 + return (parms);
100 +}
101 +
102 +if (require('MeshAgent').ARCHID == null)
103 +{
104 var id = null;
11 - switch (process.platform) {
105 + switch (process.platform)
106 + {
107 case 'win32':
108 id = require('_GenericMarshal').PointerSize == 4 ? 3 : 4;
109 break;
@@ -16,10 +111,12 @@ if (require('MeshAgent').ARCHID == null) {
111 id = require('_GenericMarshal').PointerSize == 4 ? 31 : 30;
112 break;
113 case 'darwin':
19 - try {
114 + try
115 + {
116 id = require('os').arch() == 'x64' ? 16 : 29;
117 }
22 - catch (xx) {
118 + catch (xx)
119 + {
120 id = 16;
121 }
122 break;
@@ -29,17 +126,22 @@ if (require('MeshAgent').ARCHID == null) {
126
127 //attachDebugger({ webport: 9994, wait: 1 }).then(function (p) { console.log('Debug on port: ' + p); });
128
32 -function sendConsoleText(msg, sessionid) {
33 - if (sessionid != null) {
129 +function sendConsoleText(msg, sessionid)
130 +{
131 + if (sessionid != null)
132 + {
133 require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: msg, sessionid: sessionid });
134 }
36 - else {
135 + else
136 + {
137 require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: msg });
138 }
139 }
140
41 -function sendAgentMessage(msg, icon) {
42 - if (sendAgentMessage.messages == null) {
141 +function sendAgentMessage(msg, icon)
142 +{
143 + if (sendAgentMessage.messages == null)
144 + {
145 sendAgentMessage.messages = {};
146 sendAgentMessage.nextid = 1;
147 }
@@ -48,9 +150,11 @@ function sendAgentMessage(msg, icon) {
150 }
151
152 // Add to the server event log
51 -function MeshServerLog(msg, state) {
153 +function MeshServerLog(msg, state)
154 +{
155 if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
53 - if (state) {
156 + if (state)
157 + {
158 if (state.userid) { msg.userid = state.userid; }
159 if (state.username) { msg.username = state.username; }
160 if (state.sessionid) { msg.sessionid = state.sessionid; }
@@ -60,9 +164,11 @@ function MeshServerLog(msg, state) {
164 }
165
166 // Add to the server event log, use internationalized events
63 -function MeshServerLogEx(id, args, msg, state) {
167 +function MeshServerLogEx(id, args, msg, state)
168 +{
169 var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
65 - if (state) {
170 + if (state)
171 + {
172 if (state.userid) { msg.userid = state.userid; }
173 if (state.username) { msg.username = state.username; }
174 if (state.sessionid) { msg.sessionid = state.sessionid; }
@@ -346,6 +452,34 @@ function windows_execve(name, agentfilename, sessionid) {
452 var arg2 = require('_GenericMarshal').CreateVariable('/C wmic service "' + name + '" call stopservice & "' + cwd + agentfilename + '.update.exe" -b64exec ' + 'dHJ5CnsKICAgIHZhciBzZXJ2aWNlTG9jYXRpb24gPSBwcm9jZXNzLmFyZ3YucG9wKCk7CiAgICByZXF1aXJlKCdwcm9jZXNzLW1hbmFnZXInKS5lbnVtZXJhdGVQcm9jZXNzZXMoKS50aGVuKGZ1bmN0aW9uIChwcm9jKQogICAgewogICAgICAgIGZvciAodmFyIHAgaW4gcHJvYykKICAgICAgICB7CiAgICAgICAgICAgIGlmIChwcm9jW3BdLnBhdGggPT0gc2VydmljZUxvY2F0aW9uKQogICAgICAgICAgICB7CiAgICAgICAgICAgICAgICBwcm9jZXNzLmtpbGwocHJvY1twXS5waWQpOwogICAgICAgICAgICB9CiAgICAgICAgfQogICAgICAgIHByb2Nlc3MuZXhpdCgpOwogICAgfSk7Cn0KY2F0Y2goZSkKewogICAgcHJvY2Vzcy5leGl0KCk7Cn0=' +
453 ' "' + process.execPath + '" & copy "' + cwd + agentfilename + '.update.exe" "' + process.execPath + '" & wmic service "' + name + '" call startservice & erase "' + cwd + agentfilename + '.update.exe"', { wide: true });
454
455 + if (name == null)
456 + {
457 + // We can continue with self update for Temp/Console Mode on Windows
458 + var db = null;
459 + var update = cwd + agentfilename + '.update.exe';
460 + var updatedb = cwd + agentfilename + '.update.db';
461 + var parms = windows_getCommandLine(); parms.shift();
462 +
463 + var updatesource = parms.find(function (v) { return (v.startsWith('--updateSourcePath=')); });
464 + if (updatesource == null)
465 + {
466 + parms.push('--updateSourcePath="' + cwd + agentfilename + '"');
467 + updatesource = (cwd + agentfilename).split('.exe'); updatesource.pop(); updatesource = updatesource.join('.exe');
468 + db = updatesource + '.db';
469 + updatesource = (' & move "' + updatedb + '" "' + db + '"') + (' & erase "' + updatedb + '"');
470 + }
471 + else
472 + {
473 + updatesource = updatesource.substring(19).split('.exe');
474 + updatesource.pop(); updatesource = updatesource.join('.exe');
475 + db = updatesource + '.db';
476 + updatesource = (' & move "' + update + '" "' + updatesource + '.exe" & move "' + updatedb + '" "' + db + '" & erase "' + updatedb + '"') + (' & echo move "' + update + '" "' + updatesource + '.exe" & echo move "' + updatedb + '" "' + db + '"');
477 + }
478 +
479 + var tmp = '/C echo copy "' + db + '" "' + updatedb + '" & copy "' + db + '" "' + updatedb + '"' + ' & "' + update + '" ' + parms.join(' ') + updatesource + ' & erase "' + update + '" & echo ERASE "' + update + '"';
480 + arg2 = require('_GenericMarshal').CreateVariable(tmp, { wide: true });
481 + }
482 +
483 arg1.pointerBuffer().copy(args.toBuffer());
484 arg2.pointerBuffer().copy(args.toBuffer(), require('_GenericMarshal').PointerSize);
485
@@ -363,7 +497,8 @@ function agentUpdate_Start(updateurl, updateoptions) {
497 if (updateurl.startsWith("wss://")) { updateurl = "https://" + updateurl.substring(6); }
498 }
499
366 - if (agentUpdate_Start._selfupdate != null) {
500 + if (agentUpdate_Start._selfupdate != null)
501 + {
502 // We were already called, so we will ignore this duplicate request
503 if (sessionid != null) { sendConsoleText('Self update already in progress...', sessionid); }
504 }
@@ -373,25 +508,58 @@ function agentUpdate_Start(updateurl, updateoptions) {
508 // This agent doesn't have the ability to tell us which ARCHID it is, so we don't know which agent to pull
509 sendConsoleText('Unable to initiate update, agent ARCHID is not defined', sessionid);
510 }
376 - else {
511 + else
512 + {
513 var agentfilename = process.execPath.split(process.platform == 'win32' ? '\\' : '/').pop(); // Local File Name, ie: MeshAgent.exe
514 var name = require('MeshAgent').serviceName;
379 - if (name == null) { name = (process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'); } // This is an older agent that doesn't expose the service name, so use the default
380 - try {
381 - var s = require('service-manager').manager.getService(name);
382 - if (!s.isMe()) {
515 + if (name == null) { name = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent'; }
516 + if (process.platform == 'win32')
517 + {
518 + // Special Processing for Temporary/Console Mode Agents on Windows
519 + var parms = windows_getCommandLine();
520 + if (parms.findIndex(function (val) { return (val.toUpperCase() == 'RUN' || val.toUpperCase() == 'CONNECT');})>=0)
521 + {
522 + // This is a Temporary/Console Mode Agent
523 + sendConsoleText('This is a temporary/console agent, checking for conflicts with background services...');
524 +
525 + // Check to see if our binary conflicts with an installed agent
526 + var agents = _getPotentialServiceNames();
527 + if(_getPotentialServiceNames().length>0)
528 + {
529 + sendConsoleText('Self update cannot continue because the installed agent (' + agents[0] + ') conflicts with the currently running Temp/Console agent...', sessionid);
530 + return;
531 + }
532 +
533 +
534 + sendConsoleText('No conflicts detected...');
535 + name = null;
536 + }
537 + else
538 + {
539 + // Not running in Temp/Console Mode... No Op here....
540 + }
541 + }
542 + else
543 + {
544 + // Non Windows Self Update
545 + try
546 + {
547 + var s = require('service-manager').manager.getService(name);
548 + if (!s.isMe())
549 + {
550 + if (process.platform == 'win32') { s.close(); }
551 + sendConsoleText('Self Update cannot continue, this agent is not an instance of background service (' + name + ')', sessionid);
552 + return;
553 + }
554 if (process.platform == 'win32') { s.close(); }
384 - sendConsoleText('Self Update cannot continue, this agent is not an instance of (' + name + ')', sessionid);
555 + }
556 + catch (zz)
557 + {
558 + sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
559 + sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
560 return;
561 }
387 - if (process.platform == 'win32') { s.close(); }
388 - }
389 - catch (zz) {
390 - sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
391 - sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
392 - return;
562 }
394 -
563 if ((sessionid != null) && (updateurl != null)) { sendConsoleText('Downloading update from: ' + updateurl, sessionid); }
564 var options = require('http').parseUri(updateurl != null ? updateurl : require('MeshAgent').ServerUrl);
565 options.protocol = 'https:';
@@ -1007,7 +1175,25 @@ require('MeshAgent').AddCommandHandler(function (data) {
1175 function processConsoleCommand(cmd, args, rights, sessionid) {
1176 try {
1177 var response = null;
1010 - switch (cmd) {
1178 + switch (cmd)
1179 + {
1180 + default:
1181 + { // This is an unknown command, return an error message
1182 + response = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
1183 + break;
1184 + }
1185 + case 'commandline':
1186 + {
1187 + if (process.platform == 'win32')
1188 + {
1189 + response = JSON.stringify(windows_getCommandLine(), null, 1);
1190 + }
1191 + else
1192 + {
1193 + response = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
1194 + }
1195 + }
1196 + break;
1197 case 'help':
1198 response = "Available commands are: agentupdate, agentupdateex, dbkeys, dbget, dbset, dbcompact, eval, netinfo, osinfo, setdebug, versions.";
1199 break;
@@ -1097,10 +1283,11 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
1283 response = objToString(interfaces, 0, ' ', true);
1284 break;
1285 }
1100 - default: { // This is an unknown command, return an error message
1101 - response = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
1286 + case 'name':
1287 + {
1288 + response = 'Service Name = ' + require('MeshAgent').serviceName;
1289 + }
1290 break;
1103 - }
1291 }
1292 } catch (e) { response = "Command returned an exception error: " + e; console.log(e); }
1293 if (response != null) { sendConsoleText(response, sessionid); }