Removed mobile setup when in LAN mode.

Ylian Saint-Hilaire committed Jan 24, 2021 at 21:51 UTC a885664a4190b943f50563b6ea2e1525b908624b
5 files changed +2609 -3159
agents/meshcore.js
+674 -1329
@@ -14,8 +14,7 @@ See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 -process.on('uncaughtException', function (ex)
18 -{
17 +process.on('uncaughtException', function (ex) {
18 require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: "uncaughtException1: " + ex });
19 });
20
@@ -42,11 +41,9 @@ var MESHRIGHT_CHATNOTIFY = 16384;
41 var MESHRIGHT_UNINSTALL = 32768;
42 var MESHRIGHT_NODESKTOP = 65536;
43
45 -if (require('MeshAgent').ARCHID == null)
46 -{
44 +if (require('MeshAgent').ARCHID == null) {
45 var id = null;
48 - switch (process.platform)
49 - {
46 + switch (process.platform) {
47 case 'win32':
48 id = require('_GenericMarshal').PointerSize == 4 ? 3 : 4;
49 break;
@@ -54,12 +51,10 @@ if (require('MeshAgent').ARCHID == null)
51 id = require('_GenericMarshal').PointerSize == 4 ? 31 : 30;
52 break;
53 case 'darwin':
57 - try
58 - {
54 + try {
55 id = require('os').arch() == 'x64' ? 16 : 29;
56 }
61 - catch (xx)
62 - {
57 + catch (xx) {
58 id = 16;
59 }
60 break; break;
@@ -72,11 +67,9 @@ var agentFileHttpRequests = {}; // Currently active agent HTTPS GET requests fro
67 var agentFileHttpPendingRequests = []; // Pending HTTPS GET requests from the server.
68 var debugConsole = (_MSH().debugConsole == 1);
69
75 -if (process.platform == 'win32' && require('user-sessions').isRoot())
76 -{
70 +if (process.platform == 'win32' && require('user-sessions').isRoot()) {
71 // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
78 - try
79 - {
72 + try {
73 var writtenSize = 0, actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
74 try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { }
75 if (writtenSize != actualSize) { try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { } }
@@ -84,24 +77,20 @@ if (process.platform == 'win32' && require('user-sessions').isRoot())
77
78 // Check to see if we are the Installed Mesh Agent Service, if we are, make sure we can run in Safe Mode
79 var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
87 - try
88 - {
80 + try {
81 svcname = require('MeshAgent').serviceName;
82 }
91 - catch (x)
92 - {
83 + catch (x) {
84 }
85
95 - try
96 - {
86 + try {
87 var meshCheck = false;
88 try { meshCheck = require('service-manager').manager.getService(svcname).isMe(); } catch (e) { }
89 if (meshCheck && require('win-bcd').isSafeModeService && !require('win-bcd').isSafeModeService(svcname)) { require('win-bcd').enableSafeModeService(svcname); }
90 } catch (e) { }
91 }
92
103 -if (process.platform == 'darwin' && !process.versions)
104 -{
93 +if (process.platform == 'darwin' && !process.versions) {
94 // This is an older MacOS Agent, so we'll need to check the service definition so that Auto-Update will function correctly
95 var child = require('child_process').execFile('/bin/sh', ['sh']);
96 child.stdout.str = '';
@@ -110,21 +99,18 @@ if (process.platform == 'darwin' && !process.versions)
99 child.stdin.write(" if(c[1]==\"dict\"){ split(a[2], d, \"</dict>\"); if(split(d[1], truval, \"<true/>\")>1) { split(truval[1], kn1, \"<key>\"); split(kn1[2], kn2, \"</key>\"); print kn2[1]; } }");
100 child.stdin.write(" else { split(c[1], ka, \"/\"); if(ka[1]==\"true\") {print \"ALWAYS\";} } }'\nexit\n");
101 child.waitExit();
113 - if (child.stdout.str.trim() == 'Crashed')
114 - {
102 + if (child.stdout.str.trim() == 'Crashed') {
103 child = require('child_process').execFile('/bin/sh', ['sh']);
104 child.stdout.str = '';
105 child.stdout.on('data', function (chunk) { this.str += chunk.toString(); });
106 child.stdin.write("launchctl list | grep 'meshagent' | awk '{ if($3==\"meshagent\"){print $1;}}'\nexit\n");
107 child.waitExit();
108
121 - if (parseInt(child.stdout.str.trim()) == process.pid)
122 - {
109 + if (parseInt(child.stdout.str.trim()) == process.pid) {
110 // The currently running MeshAgent is us, so we can continue with the update
111 var plist = require('fs').readFileSync('/Library/LaunchDaemons/meshagent_osx64_LaunchDaemon.plist').toString();
112 var tokens = plist.split('<key>KeepAlive</key>');
126 - if (tokens[1].split('>')[0].split('<')[1] == 'dict')
127 - {
113 + if (tokens[1].split('>')[0].split('<')[1] == 'dict') {
114 var tmp = tokens[1].split('</dict>');
115 tmp.shift();
116 tokens[1] = '\n <true/>' + tmp.join('</dict>');
@@ -180,8 +166,7 @@ if (process.platform == 'darwin' && !process.versions)
166 }
167
168 // Add an Intel AMT event to the log
183 -function addAmtEvent(msg)
184 -{
169 +function addAmtEvent(msg) {
170 if (obj.amtevents == null) { obj.amtevents = []; }
171 var d = new Date();
172 obj.amtevents.push(zeroPad(d.getHours(), 2) + ':' + zeroPad(d.getMinutes(), 2) + ':' + zeroPad(d.getSeconds(), 2) + ', ' + msg);
@@ -196,10 +181,8 @@ if (process.platform != 'win32') { try { require('fs').unlinkSync(process.cwd()
181 obj.DAIPC.IPCPATH = process.platform == 'win32' ? ('\\\\.\\pipe\\' + require('_agentNodeId')() + '-DAIPC') : (process.cwd() + '/DAIPC');
182 try { obj.DAIPC.listen({ path: obj.DAIPC.IPCPATH, writableAll: true, maxConnections: 5 }); } catch (e) { }
183 obj.DAIPC._daipc = [];
199 -obj.DAIPC.on('connection', function (c)
200 -{
201 - c._send = function (j)
202 - {
184 +obj.DAIPC.on('connection', function (c) {
185 + c._send = function (j) {
186 var data = JSON.stringify(j);
187 var packet = Buffer.alloc(data.length + 4);
188 packet.writeUInt32LE(data.length + 4, 0);
@@ -209,8 +192,7 @@ obj.DAIPC.on('connection', function (c)
192 this._daipc.push(c);
193 c.parent = this;
194 c.on('end', function () { removeRegisteredApp(this); });
212 - c.on('data', function (chunk)
213 - {
195 + c.on('data', function (chunk) {
196 if (chunk.length < 4) { this.unshift(chunk); return; }
197 var len = chunk.readUInt32LE(0);
198 if (len > 8192) { removeRegisteredApp(this); this.end(); return; }
@@ -220,10 +202,8 @@ obj.DAIPC.on('connection', function (c)
202 try { data = JSON.parse(data.toString()); } catch (e) { }
203 if ((data == null) || (typeof data.cmd != 'string')) return;
204
223 - try
224 - {
225 - switch (data.cmd)
226 - {
205 + try {
206 + switch (data.cmd) {
207 case 'requesthelp':
208 if (this._registered == null) return;
209 sendConsoleText('Request Help (' + this._registered + '): ' + data.value);
@@ -238,8 +218,7 @@ obj.DAIPC.on('connection', function (c)
218 try { mesh.SendCommand({ action: 'sessions', type: 'help', value: {} }); } catch (e) { }
219 break;
220 case 'register':
241 - if (typeof data.value == 'string')
242 - {
221 + if (typeof data.value == 'string') {
222 this._registered = data.value;
223 var apps = {};
224 apps[data.value] = 1;
@@ -248,15 +227,13 @@ obj.DAIPC.on('connection', function (c)
227 }
228 break;
229 case 'query':
251 - switch (data.value)
252 - {
230 + switch (data.value) {
231 case 'connection':
232 data.result = require('MeshAgent').ConnectedServer;
233 this._send(data);
234 break;
235 case 'descriptors':
258 - require('ChainViewer').getSnapshot().then(function (f)
259 - {
236 + require('ChainViewer').getSnapshot().then(function (f) {
237 this.tag.payload.result = f;
238 this.tag.ipc._send(this.tag.payload);
239 }).parentPromise.tag = { ipc: this, payload: data };
@@ -280,8 +257,7 @@ obj.DAIPC.on('connection', function (c)
257 try { mesh.SendCommand({ action: 'meshToolInfo', name: data.name, hash: data.hash, cookie: data.cookie ? true : false, pipe: true }); } catch (e) { }
258 break;
259 case 'console':
283 - if (debugConsole)
284 - {
260 + if (debugConsole) {
261 var args = splitArgs(data.value);
262 processConsoleCommand(args[0].toLowerCase(), parseArgs(args), 0, 'pipe');
263 }
@@ -293,28 +269,24 @@ obj.DAIPC.on('connection', function (c)
269 });
270
271 // Send current sessions to registered apps
296 -function broadcastSessionsToRegisteredApps(x)
297 -{
272 +function broadcastSessionsToRegisteredApps(x) {
273 broadcastToRegisteredApps({ cmd: 'sessions', sessions: tunnelUserCount });
274 }
275
276 // Send this object to all registered local applications
302 -function broadcastToRegisteredApps(x)
303 -{
277 +function broadcastToRegisteredApps(x) {
278 if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
279 for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered != null) { obj.DAIPC._daipc[i]._send(x); } }
280 }
281
282 // Send this object to a specific registered local applications
309 -function sendToRegisteredApp(appid, x)
310 -{
283 +function sendToRegisteredApp(appid, x) {
284 if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
285 for (var i in obj.DAIPC._daipc) { if (obj.DAIPC._daipc[i]._registered == appid) { obj.DAIPC._daipc[i]._send(x); } }
286 }
287
288 // Send list of registered apps to the server
316 -function updateRegisteredAppsToServer()
317 -{
289 +function updateRegisteredAppsToServer() {
290 if ((obj.DAIPC == null) || (obj.DAIPC._daipc == null)) return;
291 var apps = {};
292 for (var i in obj.DAIPC._daipc) { if (apps[obj.DAIPC._daipc[i]._registered] == null) { apps[obj.DAIPC._daipc[i]._registered] = 1; } else { apps[obj.DAIPC._daipc[i]._registered]++; } }
@@ -322,32 +294,26 @@ function updateRegisteredAppsToServer()
294 }
295
296 // Remove a registered app
325 -function removeRegisteredApp(pipe)
326 -{
297 +function removeRegisteredApp(pipe) {
298 for (var i = obj.DAIPC._daipc.length - 1; i >= 0; i--) { if (obj.DAIPC._daipc[i] === pipe) { obj.DAIPC._daipc.splice(i, 1); } }
299 if (pipe._registered != null) updateRegisteredAppsToServer();
300 }
301
331 -function diagnosticAgent_uninstall()
332 -{
302 +function diagnosticAgent_uninstall() {
303 require('service-manager').manager.uninstallService('meshagentDiagnostic');
304 require('task-scheduler').delete('meshagentDiagnostic/periodicStart');
305 }
336 -function diagnosticAgent_installCheck(install)
337 -{
338 - try
339 - {
306 +function diagnosticAgent_installCheck(install) {
307 + try {
308 var diag = require('service-manager').manager.getService('meshagentDiagnostic');
309 return (diag);
310 }
343 - catch (e)
344 - {
311 + catch (e) {
312 }
313 if (!install) { return (null); }
314
315 var svc = null;
349 - try
350 - {
316 + try {
317 require('service-manager').manager.installService(
318 {
319 name: 'meshagentDiagnostic',
@@ -359,8 +325,7 @@ function diagnosticAgent_installCheck(install)
325 });
326 svc = require('service-manager').manager.getService('meshagentDiagnostic');
327 }
362 - catch (e)
363 - {
328 + catch (e) {
329 return (null);
330 }
331 var proxyConfig = require('global-tunnel').proxyConfig;
@@ -373,12 +338,10 @@ function diagnosticAgent_installCheck(install)
338 ddb.Put('MeshServer', require('MeshAgent').ServerInfo.ServerUri);
339 if (cert.root.pfx) { ddb.Put('SelfNodeCert', cert.root.pfx); }
340 if (cert.tls) { ddb.Put('SelfNodeTlsCert', cert.tls.pfx); }
376 - if (proxyConfig)
377 - {
341 + if (proxyConfig) {
342 ddb.Put('WebProxy', proxyConfig.host + ':' + proxyConfig.port);
343 }
380 - else
381 - {
344 + else {
345 ddb.Put('ignoreProxyFile', '1');
346 }
347
@@ -395,24 +358,18 @@ function diagnosticAgent_installCheck(install)
358 }
359
360 // Monitor the file 'batterystate.txt' in the agent's folder and sends battery update when this file is changed.
398 -if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('fs').watch != null))
399 -{
361 +if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('fs').watch != null)) {
362 // Setup manual battery monitoring
401 - require('MeshAgent')._batteryFileWatcher = require('fs').watch(process.cwd(), function ()
402 - {
363 + require('MeshAgent')._batteryFileWatcher = require('fs').watch(process.cwd(), function () {
364 if (require('MeshAgent')._batteryFileTimer != null) return;
404 - require('MeshAgent')._batteryFileTimer = setTimeout(function ()
405 - {
406 - try
407 - {
365 + require('MeshAgent')._batteryFileTimer = setTimeout(function () {
366 + try {
367 require('MeshAgent')._batteryFileTimer = null;
368 var data = null;
369 try { data = require('fs').readFileSync(process.cwd() + 'batterystate.txt').toString(); } catch (e) { }
411 - if ((data != null) && (data.length < 10))
412 - {
370 + if ((data != null) && (data.length < 10)) {
371 data = data.split(',');
414 - if ((data.length == 2) && ((data[0] == 'ac') || (data[0] == 'dc')))
415 - {
372 + if ((data.length == 2) && ((data[0] == 'ac') || (data[0] == 'dc'))) {
373 var level = parseInt(data[1]);
374 if ((level >= 0) && (level <= 100)) { require('MeshAgent').SendCommand({ action: 'battery', state: data[0], level: level }); }
375 }
@@ -421,31 +378,24 @@ if ((require('fs').existsSync(process.cwd() + 'batterystate.txt')) && (require('
378 }, 1000);
379 });
380 }
424 -else
425 -{
381 +else {
382 // Setup normal battery monitoring
427 - if (require('identifiers').isBatteryPowered && require('identifiers').isBatteryPowered())
428 - {
429 - require('MeshAgent')._battLevelChanged = function _battLevelChanged(val)
430 - {
383 + if (require('identifiers').isBatteryPowered && require('identifiers').isBatteryPowered()) {
384 + require('MeshAgent')._battLevelChanged = function _battLevelChanged(val) {
385 _battLevelChanged.self._currentBatteryLevel = val;
386 _battLevelChanged.self.SendCommand({ action: 'battery', state: _battLevelChanged.self._currentPowerState, level: val });
387 };
388 require('MeshAgent')._battLevelChanged.self = require('MeshAgent');
435 - require('MeshAgent')._powerChanged = function _powerChanged(val)
436 - {
389 + require('MeshAgent')._powerChanged = function _powerChanged(val) {
390 _powerChanged.self._currentPowerState = (val == 'AC' ? 'ac' : 'dc');
391 _powerChanged.self.SendCommand({ action: 'battery', state: (val == 'AC' ? 'ac' : 'dc'), level: _powerChanged.self._currentBatteryLevel });
392 };
393 require('MeshAgent')._powerChanged.self = require('MeshAgent');
441 - require('MeshAgent').on('Connected', function (status)
442 - {
443 - if (status == 0)
444 - {
394 + require('MeshAgent').on('Connected', function (status) {
395 + if (status == 0) {
396 require('power-monitor').removeListener('acdc', this._powerChanged);
397 require('power-monitor').removeListener('batteryLevel', this._battLevelChanged);
447 - } else
448 - {
398 + } else {
399 require('power-monitor').on('acdc', this._powerChanged);
400 require('power-monitor').on('batteryLevel', this._battLevelChanged);
401 }
@@ -462,30 +412,23 @@ try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreO
412
413
414 // Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
465 -try
466 -{
415 +try {
416 var userSession = require('user-sessions');
468 - userSession.on('changed', function onUserSessionChanged()
469 - {
470 - userSession.enumerateUsers().then(function (users)
471 - {
472 - if (process.platform == 'linux')
473 - {
474 - if (userSession._startTime == null)
475 - {
417 + userSession.on('changed', function onUserSessionChanged() {
418 + userSession.enumerateUsers().then(function (users) {
419 + if (process.platform == 'linux') {
420 + if (userSession._startTime == null) {
421 userSession._startTime = Date.now();
422 userSession._count = users.length;
423 }
479 - else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count)
480 - {
424 + else if (Date.now() - userSession._startTime < 10000 && users.length == userSession._count) {
425 userSession.removeAllListeners('changed');
426 return;
427 }
428 }
429
430 var u = [], a = users.Active;
487 - for (var i = 0; i < a.length; i++)
488 - {
431 + for (var i = 0; i < a.length; i++) {
432 var un = a[i].Domain ? (a[i].Domain + '\\' + a[i].Username) : (a[i].Username);
433 if (u.indexOf(un) == -1) { u.push(un); } // Only push users in the list once.
434 }
@@ -517,11 +460,9 @@ var apftunnel = null;
460 var tunnelUserCount = { terminal: {}, files: {}, tcp: {}, udp: {}, msg: {} }; // List of userid->count sessions for terminal, files and TCP/UDP routing
461
462 // Add to the server event log
520 -function MeshServerLog(msg, state)
521 -{
463 +function MeshServerLog(msg, state) {
464 if (typeof msg == 'string') { msg = { action: 'log', msg: msg }; } else { msg.action = 'log'; }
523 - if (state)
524 - {
465 + if (state) {
466 if (state.userid) { msg.userid = state.userid; }
467 if (state.username) { msg.username = state.username; }
468 if (state.sessionid) { msg.sessionid = state.sessionid; }
@@ -531,11 +472,9 @@ function MeshServerLog(msg, state)
472 }
473
474 // Add to the server event log, use internationalized events
534 -function MeshServerLogEx(id, args, msg, state)
535 -{
475 +function MeshServerLogEx(id, args, msg, state) {
476 var msg = { action: 'log', msgid: id, msgArgs: args, msg: msg };
537 - if (state)
538 - {
477 + if (state) {
478 if (state.userid) { msg.userid = state.userid; }
479 if (state.username) { msg.username = state.username; }
480 if (state.sessionid) { msg.sessionid = state.sessionid; }
@@ -550,16 +489,12 @@ sha = require('SHA256Stream');
489 mesh = require('MeshAgent');
490 childProcess = require('child_process');
491
553 -if (mesh.hasKVM == 1)
554 -{ // if the agent is compiled with KVM support
492 +if (mesh.hasKVM == 1) { // if the agent is compiled with KVM support
493 // Check if this computer supports a desktop
556 - try
557 - {
558 - if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support))
559 - {
494 + try {
495 + if ((process.platform == 'win32') || (process.platform == 'darwin') || (require('monitor-info').kvm_x11_support)) {
496 meshCoreObj.caps |= 1; meshCoreObjChanged();
561 - } else if (process.platform == 'linux' || process.platform == 'freebsd')
562 - {
497 + } else if (process.platform == 'linux' || process.platform == 'freebsd') {
498 require('monitor-info').on('kvmSupportDetected', function (value) { meshCoreObj.caps |= 1; meshCoreObjChanged(); });
499 }
500 } catch (e) { }
@@ -579,23 +514,18 @@ try {
514 // Fetch the SMBios Tables
515 var SMBiosTables = null;
516 var SMBiosTablesRaw = null;
582 -try
583 -{
517 +try {
518 var SMBiosModule = null;
519 try { SMBiosModule = require('smbios'); } catch (e) { }
586 - if (SMBiosModule != null)
587 - {
588 - SMBiosModule.get(function (data)
589 - {
590 - if (data != null)
591 - {
520 + if (SMBiosModule != null) {
521 + SMBiosModule.get(function (data) {
522 + if (data != null) {
523 SMBiosTablesRaw = data;
524 SMBiosTables = require('smbios').parse(data)
525 if (mesh.isControlChannelConnected) { mesh.SendCommand({ action: 'smbios', value: SMBiosTablesRaw }); }
526
527 // If SMBios tables say that Intel AMT is present, try to connect MEI
597 - if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true))
598 - {
528 + if (SMBiosTables.amtInfo && (SMBiosTables.amtInfo.AMT == true)) {
529 var amtmodule = require('amt-manage');
530 amt = new amtmodule(mesh, db, false);
531 amt.on('portBinding_LMS', function (map) { mesh.SendCommand({ action: 'lmsinfo', value: { ports: map.keys() } }); });
@@ -609,8 +539,7 @@ try
539 } catch (e) { sendConsoleText("ex1: " + e); }
540
541 // Try to load up the WIFI scanner
612 -try
613 -{
542 +try {
543 var wifiScannerLib = require('wifi-scanner');
544 wifiScanner = new wifiScannerLib();
545 wifiScanner.on('accessPoint', function (data) { sendConsoleText("wifiScanner: " + data); });
@@ -619,28 +548,21 @@ try
548 // Get our location (lat/long) using our public IP address
549 var getIpLocationDataExInProgress = false;
550 var getIpLocationDataExCounts = [0, 0];
622 -function getIpLocationDataEx(func)
623 -{
551 +function getIpLocationDataEx(func) {
552 if (getIpLocationDataExInProgress == true) { return false; }
625 - try
626 - {
553 + try {
554 getIpLocationDataExInProgress = true;
555 getIpLocationDataExCounts[0]++;
556 var options = http.parseUri("http://ipinfo.io/json");
557 options.method = 'GET';
631 - http.request(options, function (resp)
632 - {
633 - if (resp.statusCode == 200)
634 - {
558 + http.request(options, function (resp) {
559 + if (resp.statusCode == 200) {
560 var geoData = '';
561 resp.data = function (geoipdata) { geoData += geoipdata; };
637 - resp.end = function ()
638 - {
562 + resp.end = function () {
563 var location = null;
640 - try
641 - {
642 - if (typeof geoData == 'string')
643 - {
564 + try {
565 + if (typeof geoData == 'string') {
566 var result = JSON.parse(geoData);
567 if (result.ip && result.loc) { location = result; }
568 }
@@ -657,61 +579,49 @@ function getIpLocationDataEx(func)
579 }
580
581 // Remove all Gateway MAC addresses for interface list. This is useful because the gateway MAC is not always populated reliably.
660 -function clearGatewayMac(str)
661 -{
582 +function clearGatewayMac(str) {
583 if (str == null) return null;
584 var x = JSON.parse(str);
585 for (var i in x.netif) { if (x.netif[i].gatewaymac) { delete x.netif[i].gatewaymac } }
586 return JSON.stringify(x);
587 }
588
668 -function getIpLocationData(func)
669 -{
589 +function getIpLocationData(func) {
590 // Get the location information for the cache if possible
591 var publicLocationInfo = db.Get('publicLocationInfo');
592 if (publicLocationInfo != null) { publicLocationInfo = JSON.parse(publicLocationInfo); }
673 - if (publicLocationInfo == null)
674 - {
593 + if (publicLocationInfo == null) {
594 // Nothing in the cache, fetch the data
676 - getIpLocationDataEx(function (locationData)
677 - {
678 - if (locationData != null)
679 - {
595 + getIpLocationDataEx(function (locationData) {
596 + if (locationData != null) {
597 publicLocationInfo = {};
598 publicLocationInfo.netInfoStr = lastNetworkInfo;
599 publicLocationInfo.locationData = locationData;
600 var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
601 if (func) func(locationData); // Report the new location
602 }
686 - else
687 - {
603 + else {
604 if (func) func(null); // Report no location
605 }
606 });
607 }
692 - else
693 - {
608 + else {
609 // Check the cache
695 - if (clearGatewayMac(publicLocationInfo.netInfoStr) == clearGatewayMac(lastNetworkInfo))
696 - {
610 + if (clearGatewayMac(publicLocationInfo.netInfoStr) == clearGatewayMac(lastNetworkInfo)) {
611 // Cache match
612 if (func) func(publicLocationInfo.locationData);
613 }
700 - else
701 - {
614 + else {
615 // Cache mismatch
703 - getIpLocationDataEx(function (locationData)
704 - {
705 - if (locationData != null)
706 - {
616 + getIpLocationDataEx(function (locationData) {
617 + if (locationData != null) {
618 publicLocationInfo = {};
619 publicLocationInfo.netInfoStr = lastNetworkInfo;
620 publicLocationInfo.locationData = locationData;
621 var x = db.Put('publicLocationInfo', JSON.stringify(publicLocationInfo)); // Save to database
622 if (func) func(locationData); // Report the new location
623 }
713 - else
714 - {
624 + else {
625 if (func) func(publicLocationInfo.locationData); // Can't get new location, report the old location
626 }
627 });
@@ -720,10 +630,8 @@ function getIpLocationData(func)
630 }
631
632 // Polyfill String.endsWith
723 -if (!String.prototype.endsWith)
724 -{
725 - String.prototype.endsWith = function (searchString, position)
726 - {
633 +if (!String.prototype.endsWith) {
634 + String.prototype.endsWith = function (searchString, position) {
635 var subjectString = this.toString();
636 if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) { position = subjectString.length; }
637 position -= searchString.length;
@@ -735,17 +643,13 @@ if (!String.prototype.endsWith)
643 // Polyfill path.join
644 obj.path =
645 {
738 - join: function ()
739 - {
646 + join: function () {
647 var x = [];
741 - for (var i in arguments)
742 - {
648 + for (var i in arguments) {
649 var w = arguments[i];
744 - if (w != null)
745 - {
650 + if (w != null) {
651 while (w.endsWith('/') || w.endsWith('\\')) { w = w.substring(0, w.length - 1); }
747 - if (i != 0)
748 - {
652 + if (i != 0) {
653 while (w.startsWith('/') || w.startsWith('\\')) { w = w.substring(1); }
654 }
655 x.push(w);
@@ -769,8 +673,7 @@ function rstr2hex(input) { var r = '', i; for (i = 0; i < input.length; i++) { r
673 function buf2rstr(buf) { var r = ''; for (var i = 0; i < buf.length; i++) { r += String.fromCharCode(buf[i]); } return r; }
674
675 // Convert a hex string to a raw string // TODO: Do this using Buffer(), will be MUCH faster
772 -function hex2rstr(d)
773 -{
676 +function hex2rstr(d) {
677 if (typeof d != "string" || d.length == 0) return '';
678 var r = '', m = ('' + d).match(/../g), t;
679 while (t = m.shift()) r += String.fromCharCode('0x' + t);
@@ -778,8 +681,7 @@ function hex2rstr(d)
681 }
682
683 // Convert an object to string with all functions
781 -function objToString(x, p, pad, ret)
782 -{
684 +function objToString(x, p, pad, ret) {
685 if (ret == undefined) ret = '';
686 if (p == undefined) p = 0;
687 if (x == null) { return '[null]'; }
@@ -797,26 +699,21 @@ function objToString(x, p, pad, ret)
699 function addPad(p, ret) { var r = ''; for (var i = 0; i < p; i++) { r += ret; } return r; }
700
701 // Split a string taking into account the quoats. Used for command line parsing
800 -function splitArgs(str)
801 -{
702 +function splitArgs(str) {
703 var myArray = [], myRegexp = /[^\s"]+|"([^"]*)"/gi;
704 do { var match = myRegexp.exec(str); if (match != null) { myArray.push(match[1] ? match[1] : match[0]); } } while (match != null);
705 return myArray;
706 }
707
708 // Parse arguments string array into an object
808 -function parseArgs(argv)
809 -{
709 +function parseArgs(argv) {
710 var results = { '_': [] }, current = null;
811 - for (var i = 1, len = argv.length; i < len; i++)
812 - {
711 + for (var i = 1, len = argv.length; i < len; i++) {
712 var x = argv[i];
814 - if (x.length > 2 && x[0] == '-' && x[1] == '-')
815 - {
713 + if (x.length > 2 && x[0] == '-' && x[1] == '-') {
714 if (current != null) { results[current] = true; }
715 current = x.substring(2);
818 - } else
819 - {
716 + } else {
717 if (current != null) { results[current] = toNumberIfNumber(x); current = null; } else { results['_'].push(toNumberIfNumber(x)); }
718 }
719 }
@@ -825,8 +722,7 @@ function parseArgs(argv)
722 }
723
724 // Get server target url with a custom path
828 -function getServerTargetUrl(path)
829 -{
725 +function getServerTargetUrl(path) {
726 var x = mesh.ServerUrl;
727 //sendConsoleText("mesh.ServerUrl: " + mesh.ServerUrl);
728 if (x == null) { return null; }
@@ -837,35 +733,27 @@ function getServerTargetUrl(path)
733 }
734
735 // Get server url. If the url starts with "*/..." change it, it not use the url as is.
840 -function getServerTargetUrlEx(url)
841 -{
736 +function getServerTargetUrlEx(url) {
737 if (url.substring(0, 2) == '*/') { return getServerTargetUrl(url.substring(2)); }
738 return url;
739 }
740
741 // Send a wake-on-lan packet
847 -function sendWakeOnLan(hexMac)
848 -{
742 +function sendWakeOnLan(hexMac) {
743 hexMac = hexMac.split(':').join('');
744 var count = 0;
851 - try
852 - {
745 + try {
746 var interfaces = require('os').networkInterfaces();
747 var magic = 'FFFFFFFFFFFF';
748 for (var x = 1; x <= 16; ++x) { magic += hexMac; }
749 var magicbin = Buffer.from(magic, 'hex');
750
858 - for (var adapter in interfaces)
859 - {
860 - if (interfaces.hasOwnProperty(adapter))
861 - {
862 - for (var i = 0; i < interfaces[adapter].length; ++i)
863 - {
751 + for (var adapter in interfaces) {
752 + if (interfaces.hasOwnProperty(adapter)) {
753 + for (var i = 0; i < interfaces[adapter].length; ++i) {
754 var addr = interfaces[adapter][i];
865 - if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00'))
866 - {
867 - try
868 - {
755 + if ((addr.family == 'IPv4') && (addr.mac != '00:00:00:00:00:00')) {
756 + try {
757 var socket = require('dgram').createSocket({ type: 'udp4' });
758 socket.bind({ address: addr.address });
759 socket.setBroadcast(true);
@@ -885,22 +773,17 @@ function sendWakeOnLan(hexMac)
773 }
774
775 // Handle a mesh agent command
888 -function handleServerCommand(data)
889 -{
890 - if (typeof data == 'object')
891 - {
776 +function handleServerCommand(data) {
777 + if (typeof data == 'object') {
778 // If this is a console command, parse it and call the console handler
893 - switch (data.action)
894 - {
779 + switch (data.action) {
780 case 'agentupdate':
781 agentUpdate_Start(data.url, { hash: data.hash, tlshash: data.servertlshash, sessionid: data.sessionid });
782 break;
783 case 'msg': {
899 - switch (data.type)
900 - {
784 + switch (data.type) {
785 case 'console': { // Process a console command
902 - if (data.value && data.sessionid)
903 - {
786 + if (data.value && data.sessionid) {
787 MeshServerLogEx(17, [data.value], "Processing console command: " + data.value, data);
788 var args = splitArgs(data.value);
789 processConsoleCommand(args[0].toLowerCase(), parseArgs(args), data.rights, data.sessionid);
@@ -908,12 +791,10 @@ function handleServerCommand(data)
791 break;
792 }
793 case 'tunnel': {
911 - if (data.value != null)
912 - { // Process a new tunnel connection request
794 + if (data.value != null) { // Process a new tunnel connection request
795 // Create a new tunnel object
796 var xurl = getServerTargetUrlEx(data.value);
915 - if (xurl != null)
916 - {
797 + if (xurl != null) {
798 xurl = xurl.split('$').join('%24').split('@').join('%40'); // Escape the $ and @ characters
799 var woptions = http.parseUri(xurl);
800 woptions.perMessageDeflate = false;
@@ -921,8 +802,7 @@ function handleServerCommand(data)
802
803 // Perform manual server TLS certificate checking based on the certificate hash given by the server.
804 woptions.rejectUnauthorized = 0;
924 - woptions.checkServerIdentity = function checkServerIdentity(certs)
925 - {
805 + woptions.checkServerIdentity = function checkServerIdentity(certs) {
806 // If the tunnel certificate matches the control channel certificate, accept the connection
807 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
808 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
@@ -965,8 +845,7 @@ function handleServerCommand(data)
845 }
846 case 'messagebox': {
847 // Display a message box
968 - if (data.title && data.msg)
969 - {
848 + if (data.title && data.msg) {
849 MeshServerLogEx(18, [data.title, data.msg], "Displaying message box, title=" + data.title + ", message=" + data.msg, data);
850 data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
851 try { require('message-box').create(data.title, data.msg, 120); } catch (e) { }
@@ -975,10 +854,8 @@ function handleServerCommand(data)
854 }
855 case 'ps': {
856 // Return the list of running processes
978 - if (data.sessionid)
979 - {
980 - processManager.getProcesses(function (plist)
981 - {
857 + if (data.sessionid) {
858 + processManager.getProcesses(function (plist) {
859 mesh.SendCommand({ action: 'msg', type: 'ps', value: JSON.stringify(plist), sessionid: data.sessionid });
860 });
861 }
@@ -986,8 +863,7 @@ function handleServerCommand(data)
863 }
864 case 'pskill': {
865 // Kill a process
989 - if (data.value)
990 - {
866 + if (data.value) {
867 MeshServerLogEx(19, [data.value], "Killing process " + data.value, data);
868 try { process.kill(data.value); } catch (e) { sendConsoleText("pskill: " + JSON.stringify(e)); }
869 }
@@ -1002,8 +878,7 @@ function handleServerCommand(data)
878 }
879 case 'serviceStop': {
880 // Stop a service
1005 - try
1006 - {
881 + try {
882 var service = require('service-manager').manager.getService(data.serviceName);
883 if (service != null) { service.stop(); }
884 } catch (e) { }
@@ -1011,8 +886,7 @@ function handleServerCommand(data)
886 }
887 case 'serviceStart': {
888 // Start a service
1014 - try
1015 - {
889 + try {
890 var service = require('service-manager').manager.getService(data.serviceName);
891 if (service != null) { service.start(); }
892 } catch (e) { }
@@ -1020,8 +894,7 @@ function handleServerCommand(data)
894 }
895 case 'serviceRestart': {
896 // Restart a service
1023 - try
1024 - {
897 + try {
898 var service = require('service-manager').manager.getService(data.serviceName);
899 if (service != null) { service.restart(); }
900 } catch (e) { }
@@ -1030,16 +903,12 @@ function handleServerCommand(data)
903 case 'deskBackground':
904 {
905 // Toggle desktop background
1033 - try
1034 - {
1035 - if (process.platform == 'win32')
1036 - {
906 + try {
907 + if (process.platform == 'win32') {
908 var stype = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
909 var sid = undefined;
1039 - if (stype == 1)
1040 - {
1041 - if (require('MeshAgent')._tsid != null)
1042 - {
910 + if (stype == 1) {
911 + if (require('MeshAgent')._tsid != null) {
912 stype = 5;
913 sid = require('MeshAgent')._tsid;
914 }
@@ -1055,15 +924,13 @@ function handleServerCommand(data)
924 child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
925 child.stderr.on('data', function () { });
926 child.waitExit();
1058 - } else
1059 - {
927 + } else {
928 var id = require('user-sessions').consoleUid();
929 var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
930 if (current != '/dev/null') { require('MeshAgent')._wallpaper = current; }
931 require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
932 }
1065 - } catch (e)
1066 - {
933 + } catch (e) {
934 sendConsoleText(e);
935 }
936 break;
@@ -1078,22 +945,16 @@ function handleServerCommand(data)
945 case 'getclip': {
946 // Send the load clipboard back to the user
947 //sendConsoleText('getClip: ' + JSON.stringify(data));
1081 - if (require('MeshAgent').isService)
1082 - {
1083 - require('clipboard').dispatchRead().then(function (str)
1084 - {
1085 - if (str)
1086 - {
948 + if (require('MeshAgent').isService) {
949 + require('clipboard').dispatchRead().then(function (str) {
950 + if (str) {
951 MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
952 mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
953 }
954 });
1091 - } else
1092 - {
1093 - require("clipboard").read().then(function (str)
1094 - {
1095 - if (str)
1096 - {
955 + } else {
956 + require("clipboard").read().then(function (str) {
957 + if (str) {
958 MeshServerLogEx(21, [str.length], "Getting clipboard content, " + str.length + " byte(s)", data);
959 mesh.SendCommand({ action: 'msg', type: 'getclip', sessionid: data.sessionid, data: str, tag: data.tag });
960 }
@@ -1104,8 +965,7 @@ function handleServerCommand(data)
965 case 'setclip': {
966 // Set the load clipboard to a user value
967 sendConsoleText('setClip: ' + JSON.stringify(data));
1107 - if (typeof data.data == 'string')
1108 - {
968 + if (typeof data.data == 'string') {
969 MeshServerLogEx(22, [data.data.length], "Setting clipboard content, " + data.data.length + " byte(s)", data);
970 if (require('MeshAgent').isService) { require('clipboard').dispatchWrite(data.data); } else { require("clipboard")(data.data); } // Set the clipboard
971 mesh.SendCommand({ action: 'msg', type: 'setclip', sessionid: data.sessionid, success: true });
@@ -1126,8 +986,7 @@ function handleServerCommand(data)
986 var cpuuse = require('sysinfo').cpuUtilization();
987 cpuuse.sessionid = data.sessionid;
988 cpuuse.tag = data.tag;
1129 - cpuuse.then(function (data)
1130 - {
989 + cpuuse.then(function (data) {
990 mesh.SendCommand(JSON.stringify(
991 {
992 action: 'msg',
@@ -1152,8 +1011,7 @@ function handleServerCommand(data)
1011 break;
1012 }
1013 case 'acmactivate': {
1155 - if (amt != null)
1156 - {
1014 + if (amt != null) {
1015 MeshServerLogEx(23, null, "Attempting Intel AMT ACM mode activation", data);
1016 amt.setAcmResponse(data);
1017 }
@@ -1171,21 +1029,17 @@ function handleServerCommand(data)
1029
1030 // data.runAsUser: 0=Agent,1=UserOrAgent,2=UserOnly
1031 var options = {};
1174 - if (data.runAsUser > 0)
1175 - {
1032 + if (data.runAsUser > 0) {
1033 try { options.uid = require('user-sessions').consoleUid(); } catch (e) { }
1034 options.type = require('child_process').SpawnTypes.TERM;
1035 }
1179 - if (data.runAsUser == 2)
1180 - {
1036 + if (data.runAsUser == 2) {
1037 if (options.uid == null) break;
1038 if (((require('user-sessions').minUid != null) && (options.uid < require('user-sessions').minUid()))) break; // This command can only run as user.
1039 }
1040
1185 - if (process.platform == 'win32')
1186 - {
1187 - if (data.type == 1)
1188 - {
1041 + if (process.platform == 'win32') {
1042 + if (data.type == 1) {
1043 // Windows command shell
1044 mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd'], options);
1045 mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
@@ -1193,8 +1047,7 @@ function handleServerCommand(data)
1047 mesh.cmdchild.stderr.on('data', function (c) { sendConsoleText(c.toString()); });
1048 mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1049 mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1196 - } else if (data.type == 2)
1197 - {
1050 + } else if (data.type == 2) {
1051 // Windows Powershell
1052 mesh.cmdchild = require('child_process').execFile(process.env['windir'] + '\\System32\\WindowsPowerShell\\v1.0\\powershell.exe', ['powershell', '-noprofile', '-nologo', '-command', '-'], options);
1053 mesh.cmdchild.descriptorMetadata = 'UserCommandsPowerShell';
@@ -1203,8 +1056,7 @@ function handleServerCommand(data)
1056 mesh.cmdchild.stdin.write(data.cmds + '\r\nexit\r\n');
1057 mesh.cmdchild.on('exit', function () { sendConsoleText("Run commands completed."); delete mesh.cmdchild; });
1058 }
1206 - } else if (data.type == 3)
1207 - {
1059 + } else if (data.type == 3) {
1060 // Linux shell
1061 mesh.cmdchild = require('child_process').execFile('/bin/sh', ['sh'], options);
1062 mesh.cmdchild.descriptorMetadata = 'UserCommandsShell';
@@ -1218,16 +1070,13 @@ function handleServerCommand(data)
1070 case 'uninstallagent':
1071 // Uninstall this agent
1072 var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
1221 - try
1222 - {
1073 + try {
1074 agentName = require('MeshAgent').serviceName;
1075 }
1225 - catch (x)
1226 - {
1076 + catch (x) {
1077 }
1078
1229 - if (require('service-manager').manager.getService(agentName).isMe())
1230 - {
1079 + if (require('service-manager').manager.getService(agentName).isMe()) {
1080 try { diagnosticAgent_uninstall(); } catch (e) { }
1081 var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
1082 this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true });
@@ -1235,8 +1084,7 @@ function handleServerCommand(data)
1084 break;
1085 case 'poweraction': {
1086 // Server telling us to execute a power action
1238 - if ((mesh.ExecPowerState != undefined) && (data.actiontype))
1239 - {
1087 + if ((mesh.ExecPowerState != undefined) && (data.actiontype)) {
1088 var forced = 0;
1089 if (data.forced == 1) { forced = 1; }
1090 data.actiontype = parseInt(data.actiontype);
@@ -1254,8 +1102,7 @@ function handleServerCommand(data)
1102 }
1103 case 'toast': {
1104 // Display a toast message
1257 - if (data.title && data.msg)
1258 - {
1105 + if (data.title && data.msg) {
1106 MeshServerLogEx(26, [data.title, data.msg], "Displaying toast message, title=" + data.title + ", message=" + data.msg, data);
1107 data.msg = data.msg.split('\r').join('\\r').split('\n').join('\\n');
1108 try { require('toaster').Toast(data.title, data.msg); } catch (e) { }
@@ -1272,8 +1119,7 @@ function handleServerCommand(data)
1119 case 'amtconfig': {
1120 // Perform Intel AMT activation and/or configuration
1121 if ((apftunnel != null) || (amt == null) || (typeof data.user != 'string') || (typeof data.pass != 'string')) break;
1275 - amt.getMeiState(15, function (state)
1276 - {
1122 + amt.getMeiState(15, function (state) {
1123 if ((apftunnel != null) || (amt == null)) return;
1124 if ((state == null) || (state.ProvisioningState == null)) return;
1125 if ((state.UUID == null) || (state.UUID.length != 36)) return; // Bad UUID
@@ -1290,12 +1136,10 @@ function handleServerCommand(data)
1136 };
1137 addAmtEvent('LMS tunnel start.');
1138 apftunnel = require('amt-apfclient')({ debug: false }, apfarg);
1293 - apftunnel.onJsonControl = function (data)
1294 - {
1139 + apftunnel.onJsonControl = function (data) {
1140 if (data.action == 'console') { addAmtEvent(data.msg); } // Add console message to AMT event log
1141 if (data.action == 'mestate') { amt.getMeiState(15, function (state) { apftunnel.updateMeiState(state); }); } // Update the MEI state
1297 - if (data.action == 'deactivate')
1298 - { // Request CCM deactivation
1142 + if (data.action == 'deactivate') { // Request CCM deactivation
1143 var amtMeiModule, amtMei;
1144 try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { if (apftunnel) apftunnel.sendMeiDeactivationState(1); return; }
1145 amtMei.on('error', function (e) { if (apftunnel) apftunnel.sendMeiDeactivationState(1); });
@@ -1315,8 +1159,7 @@ function handleServerCommand(data)
1159 }
1160 case 'sysinfo': {
1161 // Fetch system information
1318 - getSystemInformation(function (results)
1319 - {
1162 + getSystemInformation(function (results) {
1163 if ((results != null) && (data.hash != results.hash)) { mesh.SendCommand({ action: 'sysinfo', sessionid: this.sessionid, data: results }); }
1164 });
1165 break;
@@ -1329,18 +1172,14 @@ function handleServerCommand(data)
1172 }
1173 case 'coredump':
1174 // Set the current agent coredump situation.
1332 - if (data.value === true)
1333 - {
1334 - if (process.platform == 'win32')
1335 - {
1175 + if (data.value === true) {
1176 + if (process.platform == 'win32') {
1177 // TODO: This replace() below is not ideal, would be better to remove the .exe at the end instead of replace.
1178 process.coreDumpLocation = process.execPath.replace('.exe', '.dmp');
1338 - } else
1339 - {
1179 + } else {
1180 process.coreDumpLocation = (process.cwd() != '//') ? (process.cwd() + 'core') : null;
1181 }
1342 - } else if (data.value === false)
1343 - {
1182 + } else if (data.value === false) {
1183 process.coreDumpLocation = null;
1184 }
1185 break;
@@ -1349,18 +1188,15 @@ function handleServerCommand(data)
1188 var r = { action: 'getcoredump', value: (process.coreDumpLocation != null) };
1189 var coreDumpPath = null;
1190 if (process.platform == 'win32') { coreDumpPath = process.coreDumpLocation; } else { coreDumpPath = (process.cwd() != '//') ? fs.existsSync(process.cwd() + 'core') : null; }
1352 - if ((coreDumpPath != null) && (fs.existsSync(coreDumpPath)))
1353 - {
1354 - try
1355 - {
1191 + if ((coreDumpPath != null) && (fs.existsSync(coreDumpPath))) {
1192 + try {
1193 var coredate = fs.statSync(coreDumpPath).mtime;
1194 var coretime = new Date(coredate).getTime();
1195 var agenttime = new Date(fs.statSync(process.execPath).mtime).getTime();
1196 if (coretime > agenttime) { r.exists = (db.Get('CoreDumpTime') != coredate); }
1197 } catch (ex) { }
1198 }
1362 - if (r.exists == true)
1363 - {
1199 + if (r.exists == true) {
1200 r.agenthashhex = getSHA384FileHash(process.execPath).toString('hex'); // Hash of current agent
1201 r.corehashhex = getSHA384FileHash(coreDumpPath).toString('hex'); // Hash of core dump file
1202 }
@@ -1381,8 +1217,7 @@ function handleServerCommand(data)
1217 }
1218
1219 // Agent just get a file from the server and save it locally.
1384 -function serverFetchFile()
1385 -{
1220 +function serverFetchFile() {
1221 if ((Object.keys(agentFileHttpRequests).length > 4) || (agentFileHttpPendingRequests.length == 0)) return; // No more than 4 active HTTPS requests to the server.
1222 var data = agentFileHttpPendingRequests.shift();
1223 if ((data.overwrite !== true) && fs.existsSync(data.path)) return; // Don't overwrite an existing file.
@@ -1393,8 +1228,7 @@ function serverFetchFile()
1228
1229 // Perform manual server TLS certificate checking based on the certificate hash given by the server.
1230 agentFileHttpOptions.rejectUnauthorized = 0;
1396 - agentFileHttpOptions.checkServerIdentity = function checkServerIdentity(certs)
1397 - {
1231 + agentFileHttpOptions.checkServerIdentity = function checkServerIdentity(certs) {
1232 // If the tunnel certificate matches the control channel certificate, accept the connection
1233 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
1234 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
@@ -1405,11 +1239,9 @@ function serverFetchFile()
1239
1240 if (agentFileHttpOptions == null) return;
1241 var agentFileHttpRequest = http.request(agentFileHttpOptions,
1408 - function (response)
1409 - {
1242 + function (response) {
1243 response.xparent = this;
1411 - try
1412 - {
1244 + try {
1245 response.xfile = fs.createWriteStream(this.xpath, { flags: 'wbN' })
1246 response.pipe(response.xfile);
1247 response.end = function () { delete agentFileHttpRequests[this.xparent.xurlpath]; delete this.xparent; serverFetchFile(); }
@@ -1432,13 +1264,10 @@ function onFileWatcher(a, b) {
1264 }
1265 */
1266
1435 -function getSystemInformation(func)
1436 -{
1437 - try
1438 - {
1267 +function getSystemInformation(func) {
1268 + try {
1269 var results = { hardware: require('identifiers').get() }; // Hardware info
1440 - if (results.hardware && results.hardware.windows)
1441 - {
1270 + if (results.hardware && results.hardware.windows) {
1271 // Remove extra entries and things that change quickly
1272 var x = results.hardware.windows.osinfo;
1273 try { delete x.FreePhysicalMemory; } catch (e) { }
@@ -1448,24 +1277,19 @@ function getSystemInformation(func)
1277 try { delete x.MaxProcessMemorySize; } catch (e) { }
1278 try { delete x.TotalVirtualMemorySize; } catch (e) { }
1279 try { delete x.TotalVisibleMemorySize; } catch (e) { }
1451 - try
1452 - {
1280 + try {
1281 if (results.hardware.windows.memory) { for (var i in results.hardware.windows.memory) { delete results.hardware.windows.memory[i].Node; } }
1282 if (results.hardware.windows.osinfo) { delete results.hardware.windows.osinfo.Node; }
1283 if (results.hardware.windows.partitions) { for (var i in results.hardware.windows.partitions) { delete results.hardware.windows.partitions[i].Node; } }
1284 } catch (e) { }
1285 }
1458 - if (process.platform == 'win32')
1459 - {
1286 + if (process.platform == 'win32') {
1287 results.pendingReboot = require('win-info').pendingReboot(); // Pending reboot
1461 - if (require('identifiers').volumes != null)
1462 - {
1463 - try
1464 - {
1288 + if (require('identifiers').volumes != null) {
1289 + try {
1290 results.volumes = require('identifiers').volumes();
1291 }
1467 - catch (e)
1468 - {
1292 + catch (e) {
1293 }
1294 }
1295 }
@@ -1499,46 +1323,35 @@ function getSystemInformation(func)
1323 }
1324
1325 // Get a formated response for a given directory path
1502 -function getDirectoryInfo(reqpath)
1503 -{
1326 +function getDirectoryInfo(reqpath) {
1327 var response = { path: reqpath, dir: [] };
1505 - if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32'))
1506 - {
1328 + if (((reqpath == undefined) || (reqpath == '')) && (process.platform == 'win32')) {
1329 // List all the drives in the root, or the root itself
1330 var results = null;
1331 try { results = fs.readDrivesSync(); } catch (e) { } // TODO: Anyway to get drive total size and free space? Could draw a progress bar.
1510 - if (results != null)
1511 - {
1512 - for (var i = 0; i < results.length; ++i)
1513 - {
1332 + if (results != null) {
1333 + for (var i = 0; i < results.length; ++i) {
1334 var drive = { n: results[i].name, t: 1 };
1335 if (results[i].type == 'REMOVABLE') { drive.dt = 'removable'; } // TODO: See if this is USB/CDROM or something else, we can draw icons.
1336 response.dir.push(drive);
1337 }
1338 }
1519 - } else
1520 - {
1339 + } else {
1340 // List all the files and folders in this path
1341 if (reqpath == '') { reqpath = '/'; }
1342 var results = null, xpath = obj.path.join(reqpath, '*');
1343 //if (process.platform == "win32") { xpath = xpath.split('/').join('\\'); }
1344 try { results = fs.readdirSync(xpath); } catch (e) { }
1526 - if (results != null)
1527 - {
1528 - for (var i = 0; i < results.length; ++i)
1529 - {
1530 - if ((results[i] != '.') && (results[i] != '..'))
1531 - {
1345 + if (results != null) {
1346 + for (var i = 0; i < results.length; ++i) {
1347 + if ((results[i] != '.') && (results[i] != '..')) {
1348 var stat = null, p = obj.path.join(reqpath, results[i]);
1349 //if (process.platform == "win32") { p = p.split('/').join('\\'); }
1350 try { stat = fs.statSync(p); } catch (e) { } // TODO: Get file size/date
1535 - if ((stat != null) && (stat != undefined))
1536 - {
1537 - if (stat.isDirectory() == true)
1538 - {
1351 + if ((stat != null) && (stat != undefined)) {
1352 + if (stat.isDirectory() == true) {
1353 response.dir.push({ n: results[i], t: 2, d: stat.mtime });
1540 - } else
1541 - {
1354 + } else {
1355 response.dir.push({ n: results[i], t: 3, s: stat.size, d: stat.mtime });
1356 }
1357 }
@@ -1550,19 +1363,16 @@ function getDirectoryInfo(reqpath)
1363 }
1364
1365 // Tunnel callback operations
1553 -function onTunnelUpgrade(response, s, head)
1554 -{
1366 +function onTunnelUpgrade(response, s, head) {
1367 this.s = s;
1368 s.httprequest = this;
1369 s.end = onTunnelClosed;
1370 s.tunnel = this;
1371 s.descriptorMetadata = "MeshAgent_relayTunnel";
1372
1561 - if (require('MeshAgent').idleTimeout != null)
1562 - {
1373 + if (require('MeshAgent').idleTimeout != null) {
1374 s.setTimeout(require('MeshAgent').idleTimeout * 1000);
1564 - s.on('timeout', function ()
1565 - {
1375 + s.on('timeout', function () {
1376 this.ping();
1377 this.setTimeout(require('MeshAgent').idleTimeout * 1000);
1378 });
@@ -1570,8 +1380,7 @@ function onTunnelUpgrade(response, s, head)
1380
1381 //sendConsoleText('onTunnelUpgrade - ' + this.tcpport + ' - ' + this.udpport);
1382
1573 - if (this.tcpport != null)
1574 - {
1383 + if (this.tcpport != null) {
1384 // This is a TCP relay connection, pause now and try to connect to the target.
1385 s.pause();
1386 s.data = onTcpRelayServerTunnelData;
@@ -1581,14 +1390,12 @@ function onTunnelUpgrade(response, s, head)
1390 s.tcprelay.peerindex = this.index;
1391
1392 // Add the TCP session to the count and update the server
1584 - if (s.httprequest.userid != null)
1585 - {
1393 + if (s.httprequest.userid != null) {
1394 if (tunnelUserCount.tcp[s.httprequest.userid] == null) { tunnelUserCount.tcp[s.httprequest.userid] = 1; } else { tunnelUserCount.tcp[s.httprequest.userid]++; }
1395 try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1396 broadcastSessionsToRegisteredApps();
1397 }
1590 - } if (this.udpport != null)
1591 - {
1398 + } if (this.udpport != null) {
1399 // This is a UDP relay connection, get the UDP socket setup. // TODO: ***************
1400 s.data = onUdpRelayServerTunnelData;
1401 s.udprelay = require('dgram').createSocket({ type: 'udp4' });
@@ -1600,41 +1407,34 @@ function onTunnelUpgrade(response, s, head)
1407 s.udprelay.first = true;
1408
1409 // Add the UDP session to the count and update the server
1603 - if (s.httprequest.userid != null)
1604 - {
1410 + if (s.httprequest.userid != null) {
1411 if (tunnelUserCount.udp[s.httprequest.userid] == null) { tunnelUserCount.udp[s.httprequest.userid] = 1; } else { tunnelUserCount.udp[s.httprequest.userid]++; }
1412 try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.tcp }); } catch (e) { }
1413 broadcastSessionsToRegisteredApps();
1414 }
1609 - } else
1610 - {
1415 + } else {
1416 // This is a normal connect for KVM/Terminal/Files
1417 s.data = onTunnelData;
1418 }
1419 }
1420
1421 // Called when UDP relay data is received // TODO****
1617 -function onUdpRelayTargetTunnelConnect(data)
1618 -{
1422 +function onUdpRelayTargetTunnelConnect(data) {
1423 var peerTunnel = tunnels[this.peerindex];
1424 peerTunnel.s.write(data);
1425 }
1426
1427 // Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1624 -function onUdpRelayServerTunnelData(data)
1625 -{
1626 - if (this.udprelay.first === true)
1627 - {
1428 +function onUdpRelayServerTunnelData(data) {
1429 + if (this.udprelay.first === true) {
1430 delete this.udprelay.first; // Skip the first 'c' that is received.
1629 - } else
1630 - {
1431 + } else {
1432 this.udprelay.send(data, parseInt(this.udprelay.udpport), this.udprelay.udpaddr ? this.udprelay.udpaddr : '127.0.0.1');
1433 }
1434 }
1435
1436 // Called when the TCP relay target is connected
1636 -function onTcpRelayTargetTunnelConnect()
1637 -{
1437 +function onTcpRelayTargetTunnelConnect() {
1438 var peerTunnel = tunnels[this.peerindex];
1439 this.pipe(peerTunnel.s); // Pipe Target --> Server
1440 peerTunnel.s.first = true;
@@ -1642,30 +1442,24 @@ function onTcpRelayTargetTunnelConnect()
1442 }
1443
1444 // Called when we get data from the server for a TCP relay (We have to skip the first received 'c' and pipe the rest)
1645 -function onTcpRelayServerTunnelData(data)
1646 -{
1647 - if (this.first == true)
1648 - {
1445 +function onTcpRelayServerTunnelData(data) {
1446 + if (this.first == true) {
1447 this.first = false;
1448 this.pipe(this.tcprelay, { dataTypeSkip: 1 }); // Pipe Server --> Target (don't pipe text type websocket frames)
1449 }
1450 }
1451
1654 -function onTunnelClosed()
1655 -{
1452 +function onTunnelClosed() {
1453 var tunnel = tunnels[this.httprequest.index];
1454 if (tunnel == null) return; // Stop duplicate calls.
1455
1456 // If this is a routing session, clean up and send the new session counts.
1660 - if (this.httprequest.userid != null)
1661 - {
1662 - if (this.httprequest.tcpport != null)
1663 - {
1457 + if (this.httprequest.userid != null) {
1458 + if (this.httprequest.tcpport != null) {
1459 if (tunnelUserCount.tcp[this.httprequest.userid] != null) { tunnelUserCount.tcp[this.httprequest.userid]--; if (tunnelUserCount.tcp[this.httprequest.userid] <= 0) { delete tunnelUserCount.tcp[this.httprequest.userid]; } }
1460 try { mesh.SendCommand({ action: 'sessions', type: 'tcp', value: tunnelUserCount.tcp }); } catch (e) { }
1461 broadcastSessionsToRegisteredApps();
1667 - } else if (this.httprequest.udpport != null)
1668 - {
1462 + } else if (this.httprequest.udpport != null) {
1463 if (tunnelUserCount.udp[this.httprequest.userid] != null) { tunnelUserCount.udp[this.httprequest.userid]--; if (tunnelUserCount.udp[this.httprequest.userid] <= 0) { delete tunnelUserCount.udp[this.httprequest.userid]; } }
1464 try { mesh.SendCommand({ action: 'sessions', type: 'udp', value: tunnelUserCount.udp }); } catch (e) { }
1465 broadcastSessionsToRegisteredApps();
@@ -1673,8 +1467,7 @@ function onTunnelClosed()
1467 }
1468
1469 // Sent tunnel statistics to the server, only send this if compression was used.
1676 - if ((this.bytesSent_uncompressed) && (this.bytesSent_uncompressed.toString() != this.bytesSent_actual.toString()))
1677 - {
1470 + if ((this.bytesSent_uncompressed) && (this.bytesSent_uncompressed.toString() != this.bytesSent_actual.toString())) {
1471 mesh.SendCommand({
1472 action: 'tunnelCloseStats',
1473 url: tunnel.url,
@@ -1707,8 +1500,7 @@ function onTunnelClosed()
1500 if (this.httprequest.downloadFile) { delete this.httprequest.downloadFile; }
1501
1502 // Clean up WebRTC
1710 - if (this.webrtc != null)
1711 - {
1503 + if (this.webrtc != null) {
1504 if (this.webrtc.rtcchannel) { try { this.webrtc.rtcchannel.close(); } catch (e) { } this.webrtc.rtcchannel.removeAllListeners('data'); this.webrtc.rtcchannel.removeAllListeners('end'); delete this.webrtc.rtcchannel; }
1505 if (this.webrtc.websocket) { delete this.webrtc.websocket; }
1506 try { this.webrtc.close(); } catch (e) { }
@@ -1722,21 +1514,17 @@ function onTunnelClosed()
1514 this.removeAllListeners('data');
1515 }
1516 function onTunnelSendOk() { /*sendConsoleText("Tunnel #" + this.index + " SendOK.", this.sessionid);*/ }
1725 -function onTunnelData(data)
1726 -{
1517 +function onTunnelData(data) {
1518 //console.log("OnTunnelData");
1519 //sendConsoleText('OnTunnelData, ' + data.length + ', ' + typeof data + ', ' + data);
1520
1521 // If this is upload data, save it to file
1731 - if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123))
1732 - {
1522 + if ((this.httprequest.uploadFile) && (typeof data == 'object') && (data[0] != 123)) {
1523 // Save the data to file being uploaded.
1734 - if (data[0] == 0)
1735 - {
1524 + if (data[0] == 0) {
1525 // If data starts with zero, skip the first byte. This is used to escape binary file data from JSON.
1526 try { fs.writeSync(this.httprequest.uploadFile, data, 1, data.length - 1); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
1738 - } else
1739 - {
1527 + } else {
1528 // If data does not start with zero, save as-is.
1529 try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { sendConsoleText('FileUpload Error'); this.write(Buffer.from(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
1530 }
@@ -1744,22 +1532,18 @@ function onTunnelData(data)
1532 return;
1533 }
1534
1747 - if (this.httprequest.state == 0)
1748 - {
1535 + if (this.httprequest.state == 0) {
1536 // Check if this is a relay connection
1537 if ((data == 'c') || (data == 'cr')) { this.httprequest.state = 1; /*sendConsoleText("Tunnel #" + this.httprequest.index + " now active", this.httprequest.sessionid);*/ }
1538 }
1752 - else
1753 - {
1539 + else {
1540 // Handle tunnel data
1755 - if (this.httprequest.protocol == 0)
1756 - { // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user), 10 = FileTransfer
1541 + if (this.httprequest.protocol == 0) { // 1 = Terminal (admin), 2 = Desktop, 5 = Files, 6 = PowerShell (admin), 7 = Plugin Data Exchange, 8 = Terminal (user), 9 = PowerShell (user), 10 = FileTransfer
1542 // Take a look at the protocol
1543 if ((data.length > 3) && (data[0] == '{')) { onTunnelControlData(data, this); return; }
1544 this.httprequest.protocol = parseInt(data);
1545 if (typeof this.httprequest.protocol != 'number') { this.httprequest.protocol = 0; }
1761 - if (this.httprequest.protocol == 10)
1762 - {
1546 + if (this.httprequest.protocol == 10) {
1547 //
1548 // Basic file transfer
1549 //
@@ -1767,27 +1551,23 @@ function onTunnelData(data)
1551 if ((process.platform != 'win32') && (this.httprequest.xoptions.file.startsWith('/') == false)) { this.httprequest.xoptions.file = '/' + this.httprequest.xoptions.file; }
1552 try { stats = require('fs').statSync(this.httprequest.xoptions.file) } catch (e) { }
1553 try { if (stats) { this.httprequest.downloadFile = fs.createReadStream(this.httprequest.xoptions.file, { flags: 'rbN' }); } } catch (e) { }
1770 - if (this.httprequest.downloadFile)
1771 - {
1554 + if (this.httprequest.downloadFile) {
1555 //sendConsoleText('BasicFileTransfer, ok, ' + this.httprequest.xoptions.file + ', ' + JSON.stringify(stats));
1556 this.write(JSON.stringify({ op: 'ok', size: stats.size }));
1557 this.httprequest.downloadFile.pipe(this);
1558 this.httprequest.downloadFile.end = function () { }
1776 - } else
1777 - {
1559 + } else {
1560 //sendConsoleText('BasicFileTransfer, cancel, ' + this.httprequest.xoptions.file);
1561 this.write(JSON.stringify({ op: 'cancel' }));
1562 }
1563 }
1782 - else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9))
1783 - {
1564 + else if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6) || (this.httprequest.protocol == 8) || (this.httprequest.protocol == 9)) {
1565 //
1566 // Remote Terminal
1567 //
1568
1569 // Check user access rights for terminal
1789 - if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOTERMINAL) != 0)))
1790 - {
1570 + if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOTERMINAL) != 0))) {
1571 // Disengage this tunnel, user does not have the rights to do this!!
1572 this.httprequest.protocol = 999999;
1573 this.httprequest.s.end();
@@ -1797,10 +1577,8 @@ function onTunnelData(data)
1577
1578 this.descriptorMetadata = "Remote Terminal";
1579
1800 - if (process.platform == 'win32')
1801 - {
1802 - if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9))
1803 - {
1580 + if (process.platform == 'win32') {
1581 + if (!require('win-terminal').PowerShellCapable() && (this.httprequest.protocol == 6 || this.httprequest.protocol == 9)) {
1582 this.httprequest.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: 'PowerShell is not supported on this version of windows', msgid: 1 }));
1583 this.httprequest.s.end();
1584 return;
@@ -1812,28 +1590,24 @@ function onTunnelData(data)
1590 this.httprequest.tpromise.that = this;
1591 this.httprequest.tpromise.httprequest = this.httprequest;
1592
1815 - this.end = function ()
1816 - {
1593 + this.end = function () {
1594 if (this.httprequest.tpromise._consent) { this.httprequest.tpromise._consent.close(); }
1595 if (this.httprequest.connectionPromise) { this.httprequest.connectionPromise._rej('Closed'); }
1596
1597 // Remove the terminal session to the count to update the server
1821 - if (this.httprequest.userid != null)
1822 - {
1598 + if (this.httprequest.userid != null) {
1599 if (tunnelUserCount.terminal[this.httprequest.userid] != null) { tunnelUserCount.terminal[this.httprequest.userid]--; if (tunnelUserCount.terminal[this.httprequest.userid] <= 0) { delete tunnelUserCount.terminal[this.httprequest.userid]; } }
1600 try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1601 broadcastSessionsToRegisteredApps();
1602 }
1603
1828 - if (process.platform == 'win32')
1829 - {
1604 + if (process.platform == 'win32') {
1605 // Unpipe the web socket
1606 this.unpipe(this.httprequest._term);
1607 if (this.httprequest._term) { this.httprequest._term.unpipe(this); }
1608
1609 // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
1835 - if (this.rtcchannel)
1836 - {
1610 + if (this.rtcchannel) {
1611 this.rtcchannel.unpipe(this.httprequest._term);
1612 if (this.httprequest._term) { this.httprequest._term.unpipe(this.rtcchannel); }
1613 }
@@ -1845,118 +1619,95 @@ function onTunnelData(data)
1619 };
1620
1621 // Perform User-Consent if needed.
1848 - if (this.httprequest.consent && (this.httprequest.consent & 16))
1849 - {
1622 + if (this.httprequest.consent && (this.httprequest.consent & 16)) {
1623 this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1624 var consentMessage = this.httprequest.username + " requesting remote terminal access. Grant access?", consentTitle = 'MeshCentral';
1852 - if (this.httprequest.soptions != null)
1853 - {
1625 + if (this.httprequest.soptions != null) {
1626 if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1627 if (this.httprequest.soptions.consentMsgTerminal != null) { consentMessage = this.httprequest.soptions.consentMsgTerminal.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1628 }
1629 this.httprequest.tpromise._consent = require('message-box').create(consentTitle, consentMessage, 30);
1630 this.httprequest.tpromise._consent.retPromise = this.httprequest.tpromise;
1631 this.httprequest.tpromise._consent.then(
1860 - function ()
1861 - {
1632 + function () {
1633 // Success
1634 MeshServerLogEx(27, null, "Local user accepted remote terminal request (" + this.retPromise.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1635 this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
1636 this.retPromise._consent = null;
1637 this.retPromise._res();
1638 },
1868 - function (e)
1869 - {
1639 + function (e) {
1640 // Denied
1641 MeshServerLogEx(28, null, "Local user rejected remote terminal request (" + this.retPromise.that.httprequest.remoteaddr + ")", this.retPromise.that.httprequest);
1642 this.retPromise.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1643 this.retPromise._rej(e.toString());
1644 });
1645 }
1876 - else
1877 - {
1646 + else {
1647 // User-Consent is not required, so just resolve this promise
1648 this.httprequest.tpromise._res();
1649 }
1650
1651
1652 this.httprequest.tpromise.then(
1884 - function ()
1885 - {
1653 + function () {
1654 this.httprequest.connectionPromise = new prom(function (res, rej) { this._res = res; this._rej = rej; });
1655 this.httprequest.connectionPromise.ws = this.that;
1656
1657 // Start Terminal
1890 - if (process.platform == 'win32')
1891 - {
1892 - try
1893 - {
1658 + if (process.platform == 'win32') {
1659 + try {
1660 var cols = 80, rows = 25;
1895 - if (this.httprequest.xoptions)
1896 - {
1661 + if (this.httprequest.xoptions) {
1662 if (this.httprequest.xoptions.rows) { rows = this.httprequest.xoptions.rows; }
1663 if (this.httprequest.xoptions.cols) { cols = this.httprequest.xoptions.cols; }
1664 }
1665
1901 - if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6))
1902 - {
1666 + if ((this.httprequest.protocol == 1) || (this.httprequest.protocol == 6)) {
1667 // Admin Terminal
1904 - if (require('win-virtual-terminal').supported)
1905 - {
1668 + if (require('win-virtual-terminal').supported) {
1669 // ConPTY PseudoTerminal
1670 // this.httprequest._term = require('win-virtual-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](80, 25);
1671
1672 // The above line is commented out, because there is a bug with ClosePseudoConsole() API, so this is the workaround
1673 this.httprequest._dispatcher = require('win-dispatcher').dispatch({ modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1674 this.httprequest._dispatcher.httprequest = this.httprequest;
1912 - this.httprequest._dispatcher.on('connection', function (c)
1913 - {
1914 - if (this.httprequest.connectionPromise.completed)
1915 - {
1675 + this.httprequest._dispatcher.on('connection', function (c) {
1676 + if (this.httprequest.connectionPromise.completed) {
1677 c.end();
1678 }
1918 - else
1919 - {
1679 + else {
1680 this.httprequest.connectionPromise._res(c);
1681 }
1682 });
1683 }
1924 - else
1925 - {
1684 + else {
1685 // Legacy Terminal
1686 this.httprequest.connectionPromise._res(require('win-terminal')[this.httprequest.protocol == 6 ? 'StartPowerShell' : 'Start'](cols, rows));
1687 }
1688 }
1930 - else
1931 - {
1689 + else {
1690 // Logged in user
1691 var userPromise = require('user-sessions').enumerateUsers();
1692 userPromise.that = this;
1935 - userPromise.then(function (u)
1936 - {
1693 + userPromise.then(function (u) {
1694 var that = this.that;
1938 - if (u.Active.length > 0)
1939 - {
1695 + if (u.Active.length > 0) {
1696 var username = u.Active[0].Username;
1941 - if (require('win-virtual-terminal').supported)
1942 - {
1697 + if (require('win-virtual-terminal').supported) {
1698 // ConPTY PseudoTerminal
1699 that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-virtual-terminal', script: getJSModule('win-virtual-terminal') }], launch: { module: 'win-virtual-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1700 }
1946 - else
1947 - {
1701 + else {
1702 // Legacy Terminal
1703 that.httprequest._dispatcher = require('win-dispatcher').dispatch({ user: username, modules: [{ name: 'win-terminal', script: getJSModule('win-terminal') }], launch: { module: 'win-terminal', method: (that.httprequest.protocol == 9 ? 'StartPowerShell' : 'Start'), args: [cols, rows] } });
1704 }
1705 that.httprequest._dispatcher.ws = that;
1952 - that.httprequest._dispatcher.on('connection', function (c)
1953 - {
1954 - if (this.ws.httprequest.connectionPromise.completed)
1955 - {
1706 + that.httprequest._dispatcher.on('connection', function (c) {
1707 + if (this.ws.httprequest.connectionPromise.completed) {
1708 c.end();
1709 }
1958 - else
1959 - {
1710 + else {
1711 this.ws.httprequest.connectionPromise._res(c);
1712 }
1713 });
@@ -1964,70 +1715,58 @@ function onTunnelData(data)
1715 });
1716 }
1717 }
1967 - catch (e)
1968 - {
1718 + catch (e) {
1719 this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1720 }
1721 }
1972 - else
1973 - {
1974 - try
1975 - {
1722 + else {
1723 + try {
1724 var bash = fs.existsSync('/bin/bash') ? '/bin/bash' : false;
1725 var sh = fs.existsSync('/bin/sh') ? '/bin/sh' : false;
1726 var login = process.platform == 'linux' ? '/bin/login' : '/usr/bin/login';
1727
1728 var env = { HISTCONTROL: 'ignoreboth' };
1981 - if (this.httprequest.xoptions)
1982 - {
1729 + if (this.httprequest.xoptions) {
1730 if (this.httprequest.xoptions.rows) { env.LINES = ('' + this.httprequest.xoptions.rows); }
1731 if (this.httprequest.xoptions.cols) { env.COLUMNS = ('' + this.httprequest.xoptions.cols); }
1732 }
1733 var options = { type: childProcess.SpawnTypes.TERM, uid: (this.httprequest.protocol == 8) ? require('user-sessions').consoleUid() : null, env: env };
1987 - if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin)
1988 - {
1734 + if (this.httprequest.xoptions && this.httprequest.xoptions.requireLogin) {
1735 if (!require('fs').existsSync(login)) { throw ('Unable to spawn login process'); }
1736 this.httprequest.connectionPromise._res(childProcess.execFile(login, ['login'], options)); // Start login shell
1737 }
1992 - else if (bash)
1993 - {
1738 + else if (bash) {
1739 var p = childProcess.execFile(bash, ['bash'], options); // Start bash
1740 // Spaces at the beginning of lines are needed to hide commands from the command history
1741 if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1742 this.httprequest.connectionPromise._res(p);
1743 }
1999 - else if (sh)
2000 - {
1744 + else if (sh) {
1745 var p = childProcess.execFile(sh, ['sh'], options); // Start sh
1746 // Spaces at the beginning of lines are needed to hide commands from the command history
1747 if (process.platform == 'linux') { p.stdin.write(' alias ls=\'ls --color=auto\';clear\n'); }
1748 this.httprequest.connectionPromise._res(p);
1749 }
2006 - else
2007 - {
1750 + else {
1751 this.httprequest.connectionPromise._rej('Failed to start remote terminal session, no shell found');
1752 }
1753 }
2011 - catch (e)
2012 - {
1754 + catch (e) {
1755 this.httprequest.connectionPromise._rej('Failed to start remote terminal session, ' + e.toString());
1756 }
1757 }
1758
1759 this.httprequest.connectionPromise.then(
2018 - function (term)
2019 - {
1760 + function (term) {
1761 // SUCCESS
1762 var stdoutstream;
1763 var stdinstream;
2023 - if (process.platform == 'win32')
2024 - {
1764 + if (process.platform == 'win32') {
1765 this.ws.httprequest._term = term;
1766 this.ws.httprequest._term.tunnel = this.ws;
1767 stdoutstream = stdinstream = term;
1768 }
2029 - else
2030 - {
1769 + else {
1770 term.descriptorMetadata = 'Remote Terminal';
1771 this.ws.httprequest.process = term;
1772 this.ws.httprequest.process.tunnel = this.ws;
@@ -2046,49 +1785,42 @@ function onTunnelData(data)
1785 this.ws.pipe(stdinstream, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
1786
1787 // Add the terminal session to the count to update the server
2049 - if (this.ws.httprequest.userid != null)
2050 - {
1788 + if (this.ws.httprequest.userid != null) {
1789 if (tunnelUserCount.terminal[this.ws.httprequest.userid] == null) { tunnelUserCount.terminal[this.ws.httprequest.userid] = 1; } else { tunnelUserCount.terminal[this.ws.httprequest.userid]++; }
1790 try { mesh.SendCommand({ action: 'sessions', type: 'terminal', value: tunnelUserCount.terminal }); } catch (e) { }
1791 broadcastSessionsToRegisteredApps();
1792 }
1793
1794 // Toast Notification, if required
2057 - if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2))
2058 - {
1795 + if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 2)) {
1796 // User Notifications is required
1797 var notifyMessage = this.ws.httprequest.username + " started a remote terminal session.", notifyTitle = "MeshCentral";
2061 - if (this.ws.httprequest.soptions != null)
2062 - {
1798 + if (this.ws.httprequest.soptions != null) {
1799 if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1800 if (this.ws.httprequest.soptions.notifyMsgTerminal != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgTerminal.replace('{0}', this.ws.httprequest.realname).replace('{1}', this.ws.httprequest.username); }
1801 }
1802 try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
1803 }
1804 },
2069 - function (e)
2070 - {
1805 + function (e) {
1806 // FAILED to connect terminal
1807 this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1808 this.ws.end();
1809 });
1810 },
2076 - function (e)
2077 - {
1811 + function (e) {
1812 // DO NOT start terminal
1813 this.that.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
1814 this.that.end();
1815 });
1816 }
2083 - else if (this.httprequest.protocol == 2)
2084 - {
1817 + else if (this.httprequest.protocol == 2) {
1818 //
1819 // Remote KVM
1820 //
1821
1822 // Check user access rights for desktop
2090 - if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0)))
2091 - {
1823 + if ((((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NODESKTOP) != 0))) {
1824 // Disengage this tunnel, user does not have the rights to do this!!
1825 this.httprequest.protocol = 999999;
1826 this.httprequest.s.end();
@@ -2114,8 +1846,7 @@ function onTunnelData(data)
1846
1847 // Send a metadata update to all desktop sessions
1848 var users = {};
2117 - if (this.httprequest.desktop.kvm.tunnels != null)
2118 - {
1849 + if (this.httprequest.desktop.kvm.tunnels != null) {
1850 for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } }
1851 for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } }
1852 tunnelUserCount.desktop = users;
@@ -2123,8 +1854,7 @@ function onTunnelData(data)
1854 broadcastSessionsToRegisteredApps();
1855 }
1856
2126 - this.end = function ()
2127 - {
1857 + this.end = function () {
1858 --this.desktop.kvm.connectionCount;
1859
1860 // Remove ourself from the list of remote desktop session
@@ -2133,8 +1863,7 @@ function onTunnelData(data)
1863
1864 // Send a metadata update to all desktop sessions
1865 var users = {};
2136 - if (this.httprequest.desktop.kvm.tunnels != null)
2137 - {
1866 + if (this.httprequest.desktop.kvm.tunnels != null) {
1867 for (var i in this.httprequest.desktop.kvm.tunnels) { try { var userid = this.httprequest.desktop.kvm.tunnels[i].httprequest.userid; if (users[userid] == null) { users[userid] = 1; } else { users[userid]++; } } catch (e) { } }
1868 for (var i in this.httprequest.desktop.kvm.tunnels) { try { this.httprequest.desktop.kvm.tunnels[i].write(JSON.stringify({ ctrlChannel: '102938', type: 'metadata', users: users })); } catch (e) { } }
1869 tunnelUserCount.desktop = users;
@@ -2143,18 +1872,15 @@ function onTunnelData(data)
1872 }
1873
1874 // Unpipe the web socket
2146 - try
2147 - {
1875 + try {
1876 this.unpipe(this.httprequest.desktop.kvm);
1877 this.httprequest.desktop.kvm.unpipe(this);
1878 }
1879 catch (e) { }
1880
1881 // Unpipe the WebRTC channel if needed (This will also be done when the WebRTC channel ends).
2154 - if (this.rtcchannel)
2155 - {
2156 - try
2157 - {
1882 + if (this.rtcchannel) {
1883 + try {
1884 this.rtcchannel.unpipe(this.httprequest.desktop.kvm);
1885 this.httprequest.desktop.kvm.unpipe(this.rtcchannel);
1886 }
@@ -2164,35 +1890,28 @@ function onTunnelData(data)
1890 // Place wallpaper back if needed
1891 // TODO
1892
2167 - if (this.desktop.kvm.connectionCount == 0)
2168 - {
1893 + if (this.desktop.kvm.connectionCount == 0) {
1894 // Display a toast message. This may not be supported on all platforms.
1895 // try { require('toaster').Toast('MeshCentral', 'Remote Desktop Control Ended.'); } catch (e) { }
1896
1897 this.httprequest.desktop.kvm.end();
2173 - if (this.httprequest.desktop.kvm.connectionBar)
2174 - {
1898 + if (this.httprequest.desktop.kvm.connectionBar) {
1899 this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1900 this.httprequest.desktop.kvm.connectionBar.close();
1901 this.httprequest.desktop.kvm.connectionBar = null;
1902 }
2179 - } else
2180 - {
2181 - for (var i in this.httprequest.desktop.kvm.users)
2182 - {
2183 - if ((this.httprequest.desktop.kvm.users[i] == this.httprequest.username) && this.httprequest.desktop.kvm.connectionBar)
2184 - {
1903 + } else {
1904 + for (var i in this.httprequest.desktop.kvm.users) {
1905 + if ((this.httprequest.desktop.kvm.users[i] == this.httprequest.username) && this.httprequest.desktop.kvm.connectionBar) {
1906 for (var j in this.httprequest.desktop.kvm.rusers) { if (this.httprequest.desktop.kvm.rusers[j] == this.httprequest.realname) { this.httprequest.desktop.kvm.rusers.splice(j, 1); break; } }
1907 this.httprequest.desktop.kvm.users.splice(i, 1);
1908 this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1909 this.httprequest.desktop.kvm.connectionBar.close();
1910 this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.users.join(', ')).replace('{1}', this.httprequest.desktop.kvm.rusers.join(', ')), require('MeshAgent')._tsid);
1911 this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
2191 - this.httprequest.desktop.kvm.connectionBar.on('close', function ()
2192 - {
1912 + this.httprequest.desktop.kvm.connectionBar.on('close', function () {
1913 MeshServerLogEx(29, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2194 - for (var i in this.httprequest.desktop.kvm._pipedStreams)
2195 - {
1914 + for (var i in this.httprequest.desktop.kvm._pipedStreams) {
1915 this.httprequest.desktop.kvm._pipedStreams[i].end();
1916 }
1917 this.httprequest.desktop.kvm.end();
@@ -2202,40 +1921,34 @@ function onTunnelData(data)
1921 }
1922 }
1923 };
2205 - if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount'))
2206 - {
1924 + if (this.httprequest.desktop.kvm.hasOwnProperty('connectionCount')) {
1925 this.httprequest.desktop.kvm.connectionCount++;
1926 this.httprequest.desktop.kvm.rusers.push(this.httprequest.realname);
1927 this.httprequest.desktop.kvm.users.push(this.httprequest.username);
1928 this.httprequest.desktop.kvm.rusers.sort();
1929 this.httprequest.desktop.kvm.users.sort();
2212 - } else
2213 - {
1930 + } else {
1931 this.httprequest.desktop.kvm.connectionCount = 1;
1932 this.httprequest.desktop.kvm.rusers = [this.httprequest.realname];
1933 this.httprequest.desktop.kvm.users = [this.httprequest.username];
1934 }
1935
2219 - if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0)))
2220 - {
1936 + if ((this.httprequest.rights == 0xFFFFFFFF) || (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) != 0) && ((this.httprequest.rights & MESHRIGHT_REMOTEVIEW) == 0))) {
1937 // If we have remote control rights, pipe the KVM input
1938 this.pipe(this.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text. Pipe the Browser --> KVM input.
2223 - } else
2224 - {
1939 + } else {
1940 // We need to only pipe non-mouse & non-keyboard inputs.
1941 //sendConsoleText('Warning: No Remote Desktop Input Rights.');
1942 // TODO!!!
1943 }
1944
1945 // Perform notification if needed. Toast messages may not be supported on all platforms.
2231 - if (this.httprequest.consent && (this.httprequest.consent & 8))
2232 - {
1946 + if (this.httprequest.consent && (this.httprequest.consent & 8)) {
1947 // User Consent Prompt is required
1948 // Send a console message back using the console channel, "\n" is supported.
1949 this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
1950 var consentMessage = this.httprequest.realname + " requesting remote desktop access. Grant access?", consentTitle = 'MeshCentral';
2237 - if (this.httprequest.soptions != null)
2238 - {
1951 + if (this.httprequest.soptions != null) {
1952 if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
1953 if (this.httprequest.soptions.consentMsgDesktop != null) { consentMessage = this.httprequest.soptions.consentMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
1954 }
@@ -2245,51 +1958,40 @@ function onTunnelData(data)
1958 this._consentpromise = pr;
1959 this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
1960 pr.then(
2248 - function ()
2249 - {
1961 + function () {
1962 // Success
1963 this.ws._consentpromise = null;
1964 MeshServerLogEx(30, null, "Starting remote desktop after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1965 this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null, msgid: 0 }));
2254 - if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1))
2255 - {
1966 + if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 1)) {
1967 // User Notifications is required
1968 var notifyMessage = this.ws.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
2258 - if (this.ws.httprequest.soptions != null)
2259 - {
1969 + if (this.ws.httprequest.soptions != null) {
1970 if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
1971 if (this.ws.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.ws.httprequest.realname).replace('{1}', this.ws.httprequest.username); }
1972 }
1973 try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
1974 }
2265 - if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 0x40))
2266 - {
1975 + if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 0x40)) {
1976 // Connection Bar is required
2268 - if (this.ws.httprequest.desktop.kvm.connectionBar)
2269 - {
1977 + if (this.ws.httprequest.desktop.kvm.connectionBar) {
1978 this.ws.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
1979 this.ws.httprequest.desktop.kvm.connectionBar.close();
1980 }
2273 - try
2274 - {
1981 + try {
1982 this.ws.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.ws.httprequest.privacybartext.replace('{0}', this.ws.httprequest.desktop.kvm.users.join(', ')).replace('{1}', this.ws.httprequest.desktop.kvm.rusers.join(', ')), require('MeshAgent')._tsid);
1983 MeshServerLogEx(31, null, "Remote Desktop Connection Bar Activated/Updated (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1984 }
2278 - catch (e)
2279 - {
2280 - if (process.platform != 'darwin')
2281 - {
1985 + catch (e) {
1986 + if (process.platform != 'darwin') {
1987 MeshServerLogEx(32, null, "Remote Desktop Connection Bar Failed or Not Supported (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
1988 }
1989 }
2285 - if (this.ws.httprequest.desktop.kvm.connectionBar)
2286 - {
1990 + if (this.ws.httprequest.desktop.kvm.connectionBar) {
1991 this.ws.httprequest.desktop.kvm.connectionBar.httprequest = this.ws.httprequest;
2288 - this.ws.httprequest.desktop.kvm.connectionBar.on('close', function ()
2289 - {
1992 + this.ws.httprequest.desktop.kvm.connectionBar.on('close', function () {
1993 MeshServerLogEx(33, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2291 - for (var i in this.httprequest.desktop.kvm._pipedStreams)
2292 - {
1994 + for (var i in this.httprequest.desktop.kvm._pipedStreams) {
1995 this.httprequest.desktop.kvm._pipedStreams[i].end();
1996 }
1997 this.httprequest.desktop.kvm.end();
@@ -2299,56 +2001,44 @@ function onTunnelData(data)
2001 this.ws.httprequest.desktop.kvm.pipe(this.ws, { dataTypeSkip: 1 });
2002 this.ws.resume();
2003 },
2302 - function (e)
2303 - {
2004 + function (e) {
2005 // User Consent Denied/Failed
2006 this.ws._consentpromise = null;
2007 MeshServerLogEx(34, null, "Failed to start remote desktop after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2008 this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2009 });
2309 - } else
2310 - {
2010 + } else {
2011 // User Consent Prompt is not required
2312 - if (this.httprequest.consent && (this.httprequest.consent & 1))
2313 - {
2012 + if (this.httprequest.consent && (this.httprequest.consent & 1)) {
2013 // User Notifications is required
2014 MeshServerLogEx(35, null, "Started remote desktop with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2015 var notifyMessage = this.httprequest.realname + " started a remote desktop session.", notifyTitle = "MeshCentral";
2317 - if (this.httprequest.soptions != null)
2318 - {
2016 + if (this.httprequest.soptions != null) {
2017 if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2018 if (this.httprequest.soptions.notifyMsgDesktop != null) { notifyMessage = this.httprequest.soptions.notifyMsgDesktop.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2019 }
2020 try { require('toaster').Toast(notifyTitle, notifyMessage, tsid); } catch (e) { }
2323 - } else
2324 - {
2021 + } else {
2022 MeshServerLogEx(36, null, "Started remote desktop without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2023 }
2327 - if (this.httprequest.consent && (this.httprequest.consent & 0x40))
2328 - {
2024 + if (this.httprequest.consent && (this.httprequest.consent & 0x40)) {
2025 // Connection Bar is required
2330 - if (this.httprequest.desktop.kvm.connectionBar)
2331 - {
2026 + if (this.httprequest.desktop.kvm.connectionBar) {
2027 this.httprequest.desktop.kvm.connectionBar.removeAllListeners('close');
2028 this.httprequest.desktop.kvm.connectionBar.close();
2029 }
2335 - try
2336 - {
2030 + try {
2031 this.httprequest.desktop.kvm.connectionBar = require('notifybar-desktop')(this.httprequest.privacybartext.replace('{0}', this.httprequest.desktop.kvm.rusers.join(', ')).replace('{1}', this.httprequest.desktop.kvm.users.join(', ')), require('MeshAgent')._tsid);
2032 MeshServerLogEx(37, null, "Remote Desktop Connection Bar Activated/Updated (" + this.httprequest.remoteaddr + ")", this.httprequest);
2033 }
2340 - catch (e)
2341 - {
2034 + catch (e) {
2035 MeshServerLogEx(38, null, "Remote Desktop Connection Bar Failed or not Supported (" + this.httprequest.remoteaddr + ")", this.httprequest);
2036 }
2344 - if (this.httprequest.desktop.kvm.connectionBar)
2345 - {
2037 + if (this.httprequest.desktop.kvm.connectionBar) {
2038 this.httprequest.desktop.kvm.connectionBar.httprequest = this.httprequest;
2347 - this.httprequest.desktop.kvm.connectionBar.on('close', function ()
2348 - {
2039 + this.httprequest.desktop.kvm.connectionBar.on('close', function () {
2040 MeshServerLogEx(39, null, "Remote Desktop Connection forcefully closed by local user (" + this.httprequest.remoteaddr + ")", this.httprequest);
2350 - for (var i in this.httprequest.desktop.kvm._pipedStreams)
2351 - {
2041 + for (var i in this.httprequest.desktop.kvm._pipedStreams) {
2042 this.httprequest.desktop.kvm._pipedStreams[i].end();
2043 }
2044 this.httprequest.desktop.kvm.end();
@@ -2362,15 +2052,13 @@ function onTunnelData(data)
2052 this.on('data', onTunnelControlData);
2053 //this.write('MeshCore KVM Hello!1');
2054
2365 - } else if (this.httprequest.protocol == 5)
2366 - {
2055 + } else if (this.httprequest.protocol == 5) {
2056 //
2057 // Remote Files
2058 //
2059
2060 // Check user access rights for files
2372 - if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0)))
2373 - {
2061 + if (((this.httprequest.rights & MESHRIGHT_REMOTECONTROL) == 0) || ((this.httprequest.rights != 0xFFFFFFFF) && ((this.httprequest.rights & MESHRIGHT_NOFILES) != 0))) {
2062 // Disengage this tunnel, user does not have the rights to do this!!
2063 this.httprequest.protocol = 999999;
2064 this.httprequest.s.end();
@@ -2381,18 +2069,15 @@ function onTunnelData(data)
2069 this.descriptorMetadata = "Remote Files";
2070
2071 // Add the files session to the count to update the server
2384 - if (this.httprequest.userid != null)
2385 - {
2072 + if (this.httprequest.userid != null) {
2073 if (tunnelUserCount.files[this.httprequest.userid] == null) { tunnelUserCount.files[this.httprequest.userid] = 1; } else { tunnelUserCount.files[this.httprequest.userid]++; }
2074 try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2075 broadcastSessionsToRegisteredApps();
2076 }
2077
2391 - this.end = function ()
2392 - {
2078 + this.end = function () {
2079 // Remove the files session from the count to update the server
2394 - if (this.httprequest.userid != null)
2395 - {
2080 + if (this.httprequest.userid != null) {
2081 if (tunnelUserCount.files[this.httprequest.userid] != null) { tunnelUserCount.files[this.httprequest.userid]--; if (tunnelUserCount.files[this.httprequest.userid] <= 0) { delete tunnelUserCount.files[this.httprequest.userid]; } }
2082 try { mesh.SendCommand({ action: 'sessions', type: 'files', value: tunnelUserCount.files }); } catch (e) { }
2083 broadcastSessionsToRegisteredApps();
@@ -2400,14 +2085,12 @@ function onTunnelData(data)
2085 };
2086
2087 // Perform notification if needed. Toast messages may not be supported on all platforms.
2403 - if (this.httprequest.consent && (this.httprequest.consent & 32))
2404 - {
2088 + if (this.httprequest.consent && (this.httprequest.consent & 32)) {
2089 // User Consent Prompt is required
2090 // Send a console message back using the console channel, "\n" is supported.
2091 this.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: "Waiting for user to grant access...", msgid: 1 }));
2092 var consentMessage = this.httprequest.realname + " requesting remote file Access. Grant access?", consentTitle = 'MeshCentral';
2409 - if (this.httprequest.soptions != null)
2410 - {
2093 + if (this.httprequest.soptions != null) {
2094 if (this.httprequest.soptions.consentTitle != null) { consentTitle = this.httprequest.soptions.consentTitle; }
2095 if (this.httprequest.soptions.consentMsgFiles != null) { consentMessage = this.httprequest.soptions.consentMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2096 }
@@ -2417,18 +2100,15 @@ function onTunnelData(data)
2100 this._consentpromise = pr;
2101 this.prependOnceListener('end', function () { if (this._consentpromise && this._consentpromise.close) { this._consentpromise.close(); } });
2102 pr.then(
2420 - function ()
2421 - {
2103 + function () {
2104 // Success
2105 this.ws._consentpromise = null;
2106 MeshServerLogEx(40, null, "Starting remote files after local user accepted (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2107 this.ws.write(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: null }));
2426 - if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4))
2427 - {
2108 + if (this.ws.httprequest.consent && (this.ws.httprequest.consent & 4)) {
2109 // User Notifications is required
2110 var notifyMessage = this.ws.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2430 - if (this.ws.httprequest.soptions != null)
2431 - {
2111 + if (this.ws.httprequest.soptions != null) {
2112 if (this.ws.httprequest.soptions.notifyTitle != null) { notifyTitle = this.ws.httprequest.soptions.notifyTitle; }
2113 if (this.ws.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.ws.httprequest.soptions.notifyMsgFiles.replace('{0}', this.ws.httprequest.realname).replace('{1}', this.ws.httprequest.username); }
2114 }
@@ -2436,29 +2116,24 @@ function onTunnelData(data)
2116 }
2117 this.ws.resume();
2118 },
2439 - function (e)
2440 - {
2119 + function (e) {
2120 // User Consent Denied/Failed
2121 this.ws._consentpromise = null;
2122 MeshServerLogEx(41, null, "Failed to start remote files after local user rejected (" + this.ws.httprequest.remoteaddr + ")", this.ws.httprequest);
2123 this.ws.end(JSON.stringify({ ctrlChannel: '102938', type: 'console', msg: e.toString(), msgid: 2 }));
2124 });
2446 - } else
2447 - {
2125 + } else {
2126 // User Consent Prompt is not required
2449 - if (this.httprequest.consent && (this.httprequest.consent & 4))
2450 - {
2127 + if (this.httprequest.consent && (this.httprequest.consent & 4)) {
2128 // User Notifications is required
2129 MeshServerLogEx(42, null, "Started remote files with toast notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2130 var notifyMessage = this.httprequest.realname + " started a remote file session.", notifyTitle = "MeshCentral";
2454 - if (this.httprequest.soptions != null)
2455 - {
2131 + if (this.httprequest.soptions != null) {
2132 if (this.httprequest.soptions.notifyTitle != null) { notifyTitle = this.httprequest.soptions.notifyTitle; }
2133 if (this.httprequest.soptions.notifyMsgFiles != null) { notifyMessage = this.httprequest.soptions.notifyMsgFiles.replace('{0}', this.httprequest.realname).replace('{1}', this.httprequest.username); }
2134 }
2135 try { require('toaster').Toast(notifyTitle, notifyMessage); } catch (e) { }
2460 - } else
2461 - {
2136 + } else {
2137 MeshServerLogEx(43, null, "Started remote files without notification (" + this.httprequest.remoteaddr + ")", this.httprequest);
2138 }
2139 this.resume();
@@ -2467,23 +2142,18 @@ function onTunnelData(data)
2142 // Setup files
2143 // NOP
2144 }
2470 - } else if (this.httprequest.protocol == 1)
2471 - {
2145 + } else if (this.httprequest.protocol == 1) {
2146 // Send data into terminal stdin
2147 //this.write(data); // Echo back the keys (Does not seem to be a good idea)
2474 - } else if (this.httprequest.protocol == 2)
2475 - {
2148 + } else if (this.httprequest.protocol == 2) {
2149 // Send data into remote desktop
2477 - if (this.httprequest.desktop.state == 0)
2478 - {
2150 + if (this.httprequest.desktop.state == 0) {
2151 this.write(Buffer.from(String.fromCharCode(0x11, 0xFE, 0x00, 0x00, 0x4D, 0x45, 0x53, 0x48, 0x00, 0x00, 0x00, 0x00, 0x02)));
2152 this.httprequest.desktop.state = 1;
2481 - } else
2482 - {
2153 + } else {
2154 this.httprequest.desktop.write(data);
2155 }
2485 - } else if (this.httprequest.protocol == 5)
2486 - {
2156 + } else if (this.httprequest.protocol == 5) {
2157 // Process files commands
2158 var cmd = null;
2159 try { cmd = JSON.parse(data); } catch (e) { };
@@ -2494,8 +2164,7 @@ function onTunnelData(data)
2164
2165 if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
2166 //console.log(objToString(cmd, 0, ' '));
2497 - switch (cmd.action)
2498 - {
2167 + switch (cmd.action) {
2168 case 'ls': {
2169 /*
2170 // Close the watcher if required
@@ -2532,20 +2201,15 @@ function onTunnelData(data)
2201 }
2202 case 'rm': {
2203 // Delete, possibly recursive delete
2535 - for (var i in cmd.delfiles)
2536 - {
2204 + for (var i in cmd.delfiles) {
2205 var p = obj.path.join(cmd.path, cmd.delfiles[i]), delcount = 0;
2206 try { delcount = deleteFolderRecursive(p, cmd.rec); } catch (e) { }
2539 - if ((delcount == 1) && !cmd.rec)
2540 - {
2207 + if ((delcount == 1) && !cmd.rec) {
2208 MeshServerLogEx(45, [p], "Delete: \"" + p + "\"", this.httprequest);
2542 - } else
2543 - {
2544 - if (cmd.rec)
2545 - {
2209 + } else {
2210 + if (cmd.rec) {
2211 MeshServerLogEx(46, [p, delcount], "Delete recursive: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2547 - } else
2548 - {
2212 + } else {
2213 MeshServerLogEx(47, [p, delcount], "Delete: \"" + p + "\", " + delcount + " element(s) removed", this.httprequest);
2214 }
2215 }
@@ -2555,11 +2219,9 @@ function onTunnelData(data)
2219 case 'markcoredump': {
2220 // If we are asking for the coredump file, set the right path.
2221 var coreDumpPath = null;
2558 - if (process.platform == 'win32')
2559 - {
2222 + if (process.platform == 'win32') {
2223 if (fs.existsSync(process.coreDumpLocation)) { coreDumpPath = process.coreDumpLocation; }
2561 - } else
2562 - {
2224 + } else {
2225 if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { coreDumpPath = process.cwd() + 'core'; }
2226 }
2227 if (coreDumpPath != null) { db.Put('CoreDumpTime', require('fs').statSync(coreDumpPath).mtime); }
@@ -2596,15 +2258,11 @@ function onTunnelData(data)
2258 {
2259 // Download a file
2260 var sendNextBlock = 0;
2599 - if (cmd.sub == 'start')
2600 - { // Setup the download
2601 - if ((cmd.path == null) && (cmd.ask == 'coredump'))
2602 - { // If we are asking for the coredump file, set the right path.
2603 - if (process.platform == 'win32')
2604 - {
2261 + if (cmd.sub == 'start') { // Setup the download
2262 + if ((cmd.path == null) && (cmd.ask == 'coredump')) { // If we are asking for the coredump file, set the right path.
2263 + if (process.platform == 'win32') {
2264 if (fs.existsSync(process.coreDumpLocation)) { cmd.path = process.coreDumpLocation; }
2606 - } else
2607 - {
2265 + } else {
2266 if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) { cmd.path = process.cwd() + 'core'; }
2267 }
2268 }
@@ -2613,13 +2271,11 @@ function onTunnelData(data)
2271 this.filedownload = { id: cmd.id, path: cmd.path, ptr: 0 }
2272 try { this.filedownload.f = fs.openSync(this.filedownload.path, 'rbN'); } catch (e) { this.write({ action: 'download', sub: 'cancel', id: this.filedownload.id }); delete this.filedownload; }
2273 if (this.filedownload) { this.write({ action: 'download', sub: 'start', id: cmd.id }); }
2616 - } else if ((this.filedownload != null) && (cmd.id == this.filedownload.id))
2617 - { // Download commands
2274 + } else if ((this.filedownload != null) && (cmd.id == this.filedownload.id)) { // Download commands
2275 if (cmd.sub == 'startack') { sendNextBlock = ((typeof cmd.ack == 'number') ? cmd.ack : 8); } else if (cmd.sub == 'stop') { delete this.filedownload; } else if (cmd.sub == 'ack') { sendNextBlock = 1; }
2276 }
2277 // Send the next download block(s)
2621 - while (sendNextBlock > 0)
2622 - {
2278 + while (sendNextBlock > 0) {
2279 sendNextBlock--;
2280 var buf = Buffer.alloc(16384);
2281 var len = fs.readSync(this.filedownload.f, buf, 4, 16380, null);
@@ -2645,8 +2301,7 @@ function onTunnelData(data)
2301 case 'uploaddone':
2302 {
2303 // Indicates that an upload is done
2648 - if (this.httprequest.uploadFile)
2649 - {
2304 + if (this.httprequest.uploadFile) {
2305 fs.closeSync(this.httprequest.uploadFile);
2306 this.write(Buffer.from(JSON.stringify({ action: 'uploaddone', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
2307 delete this.httprequest.uploadFile;
@@ -2658,8 +2313,7 @@ function onTunnelData(data)
2313 case 'uploadcancel':
2314 {
2315 // Indicates that an upload is canceled
2661 - if (this.httprequest.uploadFile)
2662 - {
2316 + if (this.httprequest.uploadFile) {
2317 fs.closeSync(this.httprequest.uploadFile);
2318 fs.unlinkSync(this.httprequest.uploadFilePath);
2319 this.write(Buffer.from(JSON.stringify({ action: 'uploadcancel', reqid: this.httprequest.uploadFileid }))); // Indicate that we closed the file.
@@ -2672,8 +2326,7 @@ function onTunnelData(data)
2326 case 'copy':
2327 {
2328 // Copy a bunch of files from scpath to dspath
2675 - for (var i in cmd.names)
2676 - {
2329 + for (var i in cmd.names) {
2330 var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2331 MeshServerLogEx(51, [sc, ds], 'Copy: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2332 if (sc != ds) { try { fs.copyFileSync(sc, ds); } catch (e) { } }
@@ -2683,8 +2336,7 @@ function onTunnelData(data)
2336 case 'move':
2337 {
2338 // Move a bunch of files from scpath to dspath
2686 - for (var i in cmd.names)
2687 - {
2339 + for (var i in cmd.names) {
2340 var sc = obj.path.join(cmd.scpath, cmd.names[i]), ds = obj.path.join(cmd.dspath, cmd.names[i]);
2341 MeshServerLogEx(52, [sc, ds], 'Move: \"' + sc + '\" to \"' + ds + '\"', this.httprequest);
2342 if (sc != ds) { try { fs.copyFileSync(sc, ds); fs.unlinkSync(sc); } catch (e) { } }
@@ -2707,8 +2359,7 @@ function onTunnelData(data)
2359 delete this.zipcancel;
2360 var out = require('fs').createWriteStream(ofile, { flags: 'wb' });
2361 out.xws = this;
2710 - out.on('close', function ()
2711 - {
2362 + out.on('close', function () {
2363 this.xws.write(Buffer.from(JSON.stringify({ action: 'dialogmessage', msg: null })));
2364 this.xws.write(Buffer.from(JSON.stringify({ action: 'refresh' })));
2365 if (this.xws.zipcancel === true) { fs.unlinkSync(this.xws.zipfile); } // Delete the complete file.
@@ -2730,16 +2381,14 @@ function onTunnelData(data)
2381 // Unknown action, ignore it.
2382 break;
2383 }
2733 - } else if (this.httprequest.protocol == 7)
2734 - { // Plugin data exchange
2384 + } else if (this.httprequest.protocol == 7) { // Plugin data exchange
2385 var cmd = null;
2386 try { cmd = JSON.parse(data); } catch (e) { };
2387 if (cmd == null) { return; }
2388 if ((cmd.ctrlChannel == '102938') || ((cmd.type == 'offer') && (cmd.sdp != null))) { onTunnelControlData(cmd, this); return; } // If this is control data, handle it now.
2389 if (cmd.action == undefined) return;
2390
2741 - switch (cmd.action)
2742 - {
2391 + switch (cmd.action) {
2392 case 'plugin': {
2393 try { require(cmd.plugin).consoleaction(cmd, null, null, this); } catch (e) { throw e; }
2394 break;
@@ -2755,21 +2404,15 @@ function onTunnelData(data)
2404 }
2405
2406 // Delete a directory with a files and directories within it
2758 -function deleteFolderRecursive(path, rec)
2759 -{
2407 +function deleteFolderRecursive(path, rec) {
2408 var count = 0;
2761 - if (fs.existsSync(path))
2762 - {
2763 - if (rec == true)
2764 - {
2765 - fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index)
2766 - {
2409 + if (fs.existsSync(path)) {
2410 + if (rec == true) {
2411 + fs.readdirSync(obj.path.join(path, '*')).forEach(function (file, index) {
2412 var curPath = obj.path.join(path, file);
2768 - if (fs.statSync(curPath).isDirectory())
2769 - { // recurse
2413 + if (fs.statSync(curPath).isDirectory()) { // recurse
2414 count += deleteFolderRecursive(curPath, true);
2771 - } else
2772 - { // delete file
2415 + } else { // delete file
2416 fs.unlinkSync(curPath);
2417 count++;
2418 }
@@ -2782,13 +2425,11 @@ function deleteFolderRecursive(path, rec)
2425 }
2426
2427 // Called when receiving control data on WebRTC
2785 -function onTunnelWebRTCControlData(data)
2786 -{
2428 +function onTunnelWebRTCControlData(data) {
2429 if (typeof data != 'string') return;
2430 var obj;
2431 try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON on WebRTC: ' + data); return; }
2790 - if (obj.type == 'close')
2791 - {
2432 + if (obj.type == 'close') {
2433 //sendConsoleText('Tunnel #' + this.xrtc.websocket.tunnel.index + ' WebRTC control close');
2434 try { this.close(); } catch (e) { }
2435 try { this.xrtc.close(); } catch (e) { }
@@ -2796,8 +2437,7 @@ function onTunnelWebRTCControlData(data)
2437 }
2438
2439 // Called when receiving control data on websocket
2799 -function onTunnelControlData(data, ws)
2800 -{
2440 +function onTunnelControlData(data, ws) {
2441 var obj;
2442 if (ws == null) { ws = this; }
2443 if (typeof data == 'string') { try { obj = JSON.parse(data); } catch (e) { sendConsoleText('Invalid control JSON: ' + data); return; } }
@@ -2805,16 +2445,12 @@ function onTunnelControlData(data, ws)
2445 //sendConsoleText('onTunnelControlData(' + ws.httprequest.protocol + '): ' + JSON.stringify(data));
2446 //console.log('onTunnelControlData: ' + JSON.stringify(data));
2447
2808 - if (obj.action)
2809 - {
2810 - switch (obj.action)
2811 - {
2448 + if (obj.action) {
2449 + switch (obj.action) {
2450 case 'lock': {
2451 // Lock the current user out of the desktop
2814 - try
2815 - {
2816 - if (process.platform == 'win32')
2817 - {
2452 + try {
2453 + if (process.platform == 'win32') {
2454 MeshServerLogEx(53, null, "Locking remote user out of desktop", ws.httprequest);
2455 var child = require('child_process');
2456 child.execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'RunDll32.exe user32.dll,LockWorkStation'], { type: 1 });
@@ -2829,8 +2465,7 @@ function onTunnelControlData(data, ws)
2465 return;
2466 }
2467
2832 - switch (obj.type)
2833 - {
2468 + switch (obj.type) {
2469 case 'options': {
2470 // These are additional connection options passed in the control channel.
2471 //sendConsoleText('options: ' + JSON.stringify(obj));
@@ -2850,13 +2485,11 @@ function onTunnelControlData(data, ws)
2485 }
2486 case 'termsize': {
2487 // Indicates a change in terminal size
2853 - if (process.platform == 'win32')
2854 - {
2488 + if (process.platform == 'win32') {
2489 if (ws.httprequest._dispatcher == null) return;
2490 //sendConsoleText('Win32-TermSize: ' + obj.cols + 'x' + obj.rows);
2491 if (ws.httprequest._dispatcher.invoke) { ws.httprequest._dispatcher.invoke('resizeTerminal', [obj.cols, obj.rows]); }
2858 - } else
2859 - {
2492 + } else {
2493 if (ws.httprequest.process == null || ws.httprequest.process.pty == 0) return;
2494 //sendConsoleText('Linux Resize: ' + obj.cols + 'x' + obj.rows);
2495
@@ -2865,23 +2498,18 @@ function onTunnelControlData(data, ws)
2498 break;
2499 }
2500 case 'webrtc0': { // Browser indicates we can start WebRTC switch-over.
2868 - if (ws.httprequest.protocol == 1)
2869 - { // Terminal
2501 + if (ws.httprequest.protocol == 1) { // Terminal
2502 // This is a terminal data stream, unpipe the terminal now and indicate to the other side that terminal data will no longer be received over WebSocket
2871 - if (process.platform == 'win32')
2872 - {
2503 + if (process.platform == 'win32') {
2504 ws.httprequest._term.unpipe(ws);
2874 - } else
2875 - {
2505 + } else {
2506 ws.httprequest.process.stdout.unpipe(ws);
2507 ws.httprequest.process.stderr.unpipe(ws);
2508 }
2879 - } else if (ws.httprequest.protocol == 2)
2880 - { // Desktop
2509 + } else if (ws.httprequest.protocol == 2) { // Desktop
2510 // This is a KVM data stream, unpipe the KVM now and indicate to the other side that KVM data will no longer be received over WebSocket
2511 ws.httprequest.desktop.kvm.unpipe(ws);
2883 - } else
2884 - {
2512 + } else {
2513 // Switch things around so all WebRTC data goes to onTunnelData().
2514 ws.rtcchannel.httprequest = ws.httprequest;
2515 ws.rtcchannel.removeAllListeners('data');
@@ -2891,21 +2519,17 @@ function onTunnelControlData(data, ws)
2519 break;
2520 }
2521 case 'webrtc1': {
2894 - if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6))
2895 - { // Terminal
2522 + if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
2523 // Switch the user input from websocket to webrtc at this point.
2897 - if (process.platform == 'win32')
2898 - {
2524 + if (process.platform == 'win32') {
2525 ws.unpipe(ws.httprequest._term);
2526 ws.rtcchannel.pipe(ws.httprequest._term, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2901 - } else
2902 - {
2527 + } else {
2528 ws.unpipe(ws.httprequest.process.stdin);
2529 ws.rtcchannel.pipe(ws.httprequest.process.stdin, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2530 }
2531 ws.resume(); // Resume the websocket to keep receiving control data
2907 - } else if (ws.httprequest.protocol == 2)
2908 - { // Desktop
2532 + } else if (ws.httprequest.protocol == 2) { // Desktop
2533 // Switch the user input from websocket to webrtc at this point.
2534 ws.unpipe(ws.httprequest.desktop.kvm);
2535 try { ws.webrtc.rtcchannel.pipe(ws.httprequest.desktop.kvm, { dataTypeSkip: 1, end: false }); } catch (e) { sendConsoleText('EX2'); } // 0 = Binary, 1 = Text.
@@ -2916,18 +2540,14 @@ function onTunnelControlData(data, ws)
2540 }
2541 case 'webrtc2': {
2542 // Other side received websocket end of data marker, start sending data on WebRTC channel
2919 - if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6))
2920 - { // Terminal
2921 - if (process.platform == 'win32')
2922 - {
2543 + if ((ws.httprequest.protocol == 1) || (ws.httprequest.protocol == 6)) { // Terminal
2544 + if (process.platform == 'win32') {
2545 ws.httprequest._term.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2924 - } else
2925 - {
2546 + } else {
2547 ws.httprequest.process.stdout.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2548 ws.httprequest.process.stderr.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1, end: false }); // 0 = Binary, 1 = Text.
2549 }
2929 - } else if (ws.httprequest.protocol == 2)
2930 - { // Desktop
2550 + } else if (ws.httprequest.protocol == 2) { // Desktop
2551 ws.httprequest.desktop.kvm.pipe(ws.webrtc.rtcchannel, { dataTypeSkip: 1 }); // 0 = Binary, 1 = Text.
2552 }
2553 break;
@@ -2939,8 +2559,7 @@ function onTunnelControlData(data, ws)
2559 ws.webrtc.websocket = ws;
2560 ws.webrtc.on('connected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC connected');*/ });
2561 ws.webrtc.on('disconnected', function () { /*sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC disconnected');*/ });
2942 - ws.webrtc.on('dataChannel', function (rtcchannel)
2943 - {
2562 + ws.webrtc.on('dataChannel', function (rtcchannel) {
2563 //sendConsoleText('WebRTC Datachannel open, protocol: ' + this.websocket.httprequest.protocol);
2564 rtcchannel.maxFragmentSize = 32768;
2565 rtcchannel.xrtc = this;
@@ -2948,14 +2567,11 @@ function onTunnelControlData(data, ws)
2567 this.rtcchannel = rtcchannel;
2568 this.websocket.rtcchannel = rtcchannel;
2569 this.websocket.rtcchannel.on('data', onTunnelWebRTCControlData);
2951 - this.websocket.rtcchannel.on('end', function ()
2952 - {
2570 + this.websocket.rtcchannel.on('end', function () {
2571 // The WebRTC channel closed, unpipe the KVM now. This is also done when the web socket closes.
2572 //sendConsoleText('Tunnel #' + this.websocket.tunnel.index + ' WebRTC data channel closed');
2955 - if (this.websocket.desktop && this.websocket.desktop.kvm)
2956 - {
2957 - try
2958 - {
2573 + if (this.websocket.desktop && this.websocket.desktop.kvm) {
2574 + try {
2575 this.unpipe(this.websocket.desktop.kvm);
2576 this.websocket.httprequest.desktop.kvm.unpipe(this);
2577 }
@@ -2988,21 +2604,17 @@ var consoleWebSockets = {};
2604 var consoleHttpRequest = null;
2605
2606 // Console HTTP response
2991 -function consoleHttpResponse(response)
2992 -{
2607 +function consoleHttpResponse(response) {
2608 response.data = function (data) { sendConsoleText(rstr2hex(buf2rstr(data)), this.sessionid); consoleHttpRequest = null; }
2609 response.close = function () { sendConsoleText('httprequest.response.close', this.sessionid); consoleHttpRequest = null; }
2610 }
2611
2612 // Open a web browser to a specified URL on current user's desktop
2998 -function openUserDesktopUrl(url)
2999 -{
2613 +function openUserDesktopUrl(url) {
2614 if ((url.toLowerCase().startsWith('http://') == false) && (url.toLowerCase().startsWith('https://') == false)) { return null; }
2615 var child = null;
3002 - try
3003 - {
3004 - switch (process.platform)
3005 - {
2616 + try {
2617 + switch (process.platform) {
2618 case 'win32':
2619 var user = require('user-sessions').getUsername(require('user-sessions').consoleUid());
2620 child = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['cmd']);
@@ -3029,13 +2641,10 @@ function openUserDesktopUrl(url)
2641 }
2642
2643 // Process a mesh agent console command
3032 -function processConsoleCommand(cmd, args, rights, sessionid)
3033 -{
3034 - try
3035 - {
2644 +function processConsoleCommand(cmd, args, rights, sessionid) {
2645 + try {
2646 var response = null;
3037 - switch (cmd)
3038 - {
2647 + switch (cmd) {
2648 case 'help': { // Displays available commands
2649 var fin = '', f = '', availcommands = 'agentupdate,msh,timerinfo,coreinfo,coredump,service,fdsnapshot,fdcount,startupoptions,alert,agentsize,versions,help,info,osinfo,args,print,type,dbkeys,dbget,dbset,dbcompact,eval,parseuri,httpget,nwslist,plugin,wsconnect,wssend,wsclose,notify,ls,ps,kill,netinfo,location,power,wakeonlan,setdebug,smbios,rawsmbios,toast,lock,users,openurl,getscript,getclip,setclip,log,av,cpuinfo,sysinfo,apf,scanwifi,wallpaper,agentmsg';
2650 if (process.platform == 'win32') { availcommands += ',safemode,wpfhwacceleration,uac'; }
@@ -3045,8 +2654,7 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2654 try { require('zip-reader'); availcommands += ',zip,unzip'; } catch (e) { }
2655
2656 availcommands = availcommands.split(',').sort();
3048 - while (availcommands.length > 0)
3049 - {
2657 + while (availcommands.length > 0) {
2658 if (f.length > 90) { fin += (f + ',\r\n'); f = ''; }
2659 f += (((f != '') ? ', ' : ' ') + availcommands.shift());
2660 }
@@ -3068,12 +2676,10 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2676 response = require('ChainViewer').getTimerInfo();
2677 break;
2678 case 'find':
3071 - if (args['_'].length <= 1)
3072 - {
2679 + if (args['_'].length <= 1) {
2680 response = "Proper usage:\r\n find root criteria [criteria2] [criteria n...]";
2681 }
3075 - else
3076 - {
2682 + else {
2683 var root = args['_'][0];
2684 var p = args['_'].slice(1);
2685 var r = require('file-search').find(root, p);
@@ -3092,26 +2698,21 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2698 break;
2699 }
2700 case 'agentmsg': {
3095 - if (args['_'].length == 0)
3096 - {
2701 + if (args['_'].length == 0) {
2702 response = "Proper usage:\r\n agentmsg add \"[message]\" [iconIndex]\r\n agentmsg remove [index]\r\n agentmsg list"; // Display usage
3098 - } else
3099 - {
3100 - if ((args['_'][0] == 'add') && (args['_'].length > 1))
3101 - {
2703 + } else {
2704 + if ((args['_'][0] == 'add') && (args['_'].length > 1)) {
2705 var msgIndex = 1, iconIndex = 0;
2706 while (tunnelUserCount.msg[msgIndex] != null) { msgIndex++; }
2707 if (args['_'].length >= 3) { try { iconIndex = parseInt(args['_'][2]); } catch (e) { } }
2708 if (typeof iconIndex != 'number') { iconIndex = 0; }
2709 tunnelUserCount.msg[msgIndex] = { msg: args['_'][1], icon: iconIndex };
2710 response = 'Agent message ' + msgIndex + ' added.';
3108 - } else if ((args['_'][0] == 'remove') && (args['_'].length > 1))
3109 - {
2711 + } else if ((args['_'][0] == 'remove') && (args['_'].length > 1)) {
2712 var msgIndex = 0;
2713 try { msgIndex = parseInt(args['_'][1]); } catch (x) { }
2714 if (tunnelUserCount.msg[msgIndex] == null) { response = "Message not found."; } else { delete tunnelUserCount.msg[msgIndex]; response = "Message removed."; }
3113 - } else if (args['_'][0] == 'list')
3114 - {
2715 + } else if (args['_'][0] == 'list') {
2716 response = JSON.stringify(tunnelUserCount.msg, null, 2);
2717 }
2718 try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (x) { }
@@ -3126,13 +2727,10 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2727 break;
2728 }
2729 case 'coredump':
3129 - if (args['_'].length != 1)
3130 - {
2730 + if (args['_'].length != 1) {
2731 response = "Proper usage: coredump on|off|status|clear"; // Display usage
3132 - } else
3133 - {
3134 - switch (args['_'][0].toLowerCase())
3135 - {
2732 + } else {
2733 + switch (args['_'][0].toLowerCase()) {
2734 case 'on':
2735 process.coreDumpLocation = (process.platform == 'win32') ? (process.execPath.replace('.exe', '.dmp')) : (process.execPath + '.dmp');
2736 response = 'coredump is now on';
@@ -3143,20 +2741,15 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2741 break;
2742 case 'status':
2743 response = 'coredump is: ' + ((process.coreDumpLocation == null) ? 'off' : 'on');
3146 - if (process.coreDumpLocation != null)
3147 - {
3148 - if (process.platform == 'win32')
3149 - {
3150 - if (fs.existsSync(process.coreDumpLocation))
3151 - {
2744 + if (process.coreDumpLocation != null) {
2745 + if (process.platform == 'win32') {
2746 + if (fs.existsSync(process.coreDumpLocation)) {
2747 response += '\r\n CoreDump present at: ' + process.coreDumpLocation;
2748 response += '\r\n CoreDump Time: ' + new Date(fs.statSync(process.coreDumpLocation).mtime).getTime();
2749 response += '\r\n Agent Time : ' + new Date(fs.statSync(process.execPath).mtime).getTime();
2750 }
3156 - } else
3157 - {
3158 - if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core'))
3159 - {
2751 + } else {
2752 + if ((process.cwd() != '//') && fs.existsSync(process.cwd() + 'core')) {
2753 response += '\r\n CoreDump present at: ' + process.cwd() + 'core';
2754 response += '\r\n CoreDump Time: ' + new Date(fs.statSync(process.cwd() + 'core').mtime).getTime();
2755 response += '\r\n Agent Time : ' + new Date(fs.statSync(process.execPath).mtime).getTime();
@@ -3175,33 +2768,26 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2768 }
2769 break;
2770 case 'service':
3178 - if (args['_'].length != 1)
3179 - {
2771 + if (args['_'].length != 1) {
2772 response = "Proper usage: service status|restart"; // Display usage
2773 }
3182 - else
3183 - {
2774 + else {
2775 var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
3185 - try
3186 - {
2776 + try {
2777 svcname = require('MeshAgent').serviceName;
2778 }
3189 - catch (x)
3190 - {
2779 + catch (x) {
2780 }
2781 var s = require('service-manager').manager.getService(svcname);
3193 - switch (args['_'][0].toLowerCase())
3194 - {
2782 + switch (args['_'][0].toLowerCase()) {
2783 case 'status':
2784 response = 'Service ' + (s.isRunning() ? (s.isMe() ? '[SELF]' : '[RUNNING]') : ('[NOT RUNNING]'));
2785 break;
2786 case 'restart':
3199 - if (s.isMe())
3200 - {
2787 + if (s.isMe()) {
2788 s.restart();
2789 }
3203 - else
3204 - {
2790 + else {
2791 response = 'Restarting another agent instance is not allowed';
2792 }
2793 break;
@@ -3213,11 +2799,9 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2799 }
2800 break;
2801 case 'zip':
3216 - if (args['_'].length == 0)
3217 - {
2802 + if (args['_'].length == 0) {
2803 response = "Proper usage: zip (output file name), input1 [, input n]"; // Display usage
3219 - } else
3220 - {
2804 + } else {
2805 var p = args['_'].join(' ').split(',');
2806 var ofile = p.shift();
2807 sendConsoleText('Writing ' + ofile + '...');
@@ -3230,19 +2814,16 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2814 }
2815 break;
2816 case 'unzip':
3233 - if (args['_'].length == 0)
3234 - {
2817 + if (args['_'].length == 0) {
2818 response = "Proper usage: unzip input, destination"; // Display usage
3236 - } else
3237 - {
2819 + } else {
2820 var p = args['_'].join(' ').split(',');
2821 if (p.length != 2) { response = "Proper usage: unzip input, destination"; break; } // Display usage
2822 var prom = require('zip-reader').read(p[0]);
2823 prom._dest = p[1];
2824 prom.self = this;
2825 prom.sessionid = sessionid;
3244 - prom.then(function (zipped)
3245 - {
2826 + prom.then(function (zipped) {
2827 sendConsoleText('Extracting to ' + this._dest + '...', this.sessionid);
2828 zipped.extractAll(this._dest).then(function () { sendConsoleText('finished unzipping', this.sessionid); }, function (e) { sendConsoleText('Error unzipping: ' + e, this.sessionid); }).parentPromise.sessionid = this.sessionid;
2829 }, function (e) { sendConsoleText('Error unzipping: ' + e, this.sessionid); });
@@ -3250,13 +2831,11 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2831 break;
2832 case 'setbattery':
2833 // require('MeshAgent').SendCommand({ action: 'battery', state: 'dc', level: 55 });
3253 - if ((args['_'].length > 0) && ((args['_'][0] == 'ac') || (args['_'][0] == 'dc')))
3254 - {
2834 + if ((args['_'].length > 0) && ((args['_'][0] == 'ac') || (args['_'][0] == 'dc'))) {
2835 var b = { action: 'battery', state: args['_'][0] };
2836 if (args['_'].length == 2) { b.level = parseInt(args['_'][1]); }
2837 require('MeshAgent').SendCommand(b);
3258 - } else
3259 - {
2838 + } else {
2839 require('MeshAgent').SendCommand({ action: 'battery' });
2840 }
2841 break;
@@ -3265,51 +2844,41 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2844 break;
2845 case 'fdcount':
2846 require('DescriptorEvents').getDescriptorCount().then(
3268 - function (c)
3269 - {
2847 + function (c) {
2848 sendConsoleText('Descriptor Count: ' + c, this.sessionid);
3271 - }, function (e)
3272 - {
2849 + }, function (e) {
2850 sendConsoleText('Error fetching descriptor count: ' + e, this.sessionid);
2851 }).parentPromise.sessionid = sessionid;
2852 break;
2853 case 'uac':
3277 - if (process.platform != 'win32')
3278 - {
2854 + if (process.platform != 'win32') {
2855 response = 'Unknown command "uac", type "help" for list of avaialble commands.';
2856 break;
2857 }
3282 - if (args['_'].length != 1)
3283 - {
2858 + if (args['_'].length != 1) {
2859 response = 'Proper usage: uac [get|interactive|secure]';
2860 }
3286 - else
3287 - {
3288 - switch (args['_'][0].toUpperCase())
3289 - {
2861 + else {
2862 + switch (args['_'][0].toUpperCase()) {
2863 case 'GET':
2864 var secd = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop');
2865 response = "UAC mode: " + (secd == 0 ? "Interactive Desktop" : "Secure Desktop");
2866 break;
2867 case 'INTERACTIVE':
3295 - try
3296 - {
2868 + try {
2869 require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 0);
2870 response = 'UAC mode changed to: Interactive Desktop';
2871 }
3300 - catch (e)
3301 - {
2872 + catch (e) {
2873 response = "Unable to change UAC Mode";
2874 }
2875 break;
2876 case 'SECURE':
3306 - try
3307 - {
2877 + try {
2878 require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\System', 'PromptOnSecureDesktop', 1);
2879 response = 'UAC mode changed to: Secure Desktop';
2880 }
3311 - catch (e)
3312 - {
2881 + catch (e) {
2882 response = "Unable to change UAC Mode";
2883 }
2884 break;
@@ -3326,50 +2895,40 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2895 response = JSON.stringify(require('MeshAgent').getStartupOptions());
2896 break;
2897 case 'kvmmode':
3329 - if (require('MeshAgent').maxKvmTileSize == null)
3330 - {
2898 + if (require('MeshAgent').maxKvmTileSize == null) {
2899 response = "Unknown command \"kvmmode\", type \"help\" for list of avaialble commands.";
2900 }
3333 - else
3334 - {
3335 - if (require('MeshAgent').maxKvmTileSize == 0)
3336 - {
2901 + else {
2902 + if (require('MeshAgent').maxKvmTileSize == 0) {
2903 response = 'KVM Mode: Full JUMBO';
2904 }
3339 - else
3340 - {
2905 + else {
2906 response = 'KVM Mode: ' + (require('MeshAgent').maxKvmTileSize <= 65500 ? 'NO JUMBO' : 'Partial JUMBO');
2907 response += (', TileLimit: ' + (require('MeshAgent').maxKvmTileSize < 1024 ? (require('MeshAgent').maxKvmTileSize + ' bytes') : (Math.round(require('MeshAgent').maxKvmTileSize / 1024) + ' Kbytes')));
2908 }
2909 }
2910 break;
2911 case 'alert':
3347 - if (args['_'].length == 0)
3348 - {
2912 + if (args['_'].length == 0) {
2913 response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
2914 }
3351 - else
3352 - {
2915 + else {
2916 var p = args['_'].join(' ').split(',');
3354 - if (p.length < 2)
3355 - {
2917 + if (p.length < 2) {
2918 response = "Proper usage: alert TITLE, CAPTION [, TIMEOUT]"; // Display usage
2919 }
3358 - else
3359 - {
2920 + else {
2921 this._alert = require('message-box').create(p[0], p[1], p.length == 3 ? parseInt(p[2]) : 9999, 1);
2922 }
2923 }
2924 break;
2925 case 'agentsize':
2926 var actualSize = Math.floor(require('fs').statSync(process.execPath).size / 1024);
3366 - if (process.platform == 'win32')
3367 - {
2927 + if (process.platform == 'win32') {
2928 // Check the Agent Uninstall MetaData for correctness, as the installer may have written an incorrect value
2929 var writtenSize = 0;
2930 try { writtenSize = require('win-registry').QueryKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize'); } catch (e) { response = e; }
3371 - if (writtenSize != actualSize)
3372 - {
2931 + if (writtenSize != actualSize) {
2932 response = "Size updated from: " + writtenSize + " to: " + actualSize;
2933 try { require('win-registry').WriteKey(require('win-registry').HKEY.LocalMachine, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\MeshCentralAgent', 'EstimatedSize', actualSize); } catch (e) { response = e; }
2934 } else
@@ -3382,31 +2941,26 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2941 break;
2942 case 'wpfhwacceleration':
2943 if (process.platform != 'win32') { throw ("wpfhwacceleration setting is only supported on Windows"); }
3385 - if (args['_'].length != 1)
3386 - {
2944 + if (args['_'].length != 1) {
2945 response = "Proper usage: wpfhwacceleration (ON|OFF|STATUS)"; // Display usage
2946 }
3389 - else
3390 - {
2947 + else {
2948 var reg = require('win-registry');
2949 var uname = require('user-sessions').getUsername(require('user-sessions').consoleUid());
2950 var key = reg.usernameToUserKey(uname);
2951
3395 - switch (args['_'][0].toUpperCase())
3396 - {
2952 + switch (args['_'][0].toUpperCase()) {
2953 default:
2954 response = "Proper usage: wpfhwacceleration (ON|OFF|STATUS|DEFAULT)"; // Display usage
2955 break;
2956 case 'ON':
3401 - try
3402 - {
2957 + try {
2958 reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration', 0);
2959 response = "OK";
2960 } catch (e) { response = "FAILED"; }
2961 break;
2962 case 'OFF':
3408 - try
3409 - {
2963 + try {
2964 reg.WriteKey(reg.HKEY.Users, key + '\\SOFTWARE\\Microsoft\\Avalon.Graphics', 'DisableHWAcceleration', 1);
2965 response = 'OK';
2966 } catch (e) { response = 'FAILED'; }
@@ -3424,13 +2978,10 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2978 }
2979 break;
2980 case 'tsid':
3427 - if (process.platform == 'win32')
3428 - {
3429 - if (args['_'].length != 1)
3430 - {
2981 + if (process.platform == 'win32') {
2982 + if (args['_'].length != 1) {
2983 response = "TSID: " + (require('MeshAgent')._tsid == null ? "console" : require('MeshAgent')._tsid);
3432 - } else
3433 - {
2984 + } else {
2985 var i = parseInt(args['_'][0]);
2986 require('MeshAgent')._tsid = (isNaN(i) ? null : i);
2987 response = "TSID set to: " + (require('MeshAgent')._tsid == null ? "console" : require('MeshAgent')._tsid);
@@ -3439,15 +2990,12 @@ function processConsoleCommand(cmd, args, rights, sessionid)
2990 { response = "TSID command only supported on Windows"; }
2991 break;
2992 case 'activeusers':
3442 - if (process.platform == 'win32')
3443 - {
2993 + if (process.platform == 'win32') {
2994 var p = require('user-sessions').enumerateUsers();
2995 p.sessionid = sessionid;
3446 - p.then(function (u)
3447 - {
2996 + p.then(function (u) {
2997 var v = [];
3449 - for (var i in u)
3450 - {
2998 + for (var i in u) {
2999 if (u[i].State == 'Active') { v.push({ tsid: i, type: u[i].StationName, user: u[i].Username, domain: u[i].Domain }); }
3000 }
3001 sendConsoleText(JSON.stringify(v, null, 1), this.sessionid);
@@ -3456,44 +3004,35 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3004 { response = "activeusers command only supported on Windows"; }
3005 break;
3006 case 'wallpaper':
3459 - if (process.platform != 'win32' && !(process.platform == 'linux' && require('linux-gnome-helpers').available))
3460 - {
3007 + if (process.platform != 'win32' && !(process.platform == 'linux' && require('linux-gnome-helpers').available)) {
3008 response = "wallpaper command not supported on this platform";
3009 }
3463 - else
3464 - {
3465 - if (args['_'].length != 1)
3466 - {
3010 + else {
3011 + if (args['_'].length != 1) {
3012 response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
3013 }
3469 - else
3470 - {
3471 - switch (args['_'][0].toUpperCase())
3472 - {
3014 + else {
3015 + switch (args['_'][0].toUpperCase()) {
3016 default:
3017 response = 'Proper usage: wallpaper (GET|TOGGLE)'; // Display usage
3018 break;
3019 case 'GET':
3020 case 'TOGGLE':
3478 - if (process.platform == 'win32')
3479 - {
3021 + if (process.platform == 'win32') {
3022 var id = require('user-sessions').getProcessOwnerName(process.pid).tsid == 0 ? 1 : 0;
3023 var child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0='], { type: id });
3024 child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
3025 child.stderr.on('data', function () { });
3026 child.waitExit();
3027 var current = child.stdout.str.trim();
3486 - if (args['_'][0].toUpperCase() == 'GET')
3487 - {
3028 + if (args['_'][0].toUpperCase() == 'GET') {
3029 response = current;
3030 break;
3031 }
3491 - if (current != '')
3492 - {
3032 + if (current != '') {
3033 require('MeshAgent')._wallpaper = current;
3034 response = 'Wallpaper cleared';
3495 - } else
3496 - {
3035 + } else {
3036 response = 'Wallpaper restored';
3037 }
3038 child = require('child_process').execFile(process.execPath, [process.execPath.split('\\').pop(), '-b64exec', 'dmFyIFNQSV9HRVRERVNLV0FMTFBBUEVSID0gMHgwMDczOwp2YXIgU1BJX1NFVERFU0tXQUxMUEFQRVIgPSAweDAwMTQ7CnZhciBHTSA9IHJlcXVpcmUoJ19HZW5lcmljTWFyc2hhbCcpOwp2YXIgdXNlcjMyID0gR00uQ3JlYXRlTmF0aXZlUHJveHkoJ3VzZXIzMi5kbGwnKTsKdXNlcjMyLkNyZWF0ZU1ldGhvZCgnU3lzdGVtUGFyYW1ldGVyc0luZm9BJyk7CgppZiAocHJvY2Vzcy5hcmd2Lmxlbmd0aCA9PSAzKQp7CiAgICB2YXIgdiA9IEdNLkNyZWF0ZVZhcmlhYmxlKDEwMjQpOwogICAgdXNlcjMyLlN5c3RlbVBhcmFtZXRlcnNJbmZvQShTUElfR0VUREVTS1dBTExQQVBFUiwgdi5fc2l6ZSwgdiwgMCk7CiAgICBjb25zb2xlLmxvZyh2LlN0cmluZyk7CiAgICBwcm9jZXNzLmV4aXQoKTsKfQplbHNlCnsKICAgIHZhciBuYiA9IEdNLkNyZWF0ZVZhcmlhYmxlKHByb2Nlc3MuYXJndlszXSk7CiAgICB1c2VyMzIuU3lzdGVtUGFyYW1ldGVyc0luZm9BKFNQSV9TRVRERVNLV0FMTFBBUEVSLCBuYi5fc2l6ZSwgbmIsIDApOwogICAgcHJvY2Vzcy5leGl0KCk7Cn0=', current != '' ? '""' : require('MeshAgent')._wallpaper], { type: id });
@@ -3501,21 +3040,17 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3040 child.stderr.on('data', function () { });
3041 child.waitExit();
3042 }
3504 - else
3505 - {
3043 + else {
3044 var id = require('user-sessions').consoleUid();
3045 var current = require('linux-gnome-helpers').getDesktopWallpaper(id);
3508 - if (args['_'][0].toUpperCase() == 'GET')
3509 - {
3046 + if (args['_'][0].toUpperCase() == 'GET') {
3047 response = current;
3048 break;
3049 }
3513 - if (current != '/dev/null')
3514 - {
3050 + if (current != '/dev/null') {
3051 require('MeshAgent')._wallpaper = current;
3052 response = 'Wallpaper cleared';
3517 - } else
3518 - {
3053 + } else {
3054 response = 'Wallpaper restored';
3055 }
3056 require('linux-gnome-helpers').setDesktopWallpaper(id, current != '/dev/null' ? undefined : require('MeshAgent')._wallpaper);
@@ -3526,29 +3061,22 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3061 }
3062 break;
3063 case 'safemode':
3529 - if (process.platform != 'win32')
3530 - {
3064 + if (process.platform != 'win32') {
3065 response = 'safemode only supported on Windows Platforms'
3066 }
3533 - else
3534 - {
3535 - if (args['_'].length != 1)
3536 - {
3067 + else {
3068 + if (args['_'].length != 1) {
3069 response = 'Proper usage: safemode (ON|OFF|STATUS)'; // Display usage
3070 }
3539 - else
3540 - {
3071 + else {
3072 var svcname = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
3542 - try
3543 - {
3073 + try {
3074 svcname = require('MeshAgent').serviceName;
3075 }
3546 - catch (x)
3547 - {
3076 + catch (x) {
3077 }
3078
3550 - switch (args['_'][0].toUpperCase())
3551 - {
3079 + switch (args['_'][0].toUpperCase()) {
3080 default:
3081 response = 'Proper usage: safemode (ON|OFF|STATUS)'; // Display usage
3082 break;
@@ -3561,10 +3089,8 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3089 break;
3090 case 'STATUS':
3091 var nextboot = require('win-bcd').getKey('safeboot');
3564 - if (nextboot)
3565 - {
3566 - switch (nextboot)
3567 - {
3092 + if (nextboot) {
3093 + switch (nextboot) {
3094 case 'Network':
3095 case 'network':
3096 nextboot = 'SAFE_MODE_NETWORK';
@@ -3580,32 +3106,30 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3106 }
3107 }
3108 break;
3583 - /*
3584 - case 'border':
3585 - {
3586 - if ((args['_'].length == 1) && (args['_'][0] == 'on')) {
3587 - if (meshCoreObj.users.length > 0) {
3588 - obj.borderManager.Start(meshCoreObj.users[0]);
3589 - response = 'Border blinking is on.';
3590 - } else {
3591 - response = 'Cannot turn on border blinking, no logged in users.';
3592 - }
3593 - } else if ((args['_'].length == 1) && (args['_'][0] == 'off')) {
3594 - obj.borderManager.Stop();
3595 - response = 'Border blinking is off.';
3109 + /*
3110 + case 'border':
3111 + {
3112 + if ((args['_'].length == 1) && (args['_'][0] == 'on')) {
3113 + if (meshCoreObj.users.length > 0) {
3114 + obj.borderManager.Start(meshCoreObj.users[0]);
3115 + response = 'Border blinking is on.';
3116 } else {
3597 - response = 'Proper usage: border "on|off"'; // Display correct command usage
3117 + response = 'Cannot turn on border blinking, no logged in users.';
3118 }
3119 + } else if ((args['_'].length == 1) && (args['_'][0] == 'off')) {
3120 + obj.borderManager.Stop();
3121 + response = 'Border blinking is off.';
3122 + } else {
3123 + response = 'Proper usage: border "on|off"'; // Display correct command usage
3124 }
3600 - break;
3601 - */
3125 + }
3126 + break;
3127 + */
3128 case 'av':
3603 - if (process.platform == 'win32')
3604 - {
3129 + if (process.platform == 'win32') {
3130 // Windows Command: "wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct get /FORMAT:CSV"
3131 response = JSON.stringify(require('win-info').av(), null, 1);
3607 - } else
3608 - {
3132 + } else {
3133 response = 'Not supported on the platform';
3134 }
3135 break;
@@ -3613,27 +3137,21 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3137 if (args['_'].length != 1) { response = 'Proper usage: log "sample text"'; } else { MeshServerLog(args['_'][0]); response = 'ok'; }
3138 break;
3139 case 'getclip':
3616 - if (require('MeshAgent').isService)
3617 - {
3140 + if (require('MeshAgent').isService) {
3141 require('clipboard').dispatchRead().then(function (str) { sendConsoleText(str, sessionid); });
3619 - } else
3620 - {
3142 + } else {
3143 require("clipboard").read().then(function (str) { sendConsoleText(str, sessionid); });
3144 }
3145 break;
3146 case 'setclip': {
3625 - if (args['_'].length != 1)
3626 - {
3147 + if (args['_'].length != 1) {
3148 response = 'Proper usage: setclip "sample text"';
3628 - } else
3629 - {
3630 - if (require('MeshAgent').isService)
3631 - {
3149 + } else {
3150 + if (require('MeshAgent').isService) {
3151 require('clipboard').dispatchWrite(args['_'][0]);
3152 response = 'Setting clipboard to: "' + args['_'][0] + '"';
3153 }
3635 - else
3636 - {
3154 + else {
3155 require("clipboard")(args['_'][0]); response = 'Setting clipboard to: "' + args['_'][0] + '"';
3156 }
3157 }
@@ -3651,12 +3169,10 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3169 }
3170 case 'toast': {
3171 if (args['_'].length < 1) { response = 'Proper usage: toast "message"'; } else {
3654 - if (require('MeshAgent')._tsid == null)
3655 - {
3172 + if (require('MeshAgent')._tsid == null) {
3173 require('toaster').Toast('MeshCentral', args['_'][0]).then(sendConsoleText, sendConsoleText);
3174 }
3658 - else
3659 - {
3175 + else {
3176 require('toaster').Toast('MeshCentral', args['_'][0], require('MeshAgent')._tsid).then(sendConsoleText, sendConsoleText);
3177 }
3178 }
@@ -3668,8 +3184,7 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3184 break;
3185 }
3186 case 'ps': {
3671 - processManager.getProcesses(function (plist)
3672 - {
3187 + processManager.getProcesses(function (plist) {
3188 var x = '';
3189 for (var i in plist) { x += i + ((plist[i].user) ? (', ' + plist[i].user) : '') + ', ' + plist[i].cmd + '\r\n'; }
3190 sendConsoleText(x, sessionid);
@@ -3677,11 +3192,9 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3192 break;
3193 }
3194 case 'kill': {
3680 - if ((args['_'].length < 1))
3681 - {
3195 + if ((args['_'].length < 1)) {
3196 response = 'Proper usage: kill [pid]'; // Display correct command usage
3683 - } else
3684 - {
3197 + } else {
3198 process.kill(parseInt(args['_'][0]));
3199 response = 'Killed process ' + args['_'][0] + '.';
3200 }
@@ -3694,13 +3207,10 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3207 case 'rawsmbios': {
3208 if (SMBiosTablesRaw == null) { response = 'SMBios tables not available.'; } else {
3209 response = '';
3697 - for (var i in SMBiosTablesRaw)
3698 - {
3210 + for (var i in SMBiosTablesRaw) {
3211 var header = false;
3700 - for (var j in SMBiosTablesRaw[i])
3701 - {
3702 - if (SMBiosTablesRaw[i][j].length > 0)
3703 - {
3212 + for (var j in SMBiosTablesRaw[i]) {
3213 + if (SMBiosTablesRaw[i][j].length > 0) {
3214 if (header == false) { response += ('Table type #' + i + ((require('smbios').smTableTypes[i] == null) ? '' : (', ' + require('smbios').smTableTypes[i]))) + '\r\n'; header = true; }
3215 response += (' ' + SMBiosTablesRaw[i][j].toString('hex')) + '\r\n';
3216 }
@@ -3710,41 +3220,33 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3220 break;
3221 }
3222 case 'eval': { // Eval JavaScript
3713 - if (args['_'].length < 1)
3714 - {
3223 + if (args['_'].length < 1) {
3224 response = 'Proper usage: eval "JavaScript code"'; // Display correct command usage
3716 - } else
3717 - {
3225 + } else {
3226 response = JSON.stringify(mesh.eval(args['_'][0])); // This can only be run by trusted administrator.
3227 }
3228 break;
3229 }
3230 case 'uninstallagent': // Uninstall this agent
3231 var agentName = process.platform == 'win32' ? 'Mesh Agent' : 'meshagent';
3724 - try
3725 - {
3232 + try {
3233 agentName = require('MeshAgent').serviceName;
3234 }
3728 - catch (x)
3729 - {
3235 + catch (x) {
3236 }
3237
3732 - if (!require('service-manager').manager.getService(agentName).isMe())
3733 - {
3238 + if (!require('service-manager').manager.getService(agentName).isMe()) {
3239 response = 'Uininstall failed, this instance is not the service instance';
3735 - } else
3736 - {
3240 + } else {
3241 try { diagnosticAgent_uninstall(); } catch (e) { }
3242 var js = "require('service-manager').manager.getService('" + agentName + "').stop(); require('service-manager').manager.uninstallService('" + agentName + "'); process.exit();";
3243 this.child = require('child_process').execFile(process.execPath, [process.platform == 'win32' ? (process.execPath.split('\\').pop()) : (process.execPath.split('/').pop()), '-b64exec', Buffer.from(js).toString('base64')], { type: 4, detached: true });
3244 }
3245 break;
3246 case 'notify': { // Send a notification message to the mesh
3743 - if (args['_'].length != 1)
3744 - {
3247 + if (args['_'].length != 1) {
3248 response = 'Proper usage: notify "message" [--session]'; // Display correct command usage
3746 - } else
3747 - {
3249 + } else {
3250 var notification = { action: 'msg', type: 'notify', value: args['_'][0], tag: 'console' };
3251 if (args.session) { notification.sessionid = sessionid; } // If "--session" is specified, notify only this session, if not, the server will notify the mesh
3252 mesh.SendCommand(notification); // no sessionid or userid specified, notification will go to the entire mesh
@@ -3756,23 +3258,20 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3258 // CPU & memory utilization
3259 pr = require('sysinfo').cpuUtilization();
3260 pr.sessionid = sessionid;
3759 - pr.then(function (data)
3760 - {
3261 + pr.then(function (data) {
3262 sendConsoleText(JSON.stringify(
3263 {
3264 cpu: data,
3265 memory: require('sysinfo').memUtilization(),
3266 thermals: require('sysinfo').thermals == null ? [] : require('sysinfo').thermals()
3267 }, null, 1), this.sessionid);
3767 - }, function (e)
3768 - {
3769 - sendConsoleText(e);
3770 - });
3268 + }, function (e) {
3269 + sendConsoleText(e);
3270 + });
3271 break;
3272 }
3273 case 'sysinfo': { // Return system information
3774 - getSystemInformation(function (results, err)
3775 - {
3274 + getSystemInformation(function (results, err) {
3275 if (results == null) { sendConsoleText(err, this.sessionid); } else {
3276 sendConsoleText(JSON.stringify(results, null, 1), this.sessionid);
3277 }
@@ -3794,12 +3293,10 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3293 case 'osinfo': { // Return the operating system information
3294 var i = 1;
3295 if (args['_'].length > 0) { i = parseInt(args['_'][0]); if (i > 8) { i = 8; } response = 'Calling ' + i + ' times.'; }
3797 - for (var j = 0; j < i; j++)
3798 - {
3296 + for (var j = 0; j < i; j++) {
3297 var pr = require('os').name();
3298 pr.sessionid = sessionid;
3801 - pr.then(function (v)
3802 - {
3299 + pr.then(function (v) {
3300 sendConsoleText("OS: " + v + (process.platform == 'win32' ? (require('win-virtual-terminal').supported ? ' [ConPTY: YES]' : ' [ConPTY: NO]') : ''), this.sessionid);
3301 });
3302 }
@@ -3817,11 +3314,9 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3314 break;
3315 }
3316 case 'type': { // Returns the content of a file
3820 - if (args['_'].length == 0)
3821 - {
3317 + if (args['_'].length == 0) {
3318 response = 'Proper usage: type (filepath) [maxlength]'; // Display correct command usage
3823 - } else
3824 - {
3319 + } else {
3320 var max = 4096;
3321 if ((args['_'].length > 1) && (typeof args['_'][1] == 'number')) { max = args['_'][1]; }
3322 if (max > 4096) max = 4096;
@@ -3840,22 +3335,18 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3335 }
3336 case 'dbget': { // Return the data store value for a given key
3337 if (db == null) { response = 'Database not accessible.'; break; }
3843 - if (args['_'].length != 1)
3844 - {
3338 + if (args['_'].length != 1) {
3339 response = 'Proper usage: dbget (key)'; // Display the value for a given database key
3846 - } else
3847 - {
3340 + } else {
3341 response = db.Get(args['_'][0]);
3342 }
3343 break;
3344 }
3345 case 'dbset': { // Set a data store key and value pair
3346 if (db == null) { response = 'Database not accessible.'; break; }
3854 - if (args['_'].length != 2)
3855 - {
3347 + if (args['_'].length != 2) {
3348 response = 'Proper usage: dbset (key) (value)'; // Set a database key
3857 - } else
3858 - {
3349 + } else {
3350 var r = db.Put(args['_'][0], args['_'][1]);
3351 response = 'Key set: ' + r;
3352 }
@@ -3868,27 +3359,20 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3359 break;
3360 }
3361 case 'httpget': {
3871 - if (consoleHttpRequest != null)
3872 - {
3362 + if (consoleHttpRequest != null) {
3363 response = 'HTTP operation already in progress.';
3874 - } else
3875 - {
3876 - if (args['_'].length != 1)
3877 - {
3364 + } else {
3365 + if (args['_'].length != 1) {
3366 response = 'Proper usage: httpget (url)';
3879 - } else
3880 - {
3367 + } else {
3368 var options = http.parseUri(args['_'][0]);
3369 options.method = 'GET';
3883 - if (options == null)
3884 - {
3370 + if (options == null) {
3371 response = 'Invalid url.';
3886 - } else
3887 - {
3372 + } else {
3373 try { consoleHttpRequest = http.request(options, consoleHttpResponse); } catch (e) { response = 'Invalid HTTP GET request'; }
3374 consoleHttpRequest.sessionid = sessionid;
3890 - if (consoleHttpRequest != null)
3891 - {
3375 + if (consoleHttpRequest != null) {
3376 consoleHttpRequest.end();
3377 response = 'HTTPGET ' + options.protocol + '//' + options.host + ':' + options.port + options.path;
3378 }
@@ -3899,8 +3383,7 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3383 }
3384 case 'wslist': { // List all web sockets
3385 response = '';
3902 - for (var i in consoleWebSockets)
3903 - {
3386 + for (var i in consoleWebSockets) {
3387 var httprequest = consoleWebSockets[i];
3388 response += 'Websocket #' + i + ', ' + httprequest.url + '\r\n';
3389 }
@@ -3908,20 +3391,16 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3391 break;
3392 }
3393 case 'wsconnect': { // Setup a web socket
3911 - if (args['_'].length == 0)
3912 - {
3394 + if (args['_'].length == 0) {
3395 response = 'Proper usage: wsconnect (url)\r\nFor example: wsconnect wss://localhost:443/meshrelay.ashx?id=abc'; // Display correct command usage
3914 - } else
3915 - {
3396 + } else {
3397 var httprequest = null;
3917 - try
3918 - {
3398 + try {
3399 var options = http.parseUri(args['_'][0].split('$').join('%24').split('@').join('%40')); // Escape the $ and @ characters in the URL
3400 options.rejectUnauthorized = 0;
3401 httprequest = http.request(options);
3402 } catch (e) { response = 'Invalid HTTP websocket request'; }
3923 - if (httprequest != null)
3924 - {
3403 + if (httprequest != null) {
3404 httprequest.upgrade = onWebSocketUpgrade;
3405 httprequest.on('error', function (e) { sendConsoleText("ERROR: Unable to connect to: " + this.url + ", " + JSON.stringify(e)); });
3406
@@ -3937,43 +3416,34 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3416 break;
3417 }
3418 case 'wssend': { // Send data on a web socket
3940 - if (args['_'].length == 0)
3941 - {
3419 + if (args['_'].length == 0) {
3420 response = 'Proper usage: wssend (socketnumber)\r\n'; // Display correct command usage
3943 - for (var i in consoleWebSockets)
3944 - {
3421 + for (var i in consoleWebSockets) {
3422 var httprequest = consoleWebSockets[i];
3423 response += 'Websocket #' + i + ', ' + httprequest.url + '\r\n';
3424 }
3948 - } else
3949 - {
3425 + } else {
3426 var i = parseInt(args['_'][0]);
3427 var httprequest = consoleWebSockets[i];
3952 - if (httprequest != undefined)
3953 - {
3428 + if (httprequest != undefined) {
3429 httprequest.s.write(args['_'][1]);
3430 response = 'ok';
3956 - } else
3957 - {
3431 + } else {
3432 response = 'Invalid web socket number';
3433 }
3434 }
3435 break;
3436 }
3437 case 'wsclose': { // Close a websocket
3964 - if (args['_'].length == 0)
3965 - {
3438 + if (args['_'].length == 0) {
3439 response = 'Proper usage: wsclose (socketnumber)'; // Display correct command usage
3967 - } else
3968 - {
3440 + } else {
3441 var i = parseInt(args['_'][0]);
3442 var httprequest = consoleWebSockets[i];
3971 - if (httprequest != undefined)
3972 - {
3443 + if (httprequest != undefined) {
3444 if (httprequest.s != null) { httprequest.s.end(); } else { httprequest.end(); }
3445 response = 'ok';
3975 - } else
3976 - {
3446 + } else {
3447 response = 'Invalid web socket number';
3448 }
3449 }
@@ -3991,15 +3461,12 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3461 if (args['_'].length > 0) { xpath = obj.path.join(args['_'][0], '*'); }
3462 response = 'List of ' + xpath + '\r\n';
3463 var results = fs.readdirSync(xpath);
3994 - for (var i = 0; i < results.length; ++i)
3995 - {
3464 + for (var i = 0; i < results.length; ++i) {
3465 var stat = null, p = obj.path.join(args['_'][0], results[i]);
3466 try { stat = fs.statSync(p); } catch (e) { }
3998 - if ((stat == null) || (stat == undefined))
3999 - {
3467 + if ((stat == null) || (stat == undefined)) {
3468 response += (results[i] + "\r\n");
4001 - } else
4002 - {
3469 + } else {
3470 response += (results[i] + " " + ((stat.isDirectory()) ? "(Folder)" : "(File)") + "\r\n");
3471 }
3472 }
@@ -4015,16 +3482,13 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3482 break;
3483 }
3484 case 'amt': { // Show Intel AMT status
4018 - if (amt != null)
4019 - {
4020 - amt.getMeiState(9, function (state)
4021 - {
3485 + if (amt != null) {
3486 + amt.getMeiState(9, function (state) {
3487 var resp = "Intel AMT not detected.";
3488 if (state != null) { resp = objToString(state, 0, ' ', true); }
3489 sendConsoleText(resp, sessionid);
3490 });
4026 - } else
4027 - {
3491 + } else {
3492 response = "Intel AMT not detected.";
3493 }
3494 break;
@@ -4035,11 +3499,9 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3499 break;
3500 }
3501 case 'wakeonlan': { // Send wake-on-lan
4038 - if ((args['_'].length != 1) || (args['_'][0].length != 12))
4039 - {
3502 + if ((args['_'].length != 1) || (args['_'][0].length != 12)) {
3503 response = 'Proper usage: wakeonlan [mac], for example "wakeonlan 010203040506".';
4041 - } else
4042 - {
3504 + } else {
3505 var count = sendWakeOnLan(args['_'][0]);
3506 response = 'Sent wake-on-lan on ' + count + ' interface(s).';
3507 }
@@ -4050,16 +3512,12 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3512 break;
3513 }
3514 case 'power': { // Execute a power action on this computer
4053 - if (mesh.ExecPowerState == undefined)
4054 - {
3515 + if (mesh.ExecPowerState == undefined) {
3516 response = 'Power command not supported on this agent.';
4056 - } else
4057 - {
4058 - if ((args['_'].length == 0) || isNaN(Number(args['_'][0])))
4059 - {
3517 + } else {
3518 + if ((args['_'].length == 0) || isNaN(Number(args['_'][0]))) {
3519 response = 'Proper usage: power (actionNumber), where actionNumber is:\r\n LOGOFF = 1\r\n SHUTDOWN = 2\r\n REBOOT = 3\r\n SLEEP = 4\r\n HIBERNATE = 5\r\n DISPLAYON = 6\r\n KEEPAWAKE = 7\r\n BEEP = 8\r\n CTRLALTDEL = 9\r\n VIBRATE = 13\r\n FLASH = 14'; // Display correct command usage
4061 - } else
4062 - {
3520 + } else {
3521 var r = mesh.ExecPowerState(Number(args['_'][0]), Number(args['_'][1]));
3522 response = 'Power action executed with return code: ' + r + '.';
3523 }
@@ -4067,8 +3525,7 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3525 break;
3526 }
3527 case 'location': {
4070 - getIpLocationData(function (location)
4071 - {
3528 + getIpLocationData(function (location) {
3529 sendConsoleText(objToString({ action: 'iplocation', type: 'publicip', value: location }, 0, ' '));
3530 });
3531 break;
@@ -4078,8 +3535,7 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3535 break;
3536 }
3537 case 'scanwifi': {
4081 - if (wifiScanner != null)
4082 - {
3538 + if (wifiScanner != null) {
3539 var wifiPresent = wifiScanner.hasWireless;
3540 if (wifiPresent) { response = "Perfoming Wifi scan..."; wifiScanner.Scan(); } else { response = "Wifi absent."; }
3541 } else
@@ -4096,51 +3552,40 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3552 break;
3553 }
3554 case 'getscript': {
4099 - if (args['_'].length != 1)
4100 - {
3555 + if (args['_'].length != 1) {
3556 response = "Proper usage: getscript [scriptNumber].";
4102 - } else
4103 - {
3557 + } else {
3558 mesh.SendCommand({ action: 'getScript', type: args['_'][0] });
3559 }
3560 break;
3561 }
3562 case 'diagnostic':
3563 {
4110 - if (!mesh.DAIPC.listening)
4111 - {
3564 + if (!mesh.DAIPC.listening) {
3565 response = 'Unable to bind to Diagnostic IPC, most likely because the path (' + process.cwd() + ') is not on a local file system';
3566 break;
3567 }
3568 var diag = diagnosticAgent_installCheck();
4116 - if (diag)
4117 - {
4118 - if (args['_'].length == 1 && args['_'][0] == 'uninstall')
4119 - {
3569 + if (diag) {
3570 + if (args['_'].length == 1 && args['_'][0] == 'uninstall') {
3571 diagnosticAgent_uninstall();
3572 response = 'Diagnostic Agent uninstalled';
3573 }
4123 - else
4124 - {
3574 + else {
3575 response = 'Diagnostic Agent installed at: ' + diag.appLocation();
3576 }
3577 }
4128 - else
4129 - {
4130 - if (args['_'].length == 1 && args['_'][0] == 'install')
4131 - {
3578 + else {
3579 + if (args['_'].length == 1 && args['_'][0] == 'install') {
3580 diag = diagnosticAgent_installCheck(true);
4133 - if (diag)
4134 - {
3581 + if (diag) {
3582 response = 'Diagnostic agent was installed at: ' + diag.appLocation();
3583 }
4137 - else
4138 - {
3584 + else {
3585 response = 'Diagnostic agent installation failed';
3586 }
3587 }
4142 - else
4143 - {
3588 + else {
3589 response = 'Diagnostic Agent Not installed. To install: diagnostic install';
3590 }
3591 }
@@ -4154,8 +3599,7 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3599 case 'amtconfig': {
3600 if (amt == null) { response = "Intel AMT not detected."; break; }
3601 if (apftunnel != null) { response = "Intel AMT server tunnel already active"; break; }
4157 - amt.getMeiState(15, function (state)
4158 - {
3602 + amt.getMeiState(15, function (state) {
3603 var rx = '';
3604 if ((state == null) || (state.ProvisioningState == null)) { rx = "Intel AMT not ready for configuration."; } else {
3605 var apfarg = {
@@ -4169,19 +3613,15 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3613 conntype: 2, // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
3614 meiState: state // MEI state will be passed to MPS server
3615 };
4172 - if ((state.UUID == null) || (state.UUID.length != 36))
4173 - {
3616 + if ((state.UUID == null) || (state.UUID.length != 36)) {
3617 rx = "Unable to get Intel AMT UUID";
4175 - } else
4176 - {
3618 + } else {
3619 addAmtEvent('User LMS tunnel start.');
3620 apftunnel = require('amt-apfclient')({ debug: false }, apfarg);
4179 - apftunnel.onJsonControl = function (data)
4180 - {
3621 + apftunnel.onJsonControl = function (data) {
3622 if (data.action == 'console') { addAmtEvent(data.msg); require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); } // Display a console message
3623 if (data.action == 'mestate') { amt.getMeiState(15, function (state) { apftunnel.updateMeiState(state); }); } // Update the MEI state
4183 - if (data.action == 'deactivate')
4184 - { // Request CCM deactivation
3624 + if (data.action == 'deactivate') { // Request CCM deactivation
3625 var amtMeiModule, amtMei;
3626 try { amtMeiModule = require('amt-mei'); amtMei = new amtMeiModule(); } catch (ex) { apftunnel.sendMeiDeactivationState(1); return; }
3627 amtMei.on('error', function (e) { apftunnel.sendMeiDeactivationState(1); });
@@ -4190,12 +3630,10 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3630 if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; } // Close the CIRA-LMS connection
3631 }
3632 apftunnel.onChannelClosed = function () { addAmtEvent('User LMS tunnel closed.'); apftunnel = null; }
4193 - try
4194 - {
3633 + try {
3634 apftunnel.connect();
3635 rx = "Started Intel AMT configuration";
4197 - } catch (ex)
4198 - {
3636 + } catch (ex) {
3637 rx = JSON.stringify(ex);
3638 }
3639 }
@@ -4205,17 +3643,14 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3643 break;
3644 }
3645 case 'apf': {
4208 - if (meshCoreObj.intelamt !== null)
4209 - {
4210 - if (args['_'].length == 1)
4211 - {
3646 + if (meshCoreObj.intelamt !== null) {
3647 + if (args['_'].length == 1) {
3648 var connType = -1, connTypeStr = args['_'][0].toLowerCase();
3649 if (connTypeStr == 'lms') { connType = 2; }
3650 if (connTypeStr == 'relay') { connType = 1; }
3651 if (connTypeStr == 'cira') { connType = 0; }
3652 if (connTypeStr == 'off') { connType = -2; }
4217 - if (connType >= 0)
4218 - { // Connect
3653 + if (connType >= 0) { // Connect
3654 var apfarg = {
3655 mpsurl: mesh.ServerUrl.replace('agent.ashx', 'apf.ashx'),
3656 mpsuser: Buffer.from(mesh.ServerInfo.MeshID, 'hex').toString('base64').substring(0, 16),
@@ -4226,67 +3661,52 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3661 clientuuid: meshCoreObj.intelamt.uuid,
3662 conntype: connType // 0 = CIRA, 1 = Relay, 2 = LMS. The correct value is 2 since we are performing an LMS relay, other values for testing.
3663 };
4229 - if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36))
4230 - {
3664 + if ((apfarg.clientuuid == null) || (apfarg.clientuuid.length != 36)) {
3665 response = "Unable to get Intel AMT UUID: " + apfarg.clientuuid;
4232 - } else
4233 - {
3666 + } else {
3667 apftunnel = require('amt-apfclient')({ debug: false }, apfarg);
4235 - apftunnel.onJsonControl = function (data)
4236 - {
3668 + apftunnel.onJsonControl = function (data) {
3669 if (data.action == 'console') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: data.msg }); }
3670 if (data.action == 'close') { try { apftunnel.disconnect(); } catch (e) { } apftunnel = null; }
3671 }
3672 apftunnel.onChannelClosed = function () { apftunnel = null; }
4241 - try
4242 - {
3673 + try {
3674 apftunnel.connect();
3675 response = "Started APF tunnel";
4245 - } catch (e)
4246 - {
3676 + } catch (e) {
3677 response = JSON.stringify(e);
3678 }
3679 }
4250 - } else if (connType == -2)
4251 - { // Disconnect
4252 - try
4253 - {
3680 + } else if (connType == -2) { // Disconnect
3681 + try {
3682 apftunnel.disconnect();
3683 response = "Stopped APF tunnel";
4256 - } catch (e)
4257 - {
3684 + } catch (e) {
3685 response = JSON.stringify(e);
3686 }
3687 apftunnel = null;
4261 - } else
4262 - {
3688 + } else {
3689 response = "Invalid command.\r\nUse: apf lms|relay|cira|off";
3690 }
4265 - } else
4266 - {
3691 + } else {
3692 response = "APF tunnel is " + (apftunnel == null ? "off" : "on") + "\r\nUse: apf lms|relay|cira|off";
3693 }
4269 - } else
4270 - {
3694 + } else {
3695 response = "APF tunnel requires Intel AMT";
3696 }
3697 break;
3698 }
3699 case 'plugin': {
4276 - if (typeof args['_'][0] == 'string')
4277 - {
4278 - try
4279 - {
3700 + if (typeof args['_'][0] == 'string') {
3701 + try {
3702 // Pass off the action to the plugin
3703 // for plugin creators, you'll want to have a plugindir/modules_meshcore/plugin.js
3704 // to control the output / actions here.
3705 response = require(args['_'][0]).consoleaction(args, rights, sessionid, mesh);
4284 - } catch (e)
4285 - {
3706 + } catch (e) {
3707 response = "There was an error in the plugin (" + e + ")";
3708 }
4288 - } else
4289 - {
3709 + } else {
3710 response = "Proper usage: plugin [pluginName] [args].";
3711 }
3712 break;
@@ -4301,18 +3721,15 @@ function processConsoleCommand(cmd, args, rights, sessionid)
3721 }
3722
3723 // Send a mesh agent console command
4304 -function sendConsoleText(text, sessionid)
4305 -{
3724 +function sendConsoleText(text, sessionid) {
3725 if (typeof text == 'object') { text = JSON.stringify(text); }
3726 if (debugConsole && ((sessionid == null) || (sessionid == 'pipe'))) { broadcastToRegisteredApps({ cmd: 'console', value: text }); }
3727 if (sessionid != 'pipe') { require('MeshAgent').SendCommand({ action: 'msg', type: 'console', value: text, sessionid: sessionid }); }
3728 }
3729
3730 // Send a mesh agent message to server, placing a bubble/badge on the agent device
4312 -function sendAgentMessage(msg, icon)
4313 -{
4314 - if (sendAgentMessage.messages == null)
4315 - {
3731 +function sendAgentMessage(msg, icon) {
3732 + if (sendAgentMessage.messages == null) {
3733 sendAgentMessage.messages = {};
3734 sendAgentMessage.nextid = 1;
3735 }
@@ -4320,48 +3737,38 @@ function sendAgentMessage(msg, icon)
3737 require('MeshAgent').SendCommand({ action: 'sessions', type: 'msg', value: sendAgentMessage.messages });
3738 }
3739
4323 -function linux_execv(name, agentfilename, sessionid)
4324 -{
3740 +function linux_execv(name, agentfilename, sessionid) {
3741 var libs = require('monitor-info').getLibInfo('libc');
3742 var libc = null;
3743
4328 - while (libs.length > 0)
4329 - {
4330 - try
4331 - {
3744 + while (libs.length > 0) {
3745 + try {
3746 libc = require('_GenericMarshal').CreateNativeProxy(libs.pop().path);
3747 break;
3748 }
4335 - catch (e)
4336 - {
3749 + catch (e) {
3750 libc = null;
3751 continue;
3752 }
3753 }
4341 - if (libc != null)
4342 - {
4343 - try
4344 - {
3754 + if (libc != null) {
3755 + try {
3756 libc.CreateMethod('execv');
3757 }
4347 - catch (e)
4348 - {
3758 + catch (e) {
3759 libc = null;
3760 }
3761 }
3762
4353 - if (libc == null)
4354 - {
3763 + if (libc == null) {
3764 // Couldn't find libc.so, fallback to using service manager to restart agent
3765 if (sessionid != null) { sendConsoleText('Restarting service via service-manager...', sessionid) }
4357 - try
4358 - {
3766 + try {
3767 // restart service
3768 var s = require('service-manager').manager.getService(name);
3769 s.restart();
3770 }
4363 - catch (zz)
4364 - {
3771 + catch (zz) {
3772 sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
3773 sendAgentMessage('Self Update encountered an error trying to restart service', 3);
3774 }
@@ -4375,18 +3782,15 @@ function linux_execv(name, agentfilename, sessionid)
3782 var argarr = [];
3783 var path = require('_GenericMarshal').CreateVariable(process.execPath);
3784
4378 - if (require('MeshAgent').getStartupOptions != null)
4379 - {
3785 + if (require('MeshAgent').getStartupOptions != null) {
3786 var options = require('MeshAgent').getStartupOptions();
4381 - for (i in options)
4382 - {
3787 + for (i in options) {
3788 argarr.push('--' + i + '="' + options[i] + '"');
3789 }
3790 }
3791
3792 args = require('_GenericMarshal').CreateVariable((1 + argarr.length) * require('_GenericMarshal').PointerSize);
4388 - for (i = 0; i < argarr.length; ++i)
4389 - {
3793 + for (i = 0; i < argarr.length; ++i) {
3794 var arg = require('_GenericMarshal').CreateVariable(argarr[i]);
3795 arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
3796 }
@@ -4396,8 +3800,7 @@ function linux_execv(name, agentfilename, sessionid)
3800 sendAgentMessage('Self Update failed because execv() failed', 3);
3801 }
3802
4399 -function bsd_execv(name, agentfilename, sessionid)
4400 -{
3803 +function bsd_execv(name, agentfilename, sessionid) {
3804 var child = require('child_process').execFile('/bin/sh', ['sh']);
3805 child.stdout.str = ''; child.stdout.on('data', function (c) { this.str += c.toString(); });
3806 child.stderr.str = ''; child.stderr.on('data', function (c) { this.str += c.toString(); });
@@ -4412,21 +3815,18 @@ function bsd_execv(name, agentfilename, sessionid)
3815 child.stdin.write(' }');
3816 child.stdin.write("}'\nexit\n");
3817 child.waitExit();
4415 - if (child.stdout.str.trim() == '')
4416 - {
3818 + if (child.stdout.str.trim() == '') {
3819 if (sessionid != null) { sendConsoleText('Self Update failed because cannot find libc.so', sessionid) }
3820 sendAgentMessage('Self Update failed because cannot find libc.so', 3);
3821 return;
3822 }
3823
3824 var libc = null;
4423 - try
4424 - {
3825 + try {
3826 libc = require('_GenericMarshal').CreateNativeProxy(child.stdout.str.trim());
3827 libc.CreateMethod('execv');
3828 }
4428 - catch (e)
4429 - {
3829 + catch (e) {
3830 if (sessionid != null) { sendConsoleText('Self Update failed: ' + e.toString(), sessionid) }
3831 sendAgentMessage('Self Update failed: ' + e.toString(), 3);
3832 return;
@@ -4437,13 +3837,11 @@ function bsd_execv(name, agentfilename, sessionid)
3837 var argarr = [];
3838 var args;
3839 var options = require('MeshAgent').getStartupOptions();
4440 - for (i in options)
4441 - {
3840 + for (i in options) {
3841 argarr.push('--' + i + '="' + options[i] + '"');
3842 }
3843 args = require('_GenericMarshal').CreateVariable((1 + argarr.length) * require('_GenericMarshal').PointerSize);
4445 - for (i = 0; i < argarr.length; ++i)
4446 - {
3844 + for (i = 0; i < argarr.length; ++i) {
3845 var arg = require('_GenericMarshal').CreateVariable(argarr[i]);
3846 arg.pointerBuffer().copy(args.toBuffer(), i * require('_GenericMarshal').PointerSize);
3847 }
@@ -4454,16 +3852,13 @@ function bsd_execv(name, agentfilename, sessionid)
3852 sendAgentMessage('Self Update failed because execv() failed', 3);
3853 }
3854
4457 -function windows_execve(name, agentfilename, sessionid)
4458 -{
3855 +function windows_execve(name, agentfilename, sessionid) {
3856 var libc;
4460 - try
4461 - {
3857 + try {
3858 libc = require('_GenericMarshal').CreateNativeProxy('msvcrt.dll');
3859 libc.CreateMethod('_wexecve');
3860 }
4465 - catch (xx)
4466 - {
3861 + catch (xx) {
3862 sendConsoleText('Self Update failed because msvcrt.dll is missing', sessionid);
3863 sendAgentMessage('Self Update failed because msvcrt.dll is missing', 3);
3864 return;
@@ -4481,42 +3876,34 @@ function windows_execve(name, agentfilename, sessionid)
3876 }
3877
3878 // Start a JavaScript based Agent Self-Update
4484 -function agentUpdate_Start(updateurl, updateoptions)
4485 -{
3879 +function agentUpdate_Start(updateurl, updateoptions) {
3880 // If this value is null
3881 var sessionid = (updateoptions != null) ? updateoptions.sessionid : null; // If this is null, messages will be broadcast. Otherwise they will be unicasted
3882
4489 - if (agentUpdate_Start._selfupdate != null)
4490 - {
3883 + if (agentUpdate_Start._selfupdate != null) {
3884 // We were already called, so we will ignore this duplicate request
3885 if (sessionid != null) { sendConsoleText('Self update already in progress...', sessionid); }
3886 }
4494 - else
4495 - {
3887 + else {
3888 if (agentUpdate_Start._retryCount == null) { agentUpdate_Start._retryCount = 0; }
4497 - if (require('MeshAgent').ARCHID == null && updateurl == null)
4498 - {
3889 + if (require('MeshAgent').ARCHID == null && updateurl == null) {
3890 // This agent doesn't have the ability to tell us which ARCHID it is, so we don't know which agent to pull
3891 sendConsoleText('Unable to initiate update, agent ARCHID is not defined', sessionid);
3892 }
4502 - else
4503 - {
3893 + else {
3894 var agentfilename = process.execPath.split(process.platform == 'win32' ? '\\' : '/').pop(); // Local File Name, ie: MeshAgent.exe
3895 var name = require('MeshAgent').serviceName;
3896 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
4507 - try
4508 - {
3897 + try {
3898 var s = require('service-manager').manager.getService(name);
4510 - if (!s.isMe())
4511 - {
3899 + if (!s.isMe()) {
3900 if (process.platform == 'win32') { s.close(); }
3901 sendConsoleText('Self Update cannot continue, this agent is not an instance of (' + name + ')', sessionid);
3902 return;
3903 }
3904 if (process.platform == 'win32') { s.close(); }
3905 }
4518 - catch (zz)
4519 - {
3906 + catch (zz) {
3907 sendConsoleText('Self Update Failed because this agent is not an instance of (' + name + ')', sessionid);
3908 sendAgentMessage('Self Update Failed because this agent is not an instance of (' + name + ')', 3);
3909 return;
@@ -4527,15 +3914,13 @@ function agentUpdate_Start(updateurl, updateoptions)
3914 options.protocol = 'https:';
3915 if (updateurl == null) { options.path = ('/meshagents?id=' + require('MeshAgent').ARCHID); }
3916 options.rejectUnauthorized = false;
4530 - options.checkServerIdentity = function checkServerIdentity(certs)
4531 - {
3917 + options.checkServerIdentity = function checkServerIdentity(certs) {
3918 // If the tunnel certificate matches the control channel certificate, accept the connection
3919 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.digest == certs[0].digest) return; } catch (ex) { }
3920 try { if (require('MeshAgent').ServerInfo.ControlChannelCertificate.fingerprint == certs[0].fingerprint) return; } catch (ex) { }
3921
3922 // Check that the certificate is the one expected by the server, fail if not.
4537 - if (checkServerIdentity.servertlshash == null)
4538 - {
3923 + if (checkServerIdentity.servertlshash == null) {
3924 if (require('MeshAgent').ServerInfo == null || require('MeshAgent').ServerInfo.ControlChannelCertificate == null) { return; }
3925
3926 sendConsoleText('Self Update failed, because the url cannot be verified', sessionid);
@@ -4543,8 +3928,7 @@ function agentUpdate_Start(updateurl, updateoptions)
3928 throw new Error('BadCert');
3929 }
3930 if (certs[0].digest == null) { return; }
4546 - if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase()))
4547 - {
3931 + if ((checkServerIdentity.servertlshash != null) && (checkServerIdentity.servertlshash.toLowerCase() != certs[0].digest.split(':').join('').toLowerCase())) {
3932 sendConsoleText('Self Update failed, because the supplied certificate does not match', sessionid);
3933 sendAgentMessage('Self Update failed, because the supplied certificate does not match', 3);
3934 throw new Error('BadCert')
@@ -4552,46 +3936,37 @@ function agentUpdate_Start(updateurl, updateoptions)
3936 }
3937 options.checkServerIdentity.servertlshash = (updateoptions != null ? updateoptions.tlshash : null);
3938 agentUpdate_Start._selfupdate = require('https').get(options);
4555 - agentUpdate_Start._selfupdate.on('error', function (e)
4556 - {
3939 + agentUpdate_Start._selfupdate.on('error', function (e) {
3940 sendConsoleText('Self Update failed, because there was a problem trying to download the update', sessionid);
3941 sendAgentMessage('Self Update failed, because there was a problem trying to download the update', 3);
3942 });
4560 - agentUpdate_Start._selfupdate.on('response', function (img)
4561 - {
3943 + agentUpdate_Start._selfupdate.on('response', function (img) {
3944 this._file = require('fs').createWriteStream(agentfilename + '.update', { flags: 'wb' });
3945 this._filehash = require('SHA384Stream').create();
4564 - this._filehash.on('hash', function (h)
4565 - {
4566 - if (updateoptions != null && updateoptions.hash != null)
4567 - {
4568 - if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase())
4569 - {
3946 + this._filehash.on('hash', function (h) {
3947 + if (updateoptions != null && updateoptions.hash != null) {
3948 + if (updateoptions.hash.toLowerCase() == h.toString('hex').toLowerCase()) {
3949 if (sessionid != null) { sendConsoleText('Download complete. HASH verified.', sessionid); }
3950 }
4572 - else
4573 - {
3951 + else {
3952 agentUpdate_Start._retryCount++;
3953 sendConsoleText('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + ')', sessionid);
3954 sendAgentMessage('Self Update FAILED because the downloaded agent FAILED hash check (' + agentUpdate_Start._retryCount + ')', 3);
3955 agentUpdate_Start._selfupdate = null;
3956
4579 - if (agentUpdate_Start._retryCount < 4)
4580 - {
3957 + if (agentUpdate_Start._retryCount < 4) {
3958 // Retry the download again
3959 sendConsoleText('Self Update will try again in 60 seconds...', sessionid);
3960 agentUpdate_Start._timeout = setTimeout(agentUpdate_Start, 60000, updateurl, updateoptions);
3961 }
4585 - else
4586 - {
3962 + else {
3963 sendConsoleText('Self Update giving up, too many failures...', sessionid);
3964 sendAgentMessage('Self Update giving up, too many failures...', 3);
3965 }
3966 return;
3967 }
3968 }
4593 - else
4594 - {
3969 + else {
3970 sendConsoleText('Download complete. HASH=' + h.toString('hex'), sessionid);
3971 }
3972
@@ -4599,13 +3974,11 @@ function agentUpdate_Start(updateurl, updateoptions)
3974 try { require('MeshAgent').SendCommand({ action: 'agentupdatedownloaded' }); } catch (e) { }
3975
3976 if (sessionid != null) { sendConsoleText('Updating and restarting agent...', sessionid); }
4602 - if (process.platform == 'win32')
4603 - {
3977 + if (process.platform == 'win32') {
3978 // Use _wexecve() equivalent to perform the update
3979 windows_execve(name, agentfilename, sessionid);
3980 }
4607 - else
4608 - {
3981 + else {
3982 var m = require('fs').statSync(process.execPath).mode;
3983 require('fs').chmodSync(process.cwd() + agentfilename + '.update', m);
3984
@@ -4619,8 +3992,7 @@ function agentUpdate_Start(updateurl, updateoptions)
3992 // erase update
3993 require('fs').unlinkSync(process.cwd() + agentfilename + '.update');
3994
4622 - switch (process.platform)
4623 - {
3995 + switch (process.platform) {
3996 case 'freebsd':
3997 bsd_execv(name, agentfilename, sessionid);
3998 break;
@@ -4628,14 +4000,12 @@ function agentUpdate_Start(updateurl, updateoptions)
4000 linux_execv(name, agentfilename, sessionid);
4001 break;
4002 default:
4631 - try
4632 - {
4003 + try {
4004 // restart service
4005 var s = require('service-manager').manager.getService(name);
4006 s.restart();
4007 }
4637 - catch (zz)
4638 - {
4008 + catch (zz) {
4009 sendConsoleText('Self Update encountered an error trying to restart service', sessionid);
4010 sendAgentMessage('Self Update encountered an error trying to restart service', 3);
4011 }
@@ -4657,16 +4027,13 @@ function agentUpdate_Start(updateurl, updateoptions)
4027 //process.exit = function (code) { console.log("Exit with code: " + code.toString()); }
4028
4029 // Called when the server connection state changes
4660 -function handleServerConnection(state)
4661 -{
4030 +function handleServerConnection(state) {
4031 meshServerConnectionState = state;
4663 - if (meshServerConnectionState == 0)
4664 - {
4032 + if (meshServerConnectionState == 0) {
4033 // Server disconnected
4034 if (selfInfoUpdateTimer != null) { clearInterval(selfInfoUpdateTimer); selfInfoUpdateTimer = null; }
4035 lastSelfInfo = null;
4668 - } else
4669 - {
4036 + } else {
4037 // Server connected, send mesh core information
4038 var oldNodeId = db.Get('OldNodeId');
4039 if (oldNodeId != null) { mesh.SendCommand({ action: 'mc1migration', oldnodeid: oldNodeId }); }
@@ -4677,15 +4044,13 @@ function handleServerConnection(state)
4044 // Update the server on with basic info, logged in users and more advanced stuff, like Intel ME and Network Settings
4045 meInfoStr = null;
4046 sendPeriodicServerUpdate(null, true);
4680 - if (selfInfoUpdateTimer == null)
4681 - {
4047 + if (selfInfoUpdateTimer == null) {
4048 selfInfoUpdateTimer = setInterval(sendPeriodicServerUpdate, 1200000); // 20 minutes
4049 selfInfoUpdateTimer.metadata = 'meshcore (InfoUpdate Timer)';
4050 }
4051
4052 // Send any state messages
4687 - if (Object.keys(tunnelUserCount.msg).length > 0)
4688 - {
4053 + if (Object.keys(tunnelUserCount.msg).length > 0) {
4054 try { mesh.SendCommand({ action: 'sessions', type: 'msg', value: tunnelUserCount.msg }); } catch (e) { }
4055 broadcastSessionsToRegisteredApps();
4056 }
@@ -4701,14 +4066,12 @@ function handleServerConnection(state)
4066 // Update the server with the latest network interface information
4067 var sendNetworkUpdateNagleTimer = null;
4068 function sendNetworkUpdateNagle() { if (sendNetworkUpdateNagleTimer != null) { clearTimeout(sendNetworkUpdateNagleTimer); sendNetworkUpdateNagleTimer = null; } sendNetworkUpdateNagleTimer = setTimeout(sendNetworkUpdate, 5000); }
4704 -function sendNetworkUpdate(force)
4705 -{
4069 +function sendNetworkUpdate(force) {
4070 sendNetworkUpdateNagleTimer = null;
4071
4072 // Update the network interfaces information data
4073 var netInfo = { netif2: require('os').networkInterfaces() };
4710 - if (netInfo.netif2)
4711 - {
4074 + if (netInfo.netif2) {
4075 netInfo.action = 'netinfo';
4076 var netInfoStr = JSON.stringify(netInfo);
4077 if ((force == true) || (clearGatewayMac(netInfoStr) != clearGatewayMac(lastNetworkInfo))) { mesh.SendCommand(netInfo); lastNetworkInfo = netInfoStr; }
@@ -4716,17 +4079,14 @@ function sendNetworkUpdate(force)
4079 }
4080
4081 // Called periodically to check if we need to send updates to the server
4719 -function sendPeriodicServerUpdate(flags, force)
4720 -{
4082 +function sendPeriodicServerUpdate(flags, force) {
4083 if (meshServerConnectionState == 0) return; // Not connected to server, do nothing.
4084 if (!flags) { flags = 0xFFFFFFFF; }
4085
4086 // If we have a connected MEI, get Intel ME information
4725 - if ((flags & 1) && (amt != null) && (amt.state == 2))
4726 - {
4087 + if ((flags & 1) && (amt != null) && (amt.state == 2)) {
4088 delete meshCoreObj.intelamt;
4728 - amt.getMeiState(9, function (meinfo)
4729 - {
4089 + amt.getMeiState(9, function (meinfo) {
4090 meshCoreObj.intelamt = meinfo;
4091 meshCoreObj.intelamt.microlms = amt.lmsstate;
4092 meshCoreObjChanged();
@@ -4737,40 +4097,30 @@ function sendPeriodicServerUpdate(flags, force)
4097 if (flags & 2) { sendNetworkUpdateNagle(false); }
4098
4099 // Update anti-virus information
4740 - if ((flags & 4) && (process.platform == 'win32'))
4741 - {
4100 + if ((flags & 4) && (process.platform == 'win32')) {
4101 // Windows Command: "wmic /Namespace:\\root\SecurityCenter2 Path AntiVirusProduct get /FORMAT:CSV"
4102 try { meshCoreObj.av = require('win-info').av(); meshCoreObjChanged(); } catch (e) { av = null; } // Antivirus
4103 //if (process.platform == 'win32') { try { meshCoreObj.pr = require('win-info').pendingReboot(); meshCoreObjChanged(); } catch (e) { meshCoreObj.pr = null; } } // Pending reboot
4104 }
4746 - if (process.platform == 'win32')
4747 - {
4748 - if (require('MeshAgent')._securitycenter == null)
4749 - {
4750 - try
4751 - {
4105 + if (process.platform == 'win32') {
4106 + if (require('MeshAgent')._securitycenter == null) {
4107 + try {
4108 require('MeshAgent')._securitycenter = require('win-securitycenter').status();
4753 - meshCoreObj['windowsSecurityCenter'] = require('MeshAgent')._securitycenter;
4754 - require('win-securitycenter').on('changed', function ()
4755 - {
4109 + meshCoreObj['wsc'] = require('MeshAgent')._securitycenter; // Windows Security Central (WSC)
4110 + require('win-securitycenter').on('changed', function () {
4111 require('MeshAgent')._securitycenter = require('win-securitycenter').status();
4757 - meshCoreObj['windowsSecurityCenter'] = require('MeshAgent')._securitycenter;
4758 - require('MeshAgent').SendCommand({ action: 'coreinfo', windowsSecurityCenter: require('MeshAgent')._securitycenter });
4112 + meshCoreObj['wsc'] = require('MeshAgent')._securitycenter; // Windows Security Central (WSC)
4113 + require('MeshAgent').SendCommand({ action: 'coreinfo', wsc: require('MeshAgent')._securitycenter });
4114 });
4760 - }
4761 - catch (e)
4762 - {
4763 - }
4115 + } catch (e) { }
4116 }
4117 }
4118
4119 // Send available data right now
4768 - if (force)
4769 - {
4120 + if (force) {
4121 meshCoreObj = sortObjRec(meshCoreObj);
4122 var x = JSON.stringify(meshCoreObj);
4772 - if (x != LastPeriodicServerUpdate)
4773 - {
4123 + if (x != LastPeriodicServerUpdate) {
4124 LastPeriodicServerUpdate = x;
4125 mesh.SendCommand(meshCoreObj);
4126 }
@@ -4780,20 +4130,16 @@ function sendPeriodicServerUpdate(flags, force)
4130 // Once we are done collecting all the data, send to server if needed
4131 var LastPeriodicServerUpdate = null;
4132 var PeriodicServerUpdateNagleTimer = null;
4783 -function meshCoreObjChanged()
4784 -{
4785 - if (PeriodicServerUpdateNagleTimer == null)
4786 - {
4133 +function meshCoreObjChanged() {
4134 + if (PeriodicServerUpdateNagleTimer == null) {
4135 PeriodicServerUpdateNagleTimer = setTimeout(meshCoreObjChangedEx, 500);
4136 }
4137 }
4790 -function meshCoreObjChangedEx()
4791 -{
4138 +function meshCoreObjChangedEx() {
4139 PeriodicServerUpdateNagleTimer = null;
4140 meshCoreObj = sortObjRec(meshCoreObj);
4141 var x = JSON.stringify(meshCoreObj);
4795 - if (x != LastPeriodicServerUpdate)
4796 - {
4142 + if (x != LastPeriodicServerUpdate) {
4143 try { LastPeriodicServerUpdate = x; mesh.SendCommand(meshCoreObj); } catch (ex) { }
4144 }
4145 }
@@ -4805,8 +4151,7 @@ function onWebSocketClosed() { sendConsoleText("WebSocket #" + this.httprequest.
4151 function onWebSocketData(data) { sendConsoleText("Got WebSocket #" + this.httprequest.index + " data: " + data, this.httprequest.sessionid); }
4152 function onWebSocketSendOk() { sendConsoleText("WebSocket #" + this.index + " SendOK.", this.sessionid); }
4153
4808 -function onWebSocketUpgrade(response, s, head)
4809 -{
4154 +function onWebSocketUpgrade(response, s, head) {
4155 sendConsoleText("WebSocket #" + this.index + " connected.", this.sessionid);
4156 this.s = s;
4157 s.httprequest = this;
meshagent.js
+6 -2
@@ -1576,9 +1576,13 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1576 }
1577 if ((command.intelamt.UUID != null) && (typeof command.intelamt.UUID == 'string') && (device.intelamt.uuid != command.intelamt.UUID)) { changes.push('AMT uuid'); device.intelamt.uuid = command.intelamt.UUID; change = 1; log = 1; }
1578 }
1579 - if (command.av) {
1579 + if (command.av != null) { // Antivirus
1580 if (!device.av) { device.av = []; }
1581 - if ((command.av != null) && (JSON.stringify(device.av) != JSON.stringify(command.av))) { /*changes.push('AV status');*/ device.av = command.av; change = 1; log = 1; }
1581 + if (JSON.stringify(device.av) != JSON.stringify(command.av)) { /*changes.push('AV status');*/ device.av = command.av; change = 1; log = 1; }
1582 + }
1583 + if (command.wsc != null) { // Windows Security Center
1584 + if (!device.wsc) { device.wsc = {}; }
1585 + if (JSON.stringify(device.wsc) != JSON.stringify(command.wsc)) { /*changes.push('Windows Security Center status');*/ device.wsc = command.wsc; change = 1; log = 1; }
1586 }
1587
1588 if ((command.users != null) && (Array.isArray(command.users)) && (device.users != command.users)) { device.users = command.users; change = 1; } // Don't save this to the db.
translate/translate.json
+1883 -1823
@@ -17,8 +17,8 @@
17 "zh-chs": " + CIRA",
18 "zh-cht": " + CIRA",
19 "xloc": [
20 - "default.handlebars->31->1430",
21 - "default.handlebars->31->1432"
20 + "default.handlebars->31->1443",
21 + "default.handlebars->31->1445"
22 ]
23 },
24 {
@@ -204,7 +204,7 @@
204 "zh-chs": " 可以使用密码提示,但不建议使用。",
205 "zh-cht": " 可以使用密碼提示,但不建議使用。",
206 "xloc": [
207 - "default.handlebars->31->1343"
207 + "default.handlebars->31->1356"
208 ]
209 },
210 {
@@ -224,8 +224,8 @@
224 "zh-chs": " 用户需要先登录到该服务器一次,然后才能将其添加到设备组。",
225 "zh-cht": " 用戶需要先登入到該伺服器一次,然後才能將其新增到裝置群。",
226 "xloc": [
227 - "default.handlebars->31->1507",
228 - "default.handlebars->31->1971"
227 + "default.handlebars->31->1520",
228 + "default.handlebars->31->1984"
229 ]
230 },
231 {
@@ -432,7 +432,7 @@
432 "zh-chs": "* 8个字符,1个大写,1个小写,1个数字,1个非字母数字。",
433 "zh-cht": "* 8個字符,1個大寫,1個小寫,1個數字,1個非字母數字。",
434 "xloc": [
435 - "default.handlebars->31->1476",
435 + "default.handlebars->31->1489",
436 "default.handlebars->31->323"
437 ]
438 },
@@ -507,8 +507,8 @@
507 "zh-chs": ",",
508 "zh-cht": ",",
509 "xloc": [
510 - "default-mobile.handlebars->11->515",
511 - "default.handlebars->31->1577"
510 + "default-mobile.handlebars->11->532",
511 + "default.handlebars->31->1590"
512 ]
513 },
514 {
@@ -549,7 +549,7 @@
549 "zh-chs": ",MQTT在线",
550 "zh-cht": ",MQTT在線",
551 "xloc": [
552 - "default.handlebars->31->1084"
552 + "default.handlebars->31->1097"
553 ]
554 },
555 {
@@ -557,7 +557,7 @@
557 "fr": ", Pas de consentement",
558 "nl": ", Geen toestemming",
559 "xloc": [
560 - "default.handlebars->31->697"
560 + "default.handlebars->31->710"
561 ]
562 },
563 {
@@ -577,7 +577,7 @@
577 "zh-chs": ",提示同意",
578 "zh-cht": ",提示同意",
579 "xloc": [
580 - "default.handlebars->31->698"
580 + "default.handlebars->31->711"
581 ]
582 },
583 {
@@ -597,7 +597,7 @@
597 "zh-chs": ",软体KVM",
598 "zh-cht": ",軟體KVM",
599 "xloc": [
600 - "default.handlebars->31->870",
600 + "default.handlebars->31->883",
601 "desktop.handlebars->3->12"
602 ]
603 },
@@ -606,14 +606,14 @@
606 "fr": ", barre d'outils",
607 "nl": ", Werkbalk",
608 "xloc": [
609 - "default.handlebars->31->699"
609 + "default.handlebars->31->712"
610 ]
611 },
612 {
613 "en": ", View only",
614 "nl": ", Alleen kijken",
615 "xloc": [
616 - "default.handlebars->31->696"
616 + "default.handlebars->31->709"
617 ]
618 },
619 {
@@ -635,9 +635,9 @@
635 "xloc": [
636 "default-mobile.handlebars->11->314",
637 "default-mobile.handlebars->11->347",
638 - "default.handlebars->31->877",
639 - "default.handlebars->31->936",
640 - "default.handlebars->31->948",
638 + "default.handlebars->31->890",
639 + "default.handlebars->31->949",
640 + "default.handlebars->31->961",
641 "desktop.handlebars->3->19",
642 "terminal.handlebars->3->9",
643 "xterm.handlebars->9->6"
@@ -760,7 +760,7 @@
760 "zh-chs": ",{0}观看",
761 "zh-cht": ",{0}觀看",
762 "xloc": [
763 - "default.handlebars->31->871",
763 + "default.handlebars->31->884",
764 "desktop.handlebars->3->13"
765 ]
766 },
@@ -825,9 +825,9 @@
825 "xloc": [
826 "default-mobile.handlebars->11->119",
827 "default-mobile.handlebars->11->349",
828 - "default.handlebars->31->1618",
829 - "default.handlebars->31->2130",
830 - "default.handlebars->31->954"
828 + "default.handlebars->31->1631",
829 + "default.handlebars->31->2143",
830 + "default.handlebars->31->967"
831 ]
832 },
833 {
@@ -884,7 +884,7 @@
884 "zh-chs": "1个活跃时段",
885 "zh-cht": "1個活躍時段",
886 "xloc": [
887 - "default.handlebars->31->2042"
887 + "default.handlebars->31->2055"
888 ]
889 },
890 {
@@ -905,8 +905,8 @@
905 "zh-cht": "1個位元組",
906 "xloc": [
907 "default-mobile.handlebars->11->129",
908 - "default-mobile.handlebars->11->558",
909 - "default.handlebars->31->1642",
908 + "default-mobile.handlebars->11->575",
909 + "default.handlebars->31->1655",
910 "download.handlebars->3->1",
911 "download2.handlebars->5->1"
912 ]
@@ -928,7 +928,7 @@
928 "zh-chs": "1条连接",
929 "zh-cht": "1位聯絡文",
930 "xloc": [
931 - "default.handlebars->31->873",
931 + "default.handlebars->31->886",
932 "desktop.handlebars->3->15"
933 ]
934 },
@@ -971,7 +971,7 @@
971 "zh-chs": "1组",
972 "zh-cht": "1群",
973 "xloc": [
974 - "default.handlebars->31->2005"
974 + "default.handlebars->31->2018"
975 ]
976 },
977 {
@@ -1013,7 +1013,7 @@
1013 "zh-chs": "1分钟",
1014 "zh-cht": "1分鐘",
1015 "xloc": [
1016 - "default.handlebars->31->753"
1016 + "default.handlebars->31->766"
1017 ]
1018 },
1019 {
@@ -1075,7 +1075,7 @@
1075 "zh-chs": "有1个用户没有显示,请使用搜索框查找用户...",
1076 "zh-cht": "有1個用戶沒有顯示,請使用搜尋框搜尋用戶...",
1077 "xloc": [
1078 - "default.handlebars->31->1795"
1078 + "default.handlebars->31->1808"
1079 ]
1080 },
1081 {
@@ -1141,7 +1141,7 @@
1141 "default-mobile.handlebars->11->183",
1142 "default-mobile.handlebars->11->186",
1143 "default-mobile.handlebars->11->189",
1144 - "default.handlebars->31->1799",
1144 + "default.handlebars->31->1812",
1145 "default.handlebars->31->268",
1146 "default.handlebars->31->271",
1147 "default.handlebars->31->274",
@@ -1273,7 +1273,7 @@
1273 "zh-chs": "10分钟",
1274 "zh-cht": "10分鐘",
1275 "xloc": [
1276 - "default.handlebars->31->755"
1276 + "default.handlebars->31->768"
1277 ]
1278 },
1279 {
@@ -1356,7 +1356,7 @@
1356 "zh-chs": "12小时",
1357 "zh-cht": "12小時",
1358 "xloc": [
1359 - "default.handlebars->31->763"
1359 + "default.handlebars->31->776"
1360 ]
1361 },
1362 {
@@ -1398,7 +1398,7 @@
1398 "zh-chs": "15分钟",
1399 "zh-cht": "15分鐘",
1400 "xloc": [
1401 - "default.handlebars->31->756"
1401 + "default.handlebars->31->769"
1402 ]
1403 },
1404 {
@@ -1418,7 +1418,7 @@
1418 "zh-chs": "16小时",
1419 "zh-cht": "16小時",
1420 "xloc": [
1421 - "default.handlebars->31->764"
1421 + "default.handlebars->31->777"
1422 ]
1423 },
1424 {
@@ -1438,7 +1438,7 @@
1438 "zh-chs": "2天",
1439 "zh-cht": "2天",
1440 "xloc": [
1441 - "default.handlebars->31->766"
1441 + "default.handlebars->31->779"
1442 ]
1443 },
1444 {
@@ -1458,7 +1458,7 @@
1458 "zh-chs": "2小时",
1459 "zh-cht": "2小時",
1460 "xloc": [
1461 - "default.handlebars->31->760"
1461 + "default.handlebars->31->773"
1462 ]
1463 },
1464 {
@@ -1562,7 +1562,7 @@
1562 "zh-chs": "24小时",
1563 "zh-cht": "24小時",
1564 "xloc": [
1565 - "default.handlebars->31->765"
1565 + "default.handlebars->31->778"
1566 ]
1567 },
1568 {
@@ -1624,7 +1624,7 @@
1624 "zh-chs": "2FA备份代码已清除",
1625 "zh-cht": "2FA備份代碼已清除",
1626 "xloc": [
1627 - "default.handlebars->31->1753"
1627 + "default.handlebars->31->1766"
1628 ]
1629 },
1630 {
@@ -1644,8 +1644,8 @@
1644 "zh-chs": "启用第二因素身份验证",
1645 "zh-cht": "啟用第二因素身份驗證",
1646 "xloc": [
1647 - "default.handlebars->31->1812",
1648 - "default.handlebars->31->2027"
1647 + "default.handlebars->31->1825",
1648 + "default.handlebars->31->2040"
1649 ]
1650 },
1651 {
@@ -1764,7 +1764,7 @@
1764 "zh-chs": "30分钟",
1765 "zh-cht": "30分鐘",
1766 "xloc": [
1767 - "default.handlebars->31->757"
1767 + "default.handlebars->31->770"
1768 ]
1769 },
1770 {
@@ -1827,7 +1827,7 @@
1827 "zh-chs": "4天",
1828 "zh-cht": "4天",
1829 "xloc": [
1830 - "default.handlebars->31->767"
1830 + "default.handlebars->31->780"
1831 ]
1832 },
1833 {
@@ -1847,7 +1847,7 @@
1847 "zh-chs": "4个小时",
1848 "zh-cht": "4個小時",
1849 "xloc": [
1850 - "default.handlebars->31->761"
1850 + "default.handlebars->31->774"
1851 ]
1852 },
1853 {
@@ -1930,7 +1930,7 @@
1930 "zh-chs": "45分钟",
1931 "zh-cht": "45分鐘",
1932 "xloc": [
1933 - "default.handlebars->31->758"
1933 + "default.handlebars->31->771"
1934 ]
1935 },
1936 {
@@ -1970,7 +1970,7 @@
1970 "zh-chs": "5分钟",
1971 "zh-cht": "5分鐘",
1972 "xloc": [
1973 - "default.handlebars->31->754"
1973 + "default.handlebars->31->767"
1974 ]
1975 },
1976 {
@@ -2096,7 +2096,7 @@
2096 "zh-chs": "60分钟",
2097 "zh-cht": "60分鐘",
2098 "xloc": [
2099 - "default.handlebars->31->759"
2099 + "default.handlebars->31->772"
2100 ]
2101 },
2102 {
@@ -2216,7 +2216,7 @@
2216 "zh-chs": "7天电源状态",
2217 "zh-cht": "7天電源狀態",
2218 "xloc": [
2219 - "default.handlebars->31->798"
2219 + "default.handlebars->31->811"
2220 ]
2221 },
2222 {
@@ -2281,7 +2281,7 @@
2281 "xloc": [
2282 "default.handlebars->31->347",
2283 "default.handlebars->31->361",
2284 - "default.handlebars->31->762"
2284 + "default.handlebars->31->775"
2285 ]
2286 },
2287 {
@@ -2513,7 +2513,7 @@
2513 "zh-cht": "ACM",
2514 "xloc": [
2515 "default-mobile.handlebars->11->247",
2516 - "default.handlebars->31->1446",
2516 + "default.handlebars->31->1459",
2517 "default.handlebars->31->588"
2518 ]
2519 },
@@ -2677,6 +2677,15 @@
2677 "default.handlebars->31->39"
2678 ]
2679 },
2680 + {
2681 + "en": "AV",
2682 + "xloc": [
2683 + "default-mobile.handlebars->11->385",
2684 + "default-mobile.handlebars->11->387",
2685 + "default.handlebars->31->607",
2686 + "default.handlebars->31->609"
2687 + ]
2688 + },
2689 {
2690 "cs": "Přístup odepřen",
2691 "de": "Zugriff verweigert",
@@ -2694,7 +2703,7 @@
2703 "zh-chs": "拒绝访问",
2704 "zh-cht": "拒絕存取",
2705 "xloc": [
2697 - "default.handlebars->31->1085"
2706 + "default.handlebars->31->1098"
2707 ]
2708 },
2709 {
@@ -2736,7 +2745,7 @@
2745 "zh-chs": "访问服务器档案",
2746 "zh-cht": "存取伺服器檔案",
2747 "xloc": [
2739 - "default.handlebars->31->1977"
2748 + "default.handlebars->31->1990"
2749 ]
2750 },
2751 {
@@ -2825,9 +2834,9 @@
2834 "default-mobile.handlebars->11->222",
2835 "default-mobile.handlebars->11->224",
2836 "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountSecurity->1->0",
2828 - "default.handlebars->31->1352",
2829 - "default.handlebars->31->1354",
2830 - "default.handlebars->31->2244",
2837 + "default.handlebars->31->1365",
2838 + "default.handlebars->31->1367",
2839 + "default.handlebars->31->2257",
2840 "default.handlebars->31->557",
2841 "default.handlebars->31->559"
2842 ]
@@ -2837,8 +2846,8 @@
2846 "nl": "Account instellingen",
2847 "fr": "Paramètres du compte",
2848 "xloc": [
2840 - "default-mobile.handlebars->11->526",
2841 - "default.handlebars->31->2138"
2849 + "default-mobile.handlebars->11->543",
2850 + "default.handlebars->31->2151"
2851 ]
2852 },
2853 {
@@ -2899,7 +2908,7 @@
2908 "zh-chs": "帐户已更改:{0}",
2909 "zh-cht": "帳戶已更改:{0}",
2910 "xloc": [
2902 - "default.handlebars->31->1726"
2911 + "default.handlebars->31->1739"
2912 ]
2913 },
2914 {
@@ -2919,7 +2928,7 @@
2928 "zh-chs": "创建帐户,电子邮件为{0}",
2929 "zh-cht": "創建帳戶,電子郵件為{0}",
2930 "xloc": [
2922 - "default.handlebars->31->1725"
2931 + "default.handlebars->31->1738"
2932 ]
2933 },
2934 {
@@ -2939,7 +2948,7 @@
2948 "zh-chs": "创建帐户,用户名是{0}",
2949 "zh-cht": "帳戶已創建,用戶名是{0}",
2950 "xloc": [
2942 - "default.handlebars->31->1724"
2951 + "default.handlebars->31->1737"
2952 ]
2953 },
2954 {
@@ -2959,8 +2968,8 @@
2968 "zh-chs": "帐户已被锁定",
2969 "zh-cht": "帳戶已被鎖定",
2970 "xloc": [
2962 - "default.handlebars->31->1814",
2963 - "default.handlebars->31->1974"
2971 + "default.handlebars->31->1827",
2972 + "default.handlebars->31->1987"
2973 ]
2974 },
2975 {
@@ -2980,8 +2989,8 @@
2989 "zh-chs": "达到帐户限制。",
2990 "zh-cht": "達到帳戶限制。",
2991 "xloc": [
2983 - "default-mobile.handlebars->11->538",
2984 - "default.handlebars->31->2150",
2992 + "default-mobile.handlebars->11->555",
2993 + "default.handlebars->31->2163",
2994 "login-mobile.handlebars->5->6",
2995 "login.handlebars->5->6",
2996 "login2.handlebars->7->7"
@@ -3026,7 +3035,7 @@
3035 "zh-chs": "帐号登录",
3036 "zh-cht": "帳號登錄",
3037 "xloc": [
3029 - "default.handlebars->31->1661"
3038 + "default.handlebars->31->1674"
3039 ]
3040 },
3041 {
@@ -3046,7 +3055,7 @@
3055 "zh-chs": "帐户登出",
3056 "zh-cht": "帳戶登出",
3057 "xloc": [
3049 - "default.handlebars->31->1662"
3058 + "default.handlebars->31->1675"
3059 ]
3060 },
3061 {
@@ -3088,7 +3097,7 @@
3097 "zh-chs": "帐户密码已更改:{0}",
3098 "zh-cht": "帳戶密碼已更改:{0}",
3099 "xloc": [
3091 - "default.handlebars->31->1734"
3100 + "default.handlebars->31->1747"
3101 ]
3102 },
3103 {
@@ -3108,7 +3117,7 @@
3117 "zh-chs": "帐户已删除",
3118 "zh-cht": "帳戶已刪除",
3119 "xloc": [
3111 - "default.handlebars->31->1723"
3120 + "default.handlebars->31->1736"
3121 ]
3122 },
3123 {
@@ -3148,7 +3157,7 @@
3157 "zh-chs": "指令",
3158 "zh-cht": "指令",
3159 "xloc": [
3151 - "default.handlebars->31->1090",
3160 + "default.handlebars->31->1103",
3161 "default.handlebars->container->column_l->p42->p42tbl->1->0->8"
3162 ]
3163 },
@@ -3169,8 +3178,8 @@
3178 "zh-chs": "动作档案",
3179 "zh-cht": "動作檔案",
3180 "xloc": [
3172 - "default.handlebars->31->844",
3173 - "default.handlebars->31->846"
3181 + "default.handlebars->31->857",
3182 + "default.handlebars->31->859"
3183 ]
3184 },
3185 {
@@ -3193,7 +3202,7 @@
3202 "default-mobile.handlebars->11->270",
3203 "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea4->1->3",
3204 "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->0->1->1",
3196 - "default.handlebars->31->637",
3205 + "default.handlebars->31->650",
3206 "default.handlebars->container->column_l->p11->deskarea0->deskarea1->1",
3207 "default.handlebars->container->column_l->p12->termTable->1->1->0->1->1",
3208 "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->1"
@@ -3276,7 +3285,7 @@
3285 "zh-chs": "如果ACM失败,则激活到CCM",
3286 "zh-cht": "如果ACM失敗,則激活到CCM",
3287 "xloc": [
3279 - "default.handlebars->31->1467"
3288 + "default.handlebars->31->1480"
3289 ]
3290 },
3291 {
@@ -3298,8 +3307,8 @@
3307 "xloc": [
3308 "default-mobile.handlebars->11->242",
3309 "default-mobile.handlebars->11->244",
3301 - "default-mobile.handlebars->11->418",
3302 - "default.handlebars->31->1046",
3310 + "default-mobile.handlebars->11->435",
3311 + "default.handlebars->31->1059",
3312 "default.handlebars->31->581",
3313 "default.handlebars->31->583"
3314 ]
@@ -3341,7 +3350,7 @@
3350 "zh-chs": "主动设备共享",
3351 "zh-cht": "主動設備共享",
3352 "xloc": [
3344 - "default.handlebars->31->690"
3353 + "default.handlebars->31->703"
3354 ]
3355 },
3356 {
@@ -3367,7 +3376,7 @@
3376 "nl": "Toevoegen",
3377 "xloc": [
3378 "default-mobile.handlebars->11->340",
3370 - "default.handlebars->31->907"
3379 + "default.handlebars->31->920"
3380 ]
3381 },
3382 {
@@ -3387,7 +3396,7 @@
3396 "zh-chs": "添加代理",
3397 "zh-cht": "新增代理",
3398 "xloc": [
3390 - "default.handlebars->31->1442",
3399 + "default.handlebars->31->1455",
3400 "default.handlebars->31->301"
3401 ]
3402 },
@@ -3425,8 +3434,8 @@
3434 "zh-chs": "添加设备",
3435 "zh-cht": "新增裝置",
3436 "xloc": [
3428 - "default.handlebars->31->1951",
3429 - "default.handlebars->31->2077"
3437 + "default.handlebars->31->1964",
3438 + "default.handlebars->31->2090"
3439 ]
3440 },
3441 {
@@ -3446,7 +3455,7 @@
3455 "zh-chs": "添加设备日志",
3456 "zh-cht": "新增裝置日誌",
3457 "xloc": [
3449 - "default.handlebars->31->739"
3458 + "default.handlebars->31->752"
3459 ]
3460 },
3461 {
@@ -3466,9 +3475,9 @@
3475 "zh-chs": "添加设备组",
3476 "zh-cht": "新增裝置群",
3477 "xloc": [
3469 - "default.handlebars->31->1541",
3470 - "default.handlebars->31->1945",
3471 - "default.handlebars->31->2065",
3478 + "default.handlebars->31->1554",
3479 + "default.handlebars->31->1958",
3480 + "default.handlebars->31->2078",
3481 "default.handlebars->31->238"
3482 ]
3483 },
@@ -3489,7 +3498,7 @@
3498 "zh-chs": "添加设备组权限",
3499 "zh-cht": "新增裝置群權限",
3500 "xloc": [
3492 - "default.handlebars->31->1538"
3501 + "default.handlebars->31->1551"
3502 ]
3503 },
3504 {
@@ -3509,8 +3518,8 @@
3518 "zh-chs": "添加设备权限",
3519 "zh-cht": "新增裝置權限",
3520 "xloc": [
3512 - "default.handlebars->31->1543",
3513 - "default.handlebars->31->1545"
3521 + "default.handlebars->31->1556",
3522 + "default.handlebars->31->1558"
3523 ]
3524 },
3525 {
@@ -3607,7 +3616,7 @@
3616 "zh-chs": "添加成员身份",
3617 "zh-cht": "新增成員身份",
3618 "xloc": [
3610 - "default.handlebars->31->2097"
3619 + "default.handlebars->31->2110"
3620 ]
3621 },
3622 {
@@ -3647,8 +3656,8 @@
3656 "zh-chs": "添加安全密钥",
3657 "zh-cht": "新增安全密鑰",
3658 "xloc": [
3650 - "default.handlebars->31->1119",
3651 - "default.handlebars->31->1120",
3659 + "default.handlebars->31->1132",
3660 + "default.handlebars->31->1133",
3661 "default.handlebars->31->160",
3662 "default.handlebars->31->162",
3663 "default.handlebars->31->165",
@@ -3672,8 +3681,8 @@
3681 "zh-chs": "添加用户",
3682 "zh-cht": "新增用戶",
3683 "xloc": [
3675 - "default-mobile.handlebars->11->460",
3676 - "default.handlebars->31->682"
3684 + "default-mobile.handlebars->11->477",
3685 + "default.handlebars->31->695"
3686 ]
3687 },
3688 {
@@ -3693,7 +3702,7 @@
3702 "zh-chs": "添加用户设备权限",
3703 "zh-cht": "新增用戶裝置權限",
3704 "xloc": [
3696 - "default.handlebars->31->1548"
3705 + "default.handlebars->31->1561"
3706 ]
3707 },
3708 {
@@ -3713,10 +3722,10 @@
3722 "zh-chs": "添加用户组",
3723 "zh-cht": "新增用戶群",
3724 "xloc": [
3716 - "default.handlebars->31->1438",
3717 - "default.handlebars->31->1540",
3718 - "default.handlebars->31->2071",
3719 - "default.handlebars->31->683"
3725 + "default.handlebars->31->1451",
3726 + "default.handlebars->31->1553",
3727 + "default.handlebars->31->2084",
3728 + "default.handlebars->31->696"
3729 ]
3730 },
3731 {
@@ -3736,7 +3745,7 @@
3745 "zh-chs": "添加用户组设备权限",
3746 "zh-cht": "新增用戶群裝置權限",
3747 "xloc": [
3739 - "default.handlebars->31->1550"
3748 + "default.handlebars->31->1563"
3749 ]
3750 },
3751 {
@@ -3756,7 +3765,7 @@
3765 "zh-chs": "将用户添加到设备组",
3766 "zh-cht": "將用戶新增到裝置群",
3767 "xloc": [
3759 - "default-mobile.handlebars->11->491"
3768 + "default-mobile.handlebars->11->508"
3769 ]
3770 },
3771 {
@@ -3793,8 +3802,8 @@
3802 "zh-chs": "添加用户",
3803 "zh-cht": "新增用戶",
3804 "xloc": [
3796 - "default.handlebars->31->1437",
3797 - "default.handlebars->31->1940"
3805 + "default.handlebars->31->1450",
3806 + "default.handlebars->31->1953"
3807 ]
3808 },
3809 {
@@ -3814,7 +3823,7 @@
3823 "zh-chs": "将用户添加到设备组",
3824 "zh-cht": "將用戶新增到裝置群",
3825 "xloc": [
3817 - "default.handlebars->31->1537"
3826 + "default.handlebars->31->1550"
3827 ]
3828 },
3829 {
@@ -3834,7 +3843,7 @@
3843 "zh-chs": "将用户添加到用户组",
3844 "zh-cht": "將用戶新增到用戶群",
3845 "xloc": [
3837 - "default.handlebars->31->1973"
3846 + "default.handlebars->31->1986"
3847 ]
3848 },
3849 {
@@ -3951,7 +3960,7 @@
3960 "zh-chs": "通过安装Mesh Agent将新计算机添加到该设备组。",
3961 "zh-cht": "通過安裝Mesh Agent將新電腦新增到該裝置群。",
3962 "xloc": [
3954 - "default.handlebars->31->1441",
3963 + "default.handlebars->31->1454",
3964 "default.handlebars->31->300"
3965 ]
3966 },
@@ -4012,7 +4021,7 @@
4021 "zh-chs": "添加了身份验证应用程序",
4022 "zh-cht": "添加了身份驗證應用程序",
4023 "xloc": [
4015 - "default.handlebars->31->1750"
4024 + "default.handlebars->31->1763"
4025 ]
4026 },
4027 {
@@ -4032,7 +4041,7 @@
4041 "zh-chs": "已将设备共享{0}从{1}添加到{2}",
4042 "zh-cht": "已將設備共享{0}從{1}添加到{2}",
4043 "xloc": [
4035 - "default.handlebars->31->1761"
4044 + "default.handlebars->31->1774"
4045 ]
4046 },
4047 {
@@ -4052,8 +4061,8 @@
4061 "zh-chs": "已将设备{0}添加到设备组{1}",
4062 "zh-cht": "已將設備{0}添加到設備組{1}",
4063 "xloc": [
4055 - "default.handlebars->31->1717",
4056 - "default.handlebars->31->1744"
4064 + "default.handlebars->31->1730",
4065 + "default.handlebars->31->1757"
4066 ]
4067 },
4068 {
@@ -4073,7 +4082,7 @@
4082 "zh-chs": "添加了安全密钥",
4083 "zh-cht": "添加了安全密鑰",
4084 "xloc": [
4076 - "default.handlebars->31->1755"
4085 + "default.handlebars->31->1768"
4086 ]
4087 },
4088 {
@@ -4093,7 +4102,7 @@
4102 "zh-chs": "已将用户组{0}添加到设备组{1}",
4103 "zh-cht": "已將用戶組{0}添加到設備組{1}",
4104 "xloc": [
4096 - "default.handlebars->31->1728"
4105 + "default.handlebars->31->1741"
4106 ]
4107 },
4108 {
@@ -4113,8 +4122,8 @@
4122 "zh-chs": "已将用户{0}添加到用户组{1}",
4123 "zh-cht": "已將用戶{0}添加到用戶組{1}",
4124 "xloc": [
4116 - "default.handlebars->31->1731",
4117 - "default.handlebars->31->1740"
4125 + "default.handlebars->31->1744",
4126 + "default.handlebars->31->1753"
4127 ]
4128 },
4129 {
@@ -4174,8 +4183,8 @@
4183 "zh-chs": "管理员控制模式(ACM)",
4184 "zh-cht": "管理員控制模式(ACM)",
4185 "xloc": [
4177 - "default-mobile.handlebars->11->420",
4178 - "default.handlebars->31->1048"
4186 + "default-mobile.handlebars->11->437",
4187 + "default.handlebars->31->1061"
4188 ]
4189 },
4190 {
@@ -4195,8 +4204,8 @@
4204 "zh-chs": "管理员凭证",
4205 "zh-cht": "管理員憑證",
4206 "xloc": [
4198 - "default-mobile.handlebars->11->426",
4199 - "default.handlebars->31->1054"
4207 + "default-mobile.handlebars->11->443",
4208 + "default.handlebars->31->1067"
4209 ]
4210 },
4211 {
@@ -4237,7 +4246,7 @@
4246 "zh-chs": "管理领域",
4247 "zh-cht": "管理領域",
4248 "xloc": [
4240 - "default.handlebars->31->2009"
4249 + "default.handlebars->31->2022"
4250 ]
4251 },
4252 {
@@ -4278,7 +4287,7 @@
4287 "zh-chs": "管理领域",
4288 "zh-cht": "管理領域",
4289 "xloc": [
4281 - "default.handlebars->31->1877"
4290 + "default.handlebars->31->1890"
4291 ]
4292 },
4293 {
@@ -4298,7 +4307,7 @@
4307 "zh-chs": "管理员",
4308 "zh-cht": "管理員",
4309 "xloc": [
4301 - "default.handlebars->31->1806"
4310 + "default.handlebars->31->1819"
4311 ]
4312 },
4313 {
@@ -4318,7 +4327,7 @@
4327 "zh-chs": "南非文",
4328 "zh-cht": "南非文",
4329 "xloc": [
4321 - "default.handlebars->31->1122"
4330 + "default.handlebars->31->1135"
4331 ]
4332 },
4333 {
@@ -4342,8 +4351,8 @@
4351 "default-mobile.handlebars->11->214",
4352 "default-mobile.handlebars->11->239",
4353 "default-mobile.handlebars->11->261",
4345 - "default.handlebars->31->1604",
4346 - "default.handlebars->31->1612",
4354 + "default.handlebars->31->1617",
4355 + "default.handlebars->31->1625",
4356 "default.handlebars->31->254",
4357 "default.handlebars->31->443",
4358 "default.handlebars->container->column_l->p15->consoleTable->1->6->1->1->1->0->p15outputselecttd->p15outputselect->1"
@@ -4366,8 +4375,8 @@
4375 "zh-chs": "代理+英特尔AMT",
4376 "zh-cht": "代理+Intel&reg; AMT",
4377 "xloc": [
4369 - "default.handlebars->31->1606",
4370 - "default.handlebars->31->1614"
4378 + "default.handlebars->31->1619",
4379 + "default.handlebars->31->1627"
4380 ]
4381 },
4382 {
@@ -4407,8 +4416,8 @@
4416 "zh-chs": "代理控制台",
4417 "zh-cht": "代理控制台",
4418 "xloc": [
4410 - "default-mobile.handlebars->11->497",
4411 - "default.handlebars->31->1558"
4419 + "default-mobile.handlebars->11->514",
4420 + "default.handlebars->31->1571"
4421 ]
4422 },
4423 {
@@ -4428,7 +4437,7 @@
4437 "zh-chs": "代理错误计数器",
4438 "zh-cht": "代理錯誤計數器",
4439 "xloc": [
4431 - "default.handlebars->31->2175"
4440 + "default.handlebars->31->2188"
4441 ]
4442 },
4443 {
@@ -4531,7 +4540,7 @@
4540 "zh-chs": "代理时段",
4541 "zh-cht": "代理時段",
4542 "xloc": [
4534 - "default.handlebars->31->2191"
4543 + "default.handlebars->31->2204"
4544 ]
4545 },
4546 {
@@ -4572,7 +4581,7 @@
4581 "zh-chs": "代理类型",
4582 "zh-cht": "代理類型",
4583 "xloc": [
4575 - "default.handlebars->31->1610",
4584 + "default.handlebars->31->1623",
4585 "default.handlebars->container->column_l->p21->3->1->meshOsChartDiv->1"
4586 ]
4587 },
@@ -4593,7 +4602,7 @@
4602 "zh-chs": "代理关闭了与服务器压缩的{0}%代理会话。已发送:{1},已压缩:{2}",
4603 "zh-cht": "代理關閉了與{0}%代理到服務器壓縮的會話。已發送:{1},已壓縮:{2}",
4604 "xloc": [
4596 - "default.handlebars->31->1714"
4605 + "default.handlebars->31->1727"
4606 ]
4607 },
4608 {
@@ -4614,8 +4623,8 @@
4623 "zh-cht": "代理已連接",
4624 "xloc": [
4625 "default.handlebars->31->174",
4617 - "default.handlebars->31->673",
4618 - "default.handlebars->31->674"
4626 + "default.handlebars->31->686",
4627 + "default.handlebars->31->687"
4628 ]
4629 },
4630 {
@@ -4655,7 +4664,7 @@
4664 "zh-chs": "代理离线",
4665 "zh-cht": "代理離線",
4666 "xloc": [
4658 - "default.handlebars->31->1083"
4667 + "default.handlebars->31->1096"
4668 ]
4669 },
4670 {
@@ -4675,7 +4684,7 @@
4684 "zh-chs": "代理在线",
4685 "zh-cht": "代理在線",
4686 "xloc": [
4678 - "default.handlebars->31->1082"
4687 + "default.handlebars->31->1095"
4688 ]
4689 },
4690 {
@@ -4696,7 +4705,7 @@
4705 "zh-cht": "代理在特權降低的遠程設備上運行。",
4706 "xloc": [
4707 "default.handlebars->31->172",
4699 - "default.handlebars->31->671"
4708 + "default.handlebars->31->684"
4709 ]
4710 },
4711 {
@@ -4716,7 +4725,7 @@
4725 "zh-chs": "代理",
4726 "zh-cht": "代理",
4727 "xloc": [
4719 - "default.handlebars->31->2207"
4728 + "default.handlebars->31->2220"
4729 ]
4730 },
4731 {
@@ -4736,7 +4745,7 @@
4745 "zh-chs": "阿尔巴尼亚文",
4746 "zh-cht": "阿爾巴尼亞文",
4747 "xloc": [
4739 - "default.handlebars->31->1123"
4748 + "default.handlebars->31->1136"
4749 ]
4750 },
4751 {
@@ -4779,7 +4788,7 @@
4788 "zh-chs": "全部可用",
4789 "zh-cht": "全部可用",
4790 "xloc": [
4782 - "default.handlebars->31->1769"
4791 + "default.handlebars->31->1782"
4792 ]
4793 },
4794 {
@@ -4816,7 +4825,7 @@
4825 "zh-chs": "所有事件",
4826 "zh-cht": "所有事件",
4827 "xloc": [
4819 - "default.handlebars->31->1767"
4828 + "default.handlebars->31->1780"
4829 ]
4830 },
4831 {
@@ -4836,9 +4845,9 @@
4845 "zh-chs": "全部聚焦",
4846 "zh-cht": "全部聚焦",
4847 "xloc": [
4839 - "default.handlebars->31->878",
4840 - "default.handlebars->31->880",
4841 - "default.handlebars->31->881"
4848 + "default.handlebars->31->891",
4849 + "default.handlebars->31->893",
4850 + "default.handlebars->31->894"
4851 ]
4852 },
4853 {
@@ -4858,8 +4867,8 @@
4867 "zh-chs": "允许用户管理此设备组和该组中的设备。",
4868 "zh-cht": "允許用戶管理此裝置群和該群中的裝置。",
4869 "xloc": [
4861 - "default.handlebars->31->1505",
4862 - "default.handlebars->31->1970"
4870 + "default.handlebars->31->1518",
4871 + "default.handlebars->31->1983"
4872 ]
4873 },
4874 {
@@ -4879,7 +4888,7 @@
4888 "zh-chs": "允许用户管理此设备。",
4889 "zh-cht": "允許用戶管理此裝置。",
4890 "xloc": [
4882 - "default.handlebars->31->1506"
4891 + "default.handlebars->31->1519"
4892 ]
4893 },
4894 {
@@ -4896,8 +4905,8 @@
4905 "xloc": [
4906 "default-mobile.handlebars->11->333",
4907 "default-mobile.handlebars->11->337",
4899 - "default.handlebars->31->900",
4900 - "default.handlebars->31->904"
4908 + "default.handlebars->31->913",
4909 + "default.handlebars->31->917"
4910 ]
4911 },
4912 {
@@ -4959,7 +4968,7 @@
4968 "zh-chs": "备用(F10 = ESC + 0)",
4969 "zh-cht": "備用(F10 = ESC + 0)",
4970 "xloc": [
4962 - "default.handlebars->31->941",
4971 + "default.handlebars->31->954",
4972 "terminal.handlebars->3->19"
4973 ]
4974 },
@@ -5001,10 +5010,10 @@
5010 "zh-chs": "一直通知",
5011 "zh-cht": "一直通知",
5012 "xloc": [
5004 - "default.handlebars->31->1417",
5005 - "default.handlebars->31->1931",
5006 - "default.handlebars->31->2018",
5007 - "default.handlebars->31->619"
5013 + "default.handlebars->31->1430",
5014 + "default.handlebars->31->1944",
5015 + "default.handlebars->31->2031",
5016 + "default.handlebars->31->632"
5017 ]
5018 },
5019 {
@@ -5024,10 +5033,10 @@
5033 "zh-chs": "一直提示",
5034 "zh-cht": "一直提示",
5035 "xloc": [
5027 - "default.handlebars->31->1418",
5028 - "default.handlebars->31->1932",
5029 - "default.handlebars->31->2019",
5030 - "default.handlebars->31->620"
5036 + "default.handlebars->31->1431",
5037 + "default.handlebars->31->1945",
5038 + "default.handlebars->31->2032",
5039 + "default.handlebars->31->633"
5040 ]
5041 },
5042 {
@@ -5167,7 +5176,8 @@
5176 "zh-chs": "杀毒软件",
5177 "zh-cht": "防毒軟體",
5178 "xloc": [
5170 - "default.handlebars->31->610"
5179 + "default-mobile.handlebars->11->401",
5180 + "default.handlebars->31->623"
5181 ]
5182 },
5183 {
@@ -5288,7 +5298,7 @@
5298 "zh-chs": "阿拉伯文(阿尔及利亚)",
5299 "zh-cht": "阿拉伯文(阿爾及利亞)",
5300 "xloc": [
5291 - "default.handlebars->31->1125"
5301 + "default.handlebars->31->1138"
5302 ]
5303 },
5304 {
@@ -5308,7 +5318,7 @@
5318 "zh-chs": "阿拉伯文(巴林)",
5319 "zh-cht": "阿拉伯文(巴林)",
5320 "xloc": [
5311 - "default.handlebars->31->1126"
5321 + "default.handlebars->31->1139"
5322 ]
5323 },
5324 {
@@ -5328,7 +5338,7 @@
5338 "zh-chs": "阿拉伯文(埃及)",
5339 "zh-cht": "阿拉伯文(埃及)",
5340 "xloc": [
5331 - "default.handlebars->31->1127"
5341 + "default.handlebars->31->1140"
5342 ]
5343 },
5344 {
@@ -5348,7 +5358,7 @@
5358 "zh-chs": "阿拉伯文(伊拉克)",
5359 "zh-cht": "阿拉伯文(伊拉克)",
5360 "xloc": [
5351 - "default.handlebars->31->1128"
5361 + "default.handlebars->31->1141"
5362 ]
5363 },
5364 {
@@ -5368,7 +5378,7 @@
5378 "zh-chs": "阿拉伯文(约旦)",
5379 "zh-cht": "阿拉伯文(約旦)",
5380 "xloc": [
5371 - "default.handlebars->31->1129"
5381 + "default.handlebars->31->1142"
5382 ]
5383 },
5384 {
@@ -5388,7 +5398,7 @@
5398 "zh-chs": "阿拉伯文(科威特)",
5399 "zh-cht": "阿拉伯文(科威特)",
5400 "xloc": [
5391 - "default.handlebars->31->1130"
5401 + "default.handlebars->31->1143"
5402 ]
5403 },
5404 {
@@ -5408,7 +5418,7 @@
5418 "zh-chs": "阿拉伯文(黎巴嫩)",
5419 "zh-cht": "阿拉伯文(黎巴嫩)",
5420 "xloc": [
5411 - "default.handlebars->31->1131"
5421 + "default.handlebars->31->1144"
5422 ]
5423 },
5424 {
@@ -5428,7 +5438,7 @@
5438 "zh-chs": "阿拉伯文(利比亚)",
5439 "zh-cht": "阿拉伯文(利比亞)",
5440 "xloc": [
5431 - "default.handlebars->31->1132"
5441 + "default.handlebars->31->1145"
5442 ]
5443 },
5444 {
@@ -5448,7 +5458,7 @@
5458 "zh-chs": "阿拉伯文(摩洛哥)",
5459 "zh-cht": "阿拉伯文(摩洛哥)",
5460 "xloc": [
5451 - "default.handlebars->31->1133"
5461 + "default.handlebars->31->1146"
5462 ]
5463 },
5464 {
@@ -5468,7 +5478,7 @@
5478 "zh-chs": "阿拉伯文(阿曼)",
5479 "zh-cht": "阿拉伯文(阿曼)",
5480 "xloc": [
5471 - "default.handlebars->31->1134"
5481 + "default.handlebars->31->1147"
5482 ]
5483 },
5484 {
@@ -5488,7 +5498,7 @@
5498 "zh-chs": "阿拉伯文(卡塔尔)",
5499 "zh-cht": "阿拉伯文(卡塔爾)",
5500 "xloc": [
5491 - "default.handlebars->31->1135"
5501 + "default.handlebars->31->1148"
5502 ]
5503 },
5504 {
@@ -5508,7 +5518,7 @@
5518 "zh-chs": "阿拉伯文(沙特阿拉伯)",
5519 "zh-cht": "阿拉伯文(沙特阿拉伯)",
5520 "xloc": [
5511 - "default.handlebars->31->1136"
5521 + "default.handlebars->31->1149"
5522 ]
5523 },
5524 {
@@ -5528,7 +5538,7 @@
5538 "zh-chs": "阿拉伯文(标准)",
5539 "zh-cht": "阿拉伯文(標準)",
5540 "xloc": [
5531 - "default.handlebars->31->1124"
5541 + "default.handlebars->31->1137"
5542 ]
5543 },
5544 {
@@ -5548,7 +5558,7 @@
5558 "zh-chs": "阿拉伯文(叙利亚)",
5559 "zh-cht": "阿拉伯文(敘利亞)",
5560 "xloc": [
5551 - "default.handlebars->31->1137"
5561 + "default.handlebars->31->1150"
5562 ]
5563 },
5564 {
@@ -5568,7 +5578,7 @@
5578 "zh-chs": "阿拉伯文(突尼斯)",
5579 "zh-cht": "阿拉伯文(突尼斯)",
5580 "xloc": [
5571 - "default.handlebars->31->1138"
5581 + "default.handlebars->31->1151"
5582 ]
5583 },
5584 {
@@ -5588,7 +5598,7 @@
5598 "zh-chs": "阿拉伯文(阿联酋)",
5599 "zh-cht": "阿拉伯文(阿聯酋)",
5600 "xloc": [
5591 - "default.handlebars->31->1139"
5601 + "default.handlebars->31->1152"
5602 ]
5603 },
5604 {
@@ -5608,7 +5618,7 @@
5618 "zh-chs": "阿拉伯文(也门)",
5619 "zh-cht": "阿拉伯文(也門)",
5620 "xloc": [
5611 - "default.handlebars->31->1140"
5621 + "default.handlebars->31->1153"
5622 ]
5623 },
5624 {
@@ -5628,7 +5638,7 @@
5638 "zh-chs": "阿拉贡文",
5639 "zh-cht": "阿拉貢文",
5640 "xloc": [
5631 - "default.handlebars->31->1141"
5641 + "default.handlebars->31->1154"
5642 ]
5643 },
5644 {
@@ -5649,7 +5659,7 @@
5659 "zh-cht": "結構",
5660 "xloc": [
5661 "default-mobile.handlebars->11->384",
5652 - "default.handlebars->31->1002"
5662 + "default.handlebars->31->1015"
5663 ]
5664 },
5665 {
@@ -5689,8 +5699,8 @@
5699 "zh-chs": "你确定要删除组{0}吗?删除设备组还将删除该组中有关设备的所有信息。",
5700 "zh-cht": "你確定要刪除群{0}嗎?刪除裝置群還將刪除該群中有關裝置的所有訊息。",
5701 "xloc": [
5692 - "default-mobile.handlebars->11->466",
5693 - "default.handlebars->31->1481"
5702 + "default-mobile.handlebars->11->483",
5703 + "default.handlebars->31->1494"
5704 ]
5705 },
5706 {
@@ -5710,7 +5720,7 @@
5720 "zh-chs": "您确定要删除节点{0}吗?",
5721 "zh-cht": "你確定要刪除節點{0}嗎?",
5722 "xloc": [
5713 - "default.handlebars->31->820"
5723 + "default.handlebars->31->833"
5724 ]
5725 },
5726 {
@@ -5730,7 +5740,7 @@
5740 "zh-chs": "您确定要卸载所选代理吗?",
5741 "zh-cht": "你確定要卸載所選代理嗎?",
5742 "xloc": [
5733 - "default.handlebars->31->809"
5743 + "default.handlebars->31->822"
5744 ]
5745 },
5746 {
@@ -5750,7 +5760,7 @@
5760 "zh-chs": "您确定要卸载所选的{0}代理吗?",
5761 "zh-cht": "你確定要卸載所選的{0}代理嗎?",
5762 "xloc": [
5753 - "default.handlebars->31->808"
5763 + "default.handlebars->31->821"
5764 ]
5765 },
5766 {
@@ -5770,7 +5780,7 @@
5780 "zh-chs": "您确定要{0}插件吗:{1}",
5781 "zh-cht": "你確定要{0}外掛嗎:{1}",
5782 "xloc": [
5773 - "default.handlebars->31->2253"
5783 + "default.handlebars->31->2266"
5784 ]
5785 },
5786 {
@@ -5790,7 +5800,7 @@
5800 "zh-chs": "亚美尼亚文",
5801 "zh-cht": "亞美尼亞文",
5802 "xloc": [
5793 - "default.handlebars->31->1142"
5803 + "default.handlebars->31->1155"
5804 ]
5805 },
5806 {
@@ -5850,7 +5860,7 @@
5860 "zh-chs": "阿萨姆文",
5861 "zh-cht": "阿薩姆文",
5862 "xloc": [
5853 - "default.handlebars->31->1143"
5863 + "default.handlebars->31->1156"
5864 ]
5865 },
5866 {
@@ -5870,7 +5880,7 @@
5880 "zh-chs": "阿斯图里亚斯文",
5881 "zh-cht": "阿斯圖里亞斯文",
5882 "xloc": [
5873 - "default.handlebars->31->1144"
5883 + "default.handlebars->31->1157"
5884 ]
5885 },
5886 {
@@ -5890,7 +5900,7 @@
5900 "zh-chs": "尝试激活英特尔(R)AMT ACM模式",
5901 "zh-cht": "嘗試激活英特爾(R)AMT ACM模式",
5902 "xloc": [
5893 - "default.handlebars->31->1683"
5903 + "default.handlebars->31->1696"
5904 ]
5905 },
5906 {
@@ -5910,7 +5920,7 @@
5920 "zh-chs": "认证软件",
5921 "zh-cht": "認證軟體",
5922 "xloc": [
5913 - "default.handlebars->31->2022"
5923 + "default.handlebars->31->2035"
5924 ]
5925 },
5926 {
@@ -5934,8 +5944,8 @@
5944 "default-mobile.handlebars->11->63",
5945 "default-mobile.handlebars->11->82",
5946 "default-mobile.handlebars->11->84",
5937 - "default.handlebars->31->1108",
5938 - "default.handlebars->31->1110",
5947 + "default.handlebars->31->1121",
5948 + "default.handlebars->31->1123",
5949 "default.handlebars->31->136",
5950 "default.handlebars->31->141"
5951 ]
@@ -6017,7 +6027,7 @@
6027 "zh-chs": "自动删除",
6028 "zh-cht": "自動刪除",
6029 "xloc": [
6020 - "default.handlebars->31->1404"
6030 + "default.handlebars->31->1417"
6031 ]
6032 },
6033 {
@@ -6061,7 +6071,7 @@
6071 "zh-chs": "自动下载代理程序核心转储文件:“{0}”",
6072 "zh-cht": "自動下載代理程序核心轉儲文件:“{0}”",
6073 "xloc": [
6064 - "default.handlebars->31->1764"
6074 + "default.handlebars->31->1777"
6075 ]
6076 },
6077 {
@@ -6101,7 +6111,7 @@
6111 "zh-chs": "可用內存",
6112 "zh-cht": "可用內存",
6113 "xloc": [
6104 - "default.handlebars->31->2200"
6114 + "default.handlebars->31->2213"
6115 ]
6116 },
6117 {
@@ -6121,7 +6131,18 @@
6131 "zh-chs": "阿塞拜疆文",
6132 "zh-cht": "阿塞拜疆文",
6133 "xloc": [
6124 - "default.handlebars->31->1145"
6134 + "default.handlebars->31->1158"
6135 + ]
6136 + },
6137 + {
6138 + "en": "BAD",
6139 + "xloc": [
6140 + "default-mobile.handlebars->11->388",
6141 + "default-mobile.handlebars->11->392",
6142 + "default-mobile.handlebars->11->396",
6143 + "default.handlebars->31->610",
6144 + "default.handlebars->31->614",
6145 + "default.handlebars->31->618"
6146 ]
6147 },
6148 {
@@ -6141,8 +6162,8 @@
6162 "zh-chs": "的BIOS",
6163 "zh-cht": "的BIOS",
6164 "xloc": [
6144 - "default-mobile.handlebars->11->432",
6145 - "default.handlebars->31->1060"
6165 + "default-mobile.handlebars->11->449",
6166 + "default.handlebars->31->1073"
6167 ]
6168 },
6169 {
@@ -6226,7 +6247,7 @@
6247 "nl": "BackSpace",
6248 "xloc": [
6249 "default-mobile.handlebars->11->317",
6229 - "default.handlebars->31->884"
6250 + "default.handlebars->31->897"
6251 ]
6252 },
6253 {
@@ -6266,8 +6287,8 @@
6287 "zh-chs": "背景与互动",
6288 "zh-cht": "背景與互動",
6289 "xloc": [
6269 - "default.handlebars->31->1587",
6270 - "default.handlebars->31->1594",
6290 + "default.handlebars->31->1600",
6291 + "default.handlebars->31->1607",
6292 "default.handlebars->31->353",
6293 "default.handlebars->31->367"
6294 ]
@@ -6289,8 +6310,8 @@
6310 "zh-chs": "仅背景",
6311 "zh-cht": "僅背景",
6312 "xloc": [
6292 - "default.handlebars->31->1588",
6293 - "default.handlebars->31->1595",
6313 + "default.handlebars->31->1601",
6314 + "default.handlebars->31->1608",
6315 "default.handlebars->31->354",
6316 "default.handlebars->31->368",
6317 "default.handlebars->31->383"
@@ -6334,7 +6355,7 @@
6355 "zh-chs": "备用码",
6356 "zh-cht": "備用碼",
6357 "xloc": [
6337 - "default.handlebars->31->2024"
6358 + "default.handlebars->31->2037"
6359 ]
6360 },
6361 {
@@ -6354,7 +6375,7 @@
6375 "zh-chs": "错误的签名",
6376 "zh-cht": "錯誤的簽名",
6377 "xloc": [
6357 - "default.handlebars->31->2182"
6378 + "default.handlebars->31->2195"
6379 ]
6380 },
6381 {
@@ -6374,7 +6395,7 @@
6395 "zh-chs": "错误的网络证书",
6396 "zh-cht": "錯誤的網絡憑證",
6397 "xloc": [
6377 - "default.handlebars->31->2181"
6398 + "default.handlebars->31->2194"
6399 ]
6400 },
6401 {
@@ -6394,7 +6415,7 @@
6415 "zh-chs": "巴斯克",
6416 "zh-cht": "巴斯克",
6417 "xloc": [
6397 - "default.handlebars->31->1146"
6418 + "default.handlebars->31->1159"
6419 ]
6420 },
6421 {
@@ -6454,7 +6475,7 @@
6475 "zh-chs": "将{0}个文件批量上传到文件夹{1}",
6476 "zh-cht": "將{0}個文件批量上傳到文件夾{1}",
6477 "xloc": [
6457 - "default.handlebars->31->1763"
6478 + "default.handlebars->31->1776"
6479 ]
6480 },
6481 {
@@ -6474,7 +6495,7 @@
6495 "zh-chs": "白俄罗斯文",
6496 "zh-cht": "白俄羅斯文",
6497 "xloc": [
6477 - "default.handlebars->31->1148"
6498 + "default.handlebars->31->1161"
6499 ]
6500 },
6501 {
@@ -6494,7 +6515,7 @@
6515 "zh-chs": "孟加拉",
6516 "zh-cht": "孟加拉",
6517 "xloc": [
6497 - "default.handlebars->31->1149"
6518 + "default.handlebars->31->1162"
6519 ]
6520 },
6521 {
@@ -6524,8 +6545,8 @@
6545 "en": "Bootloader",
6546 "nl": "Bootloader",
6547 "xloc": [
6527 - "default-mobile.handlebars->11->396",
6528 - "default.handlebars->31->1014"
6548 + "default-mobile.handlebars->11->413",
6549 + "default.handlebars->31->1027"
6550 ]
6551 },
6552 {
@@ -6545,7 +6566,7 @@
6566 "zh-chs": "波斯尼亚文",
6567 "zh-cht": "波斯尼亞文",
6568 "xloc": [
6548 - "default.handlebars->31->1150"
6569 + "default.handlebars->31->1163"
6570 ]
6571 },
6572 {
@@ -6565,7 +6586,7 @@
6586 "zh-chs": "布列塔尼",
6587 "zh-cht": "布列塔尼",
6588 "xloc": [
6568 - "default.handlebars->31->1151"
6589 + "default.handlebars->31->1164"
6590 ]
6591 },
6592 {
@@ -6585,7 +6606,7 @@
6606 "zh-chs": "广播",
6607 "zh-cht": "廣播",
6608 "xloc": [
6588 - "default.handlebars->31->1938",
6609 + "default.handlebars->31->1951",
6610 "default.handlebars->container->column_l->p4->3->1->0->3->1"
6611 ]
6612 },
@@ -6606,7 +6627,7 @@
6627 "zh-chs": "广播消息",
6628 "zh-cht": "廣播消息",
6629 "xloc": [
6609 - "default.handlebars->31->1859"
6630 + "default.handlebars->31->1872"
6631 ]
6632 },
6633 {
@@ -6626,7 +6647,7 @@
6647 "zh-chs": "向所有连接的用户广播消息。",
6648 "zh-cht": "向所有連接的用戶廣播消息。",
6649 "xloc": [
6629 - "default.handlebars->31->1854"
6650 + "default.handlebars->31->1867"
6651 ]
6652 },
6653 {
@@ -6646,7 +6667,7 @@
6667 "zh-chs": "保加利亚文",
6668 "zh-cht": "保加利亞文",
6669 "xloc": [
6649 - "default.handlebars->31->1147"
6670 + "default.handlebars->31->1160"
6671 ]
6672 },
6673 {
@@ -6666,7 +6687,7 @@
6687 "zh-chs": "缅甸文",
6688 "zh-cht": "緬甸文",
6689 "xloc": [
6669 - "default.handlebars->31->1152"
6690 + "default.handlebars->31->1165"
6691 ]
6692 },
6693 {
@@ -6707,7 +6728,7 @@
6728 "zh-chs": "CCM模式",
6729 "zh-cht": "CCM模式",
6730 "xloc": [
6710 - "default.handlebars->31->1464"
6731 + "default.handlebars->31->1477"
6732 ]
6733 },
6734 {
@@ -6749,7 +6770,7 @@
6770 "zh-chs": "CIRA服务器",
6771 "zh-cht": "CIRA伺服器",
6772 "xloc": [
6752 - "default.handlebars->31->2239"
6773 + "default.handlebars->31->2252"
6774 ]
6775 },
6776 {
@@ -6769,7 +6790,7 @@
6790 "zh-chs": "CIRA服务器命令",
6791 "zh-cht": "CIRA伺服器指令",
6792 "xloc": [
6772 - "default.handlebars->31->2240"
6793 + "default.handlebars->31->2253"
6794 ]
6795 },
6796 {
@@ -6789,7 +6810,7 @@
6810 "zh-chs": "CIRA设置",
6811 "zh-cht": "CIRA設置",
6812 "xloc": [
6792 - "default.handlebars->31->1472"
6813 + "default.handlebars->31->1485"
6814 ]
6815 },
6816 {
@@ -6809,8 +6830,8 @@
6830 "zh-chs": "CPU",
6831 "zh-cht": "CPU",
6832 "xloc": [
6812 - "default-mobile.handlebars->11->438",
6813 - "default.handlebars->31->1066"
6833 + "default-mobile.handlebars->11->455",
6834 + "default.handlebars->31->1079"
6835 ]
6836 },
6837 {
@@ -6830,7 +6851,7 @@
6851 "zh-chs": "CPU负载",
6852 "zh-cht": "CPU負載",
6853 "xloc": [
6833 - "default.handlebars->31->2196"
6854 + "default.handlebars->31->2209"
6855 ]
6856 },
6857 {
@@ -6850,7 +6871,7 @@
6871 "zh-chs": "最近15分钟的CPU负载",
6872 "zh-cht": "最近15分鐘的CPU負載",
6873 "xloc": [
6853 - "default.handlebars->31->2199"
6874 + "default.handlebars->31->2212"
6875 ]
6876 },
6877 {
@@ -6870,7 +6891,7 @@
6891 "zh-chs": "最近5分钟的CPU负载",
6892 "zh-cht": "最近5分鐘的CPU負載",
6893 "xloc": [
6873 - "default.handlebars->31->2198"
6894 + "default.handlebars->31->2211"
6895 ]
6896 },
6897 {
@@ -6890,7 +6911,7 @@
6911 "zh-chs": "最近一分钟的CPU负载",
6912 "zh-cht": "最近一分鐘的CPU負載",
6913 "xloc": [
6893 - "default.handlebars->31->2197"
6914 + "default.handlebars->31->2210"
6915 ]
6916 },
6917 {
@@ -6910,8 +6931,8 @@
6931 "zh-chs": "CR+LF",
6932 "zh-cht": "CR+LF",
6933 "xloc": [
6913 - "default.handlebars->31->934",
6914 - "default.handlebars->31->943",
6934 + "default.handlebars->31->947",
6935 + "default.handlebars->31->956",
6936 "default.handlebars->container->column_l->p12->termTable->1->1->6->1->1->terminalSettingsButtons",
6937 "terminal.handlebars->3->21",
6938 "terminal.handlebars->3->7",
@@ -6935,7 +6956,7 @@
6956 "zh-chs": "CSV",
6957 "zh-cht": "CSV",
6958 "xloc": [
6938 - "default.handlebars->31->1777"
6959 + "default.handlebars->31->1790"
6960 ]
6961 },
6962 {
@@ -6955,8 +6976,8 @@
6976 "zh-chs": "CSV格式",
6977 "zh-cht": "CSV格式",
6978 "xloc": [
6958 - "default.handlebars->31->1781",
6959 - "default.handlebars->31->1846",
6979 + "default.handlebars->31->1794",
6980 + "default.handlebars->31->1859",
6981 "default.handlebars->31->502"
6982 ]
6983 },
@@ -6994,7 +7015,7 @@
7015 "zh-chs": "呼叫错误",
7016 "zh-cht": "呼叫錯誤",
7017 "xloc": [
6997 - "default.handlebars->31->2254"
7018 + "default.handlebars->31->2267"
7019 ]
7020 },
7021 {
@@ -7017,7 +7038,7 @@
7038 "agent-translations.json",
7039 "default-mobile.handlebars->11->93",
7040 "default-mobile.handlebars->dialog->idx_dlgButtonBar",
7020 - "default.handlebars->31->1382",
7041 + "default.handlebars->31->1395",
7042 "default.handlebars->container->dialog->idx_dlgButtonBar",
7043 "desktop.handlebars->p11->dialog->idx_dlgButtonBar",
7044 "login-mobile.handlebars->dialog->idx_dlgButtonBar",
@@ -7045,12 +7066,12 @@
7066 "zh-chs": "容量",
7067 "zh-cht": "容量",
7068 "xloc": [
7048 - "default-mobile.handlebars->11->443",
7049 - "default-mobile.handlebars->11->448",
7050 - "default-mobile.handlebars->11->450",
7051 - "default.handlebars->31->1071",
7052 - "default.handlebars->31->1076",
7053 - "default.handlebars->31->1078"
7069 + "default-mobile.handlebars->11->460",
7070 + "default-mobile.handlebars->11->465",
7071 + "default-mobile.handlebars->11->467",
7072 + "default.handlebars->31->1084",
7073 + "default.handlebars->31->1089",
7074 + "default.handlebars->31->1091"
7075 ]
7076 },
7077 {
@@ -7070,8 +7091,8 @@
7091 "zh-chs": "容量/速度",
7092 "zh-cht": "容量/速度",
7093 "xloc": [
7073 - "default-mobile.handlebars->11->441",
7074 - "default.handlebars->31->1069"
7094 + "default-mobile.handlebars->11->458",
7095 + "default.handlebars->31->1082"
7096 ]
7097 },
7098 {
@@ -7091,7 +7112,7 @@
7112 "zh-chs": "加泰罗尼亚文",
7113 "zh-cht": "加泰羅尼亞文",
7114 "xloc": [
7094 - "default.handlebars->31->1153"
7115 + "default.handlebars->31->1166"
7116 ]
7117 },
7118 {
@@ -7131,7 +7152,7 @@
7152 "zh-chs": "查莫罗",
7153 "zh-cht": "查莫羅",
7154 "xloc": [
7134 - "default.handlebars->31->1154"
7155 + "default.handlebars->31->1167"
7156 ]
7157 },
7158 {
@@ -7173,7 +7194,7 @@
7194 "zh-chs": "更改{0}的电邮",
7195 "zh-cht": "更改{0}的電郵",
7196 "xloc": [
7176 - "default.handlebars->31->2054"
7197 + "default.handlebars->31->2067"
7198 ]
7199 },
7200 {
@@ -7193,9 +7214,9 @@
7214 "zh-chs": "更改组",
7215 "zh-cht": "更改群",
7216 "xloc": [
7196 - "default.handlebars->31->648",
7197 - "default.handlebars->31->817",
7198 - "default.handlebars->31->818"
7217 + "default.handlebars->31->661",
7218 + "default.handlebars->31->830",
7219 + "default.handlebars->31->831"
7220 ]
7221 },
7222 {
@@ -7216,8 +7237,8 @@
7237 "zh-cht": "更改密碼",
7238 "xloc": [
7239 "default-mobile.handlebars->11->101",
7219 - "default.handlebars->31->1349",
7220 - "default.handlebars->31->2041"
7240 + "default.handlebars->31->1362",
7241 + "default.handlebars->31->2054"
7242 ]
7243 },
7244 {
@@ -7237,7 +7258,7 @@
7258 "zh-chs": "更改{0}的密码",
7259 "zh-cht": "更改{0}的密碼",
7260 "xloc": [
7240 - "default.handlebars->31->2061"
7261 + "default.handlebars->31->2074"
7262 ]
7263 },
7264 {
@@ -7257,7 +7278,7 @@
7278 "zh-chs": "更改{0}的真实名称",
7279 "zh-cht": "更改{0}的真實名稱",
7280 "xloc": [
7260 - "default.handlebars->31->2049"
7281 + "default.handlebars->31->2062"
7282 ]
7283 },
7284 {
@@ -7339,7 +7360,7 @@
7360 "zh-chs": "更改该用户的密码",
7361 "zh-cht": "更改該用戶的密碼",
7362 "xloc": [
7342 - "default.handlebars->31->2040"
7363 + "default.handlebars->31->2053"
7364 ]
7365 },
7366 {
@@ -7379,7 +7400,7 @@
7400 "zh-chs": "在此处更改您的帐户电邮地址。",
7401 "zh-cht": "在此處更改你的帳戶電郵地址。",
7402 "xloc": [
7382 - "default.handlebars->31->1336"
7403 + "default.handlebars->31->1349"
7404 ]
7405 },
7406 {
@@ -7399,7 +7420,7 @@
7420 "zh-chs": "在下面的框中两次输入旧密码和新密码,以更改帐户密码。",
7421 "zh-cht": "在下面的框中兩次輸入舊密碼和新密碼,以更改帳戶密碼。",
7422 "xloc": [
7402 - "default.handlebars->31->1342"
7423 + "default.handlebars->31->1355"
7424 ]
7425 },
7426 {
@@ -7419,7 +7440,7 @@
7440 "zh-chs": "更改帐户凭据",
7441 "zh-cht": "帳戶憑證已更改",
7442 "xloc": [
7422 - "default.handlebars->31->1735"
7443 + "default.handlebars->31->1748"
7444 ]
7445 },
7446 {
@@ -7439,7 +7460,7 @@
7460 "zh-chs": "{1}组中的设备{0}已更改:{2}",
7461 "zh-cht": "{1}組中的設備{0}已更改:{2}",
7462 "xloc": [
7442 - "default.handlebars->31->1719"
7463 + "default.handlebars->31->1732"
7464 ]
7465 },
7466 {
@@ -7459,7 +7480,7 @@
7480 "zh-chs": "语言从{1}更改为{2}",
7481 "zh-cht": "語言從{1}更改為{2}",
7482 "xloc": [
7462 - "default.handlebars->31->1663"
7483 + "default.handlebars->31->1676"
7484 ]
7485 },
7486 {
@@ -7479,8 +7500,8 @@
7500 "zh-chs": "已更改{0}的用户设备权限",
7501 "zh-cht": "已更改{0}的用戶設備權限",
7502 "xloc": [
7482 - "default.handlebars->31->1721",
7483 - "default.handlebars->31->1742"
7503 + "default.handlebars->31->1734",
7504 + "default.handlebars->31->1755"
7505 ]
7506 },
7507 {
@@ -7500,7 +7521,7 @@
7521 "zh-chs": "更改语言将需要刷新页面。",
7522 "zh-cht": "更改語言將需要刷新頁面。",
7523 "xloc": [
7503 - "default.handlebars->31->1321"
7524 + "default.handlebars->31->1334"
7525 ]
7526 },
7527 {
@@ -7520,11 +7541,11 @@
7541 "zh-chs": "聊天",
7542 "zh-cht": "聊天",
7543 "xloc": [
7523 - "default.handlebars->31->1798",
7524 - "default.handlebars->31->2036",
7525 - "default.handlebars->31->2037",
7526 - "default.handlebars->31->713",
7527 - "default.handlebars->31->734"
7544 + "default.handlebars->31->1811",
7545 + "default.handlebars->31->2049",
7546 + "default.handlebars->31->2050",
7547 + "default.handlebars->31->726",
7548 + "default.handlebars->31->747"
7549 ]
7550 },
7551 {
@@ -7544,10 +7565,10 @@
7565 "zh-chs": "聊天并通知",
7566 "zh-cht": "聊天並通知",
7567 "xloc": [
7547 - "default-mobile.handlebars->11->487",
7548 - "default-mobile.handlebars->11->507",
7549 - "default.handlebars->31->1533",
7550 - "default.handlebars->31->1569"
7568 + "default-mobile.handlebars->11->504",
7569 + "default-mobile.handlebars->11->524",
7570 + "default.handlebars->31->1546",
7571 + "default.handlebars->31->1582"
7572 ]
7573 },
7574 {
@@ -7555,8 +7576,8 @@
7576 "nl": "Chatverzoek, klik hier om te accepteren.",
7577 "fr": "Demande de chat, cliquez ici pour accepter.",
7578 "xloc": [
7558 - "default-mobile.handlebars->11->539",
7559 - "default.handlebars->31->2151"
7579 + "default-mobile.handlebars->11->556",
7580 + "default.handlebars->31->2164"
7581 ]
7582 },
7583 {
@@ -7596,7 +7617,7 @@
7617 "zh-chs": "车臣",
7618 "zh-cht": "車臣",
7619 "xloc": [
7599 - "default.handlebars->31->1155"
7620 + "default.handlebars->31->1168"
7621 ]
7622 },
7623 {
@@ -7696,8 +7717,8 @@
7717 "zh-chs": "检查...",
7718 "zh-cht": "檢查...",
7719 "xloc": [
7699 - "default.handlebars->31->1121",
7700 - "default.handlebars->31->2248"
7720 + "default.handlebars->31->1134",
7721 + "default.handlebars->31->2261"
7722 ]
7723 },
7724 {
@@ -7717,7 +7738,7 @@
7738 "zh-chs": "中文",
7739 "zh-cht": "中文",
7740 "xloc": [
7720 - "default.handlebars->31->1156"
7741 + "default.handlebars->31->1169"
7742 ]
7743 },
7744 {
@@ -7737,7 +7758,7 @@
7758 "zh-chs": "中文(香港)",
7759 "zh-cht": "中文(香港)",
7760 "xloc": [
7740 - "default.handlebars->31->1157"
7761 + "default.handlebars->31->1170"
7762 ]
7763 },
7764 {
@@ -7757,7 +7778,7 @@
7778 "zh-chs": "中文(中国)",
7779 "zh-cht": "中文(中國)",
7780 "xloc": [
7760 - "default.handlebars->31->1158"
7781 + "default.handlebars->31->1171"
7782 ]
7783 },
7784 {
@@ -7777,7 +7798,7 @@
7798 "zh-chs": "简体中文",
7799 "zh-cht": "簡體中文",
7800 "xloc": [
7780 - "default.handlebars->31->1318"
7801 + "default.handlebars->31->1331"
7802 ]
7803 },
7804 {
@@ -7797,7 +7818,7 @@
7818 "zh-chs": "中文(新加坡)",
7819 "zh-cht": "中文(新加坡)",
7820 "xloc": [
7800 - "default.handlebars->31->1159"
7821 + "default.handlebars->31->1172"
7822 ]
7823 },
7824 {
@@ -7817,7 +7838,7 @@
7838 "zh-chs": "中文(台湾)",
7839 "zh-cht": "中文(台灣)",
7840 "xloc": [
7820 - "default.handlebars->31->1160"
7841 + "default.handlebars->31->1173"
7842 ]
7843 },
7844 {
@@ -7837,7 +7858,7 @@
7858 "zh-chs": "繁体中文",
7859 "zh-cht": "繁體中文",
7860 "xloc": [
7840 - "default.handlebars->31->1319"
7861 + "default.handlebars->31->1332"
7862 ]
7863 },
7864 {
@@ -7878,7 +7899,7 @@
7899 "zh-chs": "楚瓦什",
7900 "zh-cht": "楚瓦什",
7901 "xloc": [
7881 - "default.handlebars->31->1161"
7902 + "default.handlebars->31->1174"
7903 ]
7904 },
7905 {
@@ -7921,11 +7942,11 @@
7942 "default-mobile.handlebars->11->372",
7943 "default-mobile.handlebars->11->374",
7944 "default-mobile.handlebars->11->70",
7924 - "default.handlebars->31->1657",
7925 - "default.handlebars->31->979",
7926 - "default.handlebars->31->981",
7927 - "default.handlebars->31->983",
7928 - "default.handlebars->31->985",
7945 + "default.handlebars->31->1670",
7946 + "default.handlebars->31->992",
7947 + "default.handlebars->31->994",
7948 + "default.handlebars->31->996",
7949 + "default.handlebars->31->998",
7950 "default.handlebars->container->column_l->p15->consoleTable->1->6->1->1->1->0->7",
7951 "default.handlebars->container->column_l->p41->3->1",
7952 "messenger.handlebars->xbottom->1->1->0->5"
@@ -7968,8 +7989,8 @@
7989 "zh-chs": "全部清除",
7990 "zh-cht": "全部清除",
7991 "xloc": [
7971 - "default-mobile.handlebars->11->522",
7972 - "default.handlebars->31->2134"
7992 + "default-mobile.handlebars->11->539",
7993 + "default.handlebars->31->2147"
7994 ]
7995 },
7996 {
@@ -8010,7 +8031,7 @@
8031 "zh-chs": "清除核心",
8032 "zh-cht": "清除核心",
8033 "xloc": [
8013 - "default.handlebars->31->1092"
8034 + "default.handlebars->31->1105"
8035 ]
8036 },
8037 {
@@ -8050,8 +8071,8 @@
8071 "zh-chs": "清除此通知",
8072 "zh-cht": "清除此通知",
8073 "xloc": [
8053 - "default-mobile.handlebars->11->521",
8054 - "default.handlebars->31->2133"
8074 + "default-mobile.handlebars->11->538",
8075 + "default.handlebars->31->2146"
8076 ]
8077 },
8078 {
@@ -8111,8 +8132,8 @@
8132 "zh-chs": "单击此处编辑设备组名称",
8133 "zh-cht": "單擊此處編輯裝置群名稱",
8134 "xloc": [
8114 - "default.handlebars->31->1393",
8115 - "default.handlebars->31->1608"
8135 + "default.handlebars->31->1406",
8136 + "default.handlebars->31->1621"
8137 ]
8138 },
8139 {
@@ -8152,7 +8173,7 @@
8173 "zh-chs": "单击此处编辑用户组名称",
8174 "zh-cht": "單擊此處編輯用戶群名稱",
8175 "xloc": [
8155 - "default.handlebars->31->1915"
8176 + "default.handlebars->31->1928"
8177 ]
8178 },
8179 {
@@ -8223,7 +8244,7 @@
8244 "zh-cht": "單擊確定將驗證電郵發送到:",
8245 "xloc": [
8246 "default-mobile.handlebars->11->86",
8226 - "default.handlebars->31->1333"
8247 + "default.handlebars->31->1346"
8248 ]
8249 },
8250 {
@@ -8284,8 +8305,8 @@
8305 "zh-chs": "客户端控制模式(CCM)",
8306 "zh-cht": "客戶端控制模式(CCM)",
8307 "xloc": [
8287 - "default-mobile.handlebars->11->419",
8288 - "default.handlebars->31->1047"
8308 + "default-mobile.handlebars->11->436",
8309 + "default.handlebars->31->1060"
8310 ]
8311 },
8312 {
@@ -8305,7 +8326,7 @@
8326 "zh-chs": "客户编号",
8327 "zh-cht": "客戶編號",
8328 "xloc": [
8308 - "default.handlebars->31->1375"
8329 + "default.handlebars->31->1388"
8330 ]
8331 },
8332 {
@@ -8325,7 +8346,7 @@
8346 "zh-chs": "客户端启动的远程访问",
8347 "zh-cht": "客戶端啟動的遠程訪問",
8348 "xloc": [
8328 - "default.handlebars->31->1471"
8349 + "default.handlebars->31->1484"
8350 ]
8351 },
8352 {
@@ -8345,7 +8366,7 @@
8366 "zh-chs": "客户机密",
8367 "zh-cht": "客戶機密",
8368 "xloc": [
8348 - "default.handlebars->31->1376"
8369 + "default.handlebars->31->1389"
8370 ]
8371 },
8372 {
@@ -8389,8 +8410,8 @@
8410 "default-mobile.handlebars->11->68",
8411 "default.handlebars->31->148",
8412 "default.handlebars->31->156",
8392 - "default.handlebars->31->925",
8393 - "default.handlebars->31->956"
8413 + "default.handlebars->31->938",
8414 + "default.handlebars->31->969"
8415 ]
8416 },
8417 {
@@ -8410,7 +8431,7 @@
8431 "zh-chs": "封闭式桌面多路复用会话,{0}秒",
8432 "zh-cht": "封閉式桌面多路復用會話,{0}秒",
8433 "xloc": [
8413 - "default.handlebars->31->1668"
8434 + "default.handlebars->31->1681"
8435 ]
8436 },
8437 {
@@ -8532,10 +8553,10 @@
8553 "zh-chs": "指令",
8554 "zh-cht": "指令",
8555 "xloc": [
8535 - "default-mobile.handlebars->11->509",
8536 - "default.handlebars->31->1571",
8537 - "default.handlebars->31->715",
8538 - "default.handlebars->31->736"
8556 + "default-mobile.handlebars->11->526",
8557 + "default.handlebars->31->1584",
8558 + "default.handlebars->31->728",
8559 + "default.handlebars->31->749"
8560 ]
8561 },
8562 {
@@ -8555,8 +8576,8 @@
8576 "zh-chs": "通用设备组",
8577 "zh-cht": "通用裝置群",
8578 "xloc": [
8558 - "default.handlebars->31->1946",
8559 - "default.handlebars->31->2066"
8579 + "default.handlebars->31->1959",
8580 + "default.handlebars->31->2079"
8581 ]
8582 },
8583 {
@@ -8576,8 +8597,8 @@
8597 "zh-chs": "通用设备",
8598 "zh-cht": "通用裝置",
8599 "xloc": [
8579 - "default.handlebars->31->1952",
8580 - "default.handlebars->31->2078"
8600 + "default.handlebars->31->1965",
8601 + "default.handlebars->31->2091"
8602 ]
8603 },
8604 {
@@ -8597,7 +8618,7 @@
8618 "zh-chs": "压缩档案...",
8619 "zh-cht": "壓縮檔案...",
8620 "xloc": [
8600 - "default.handlebars->31->951"
8621 + "default.handlebars->31->964"
8622 ]
8623 },
8624 {
@@ -8618,15 +8639,15 @@
8639 "zh-cht": "確認",
8640 "xloc": [
8641 "default-mobile.handlebars->11->301",
8621 - "default-mobile.handlebars->11->467",
8622 - "default.handlebars->31->1482",
8623 - "default.handlebars->31->1826",
8624 - "default.handlebars->31->1905",
8625 - "default.handlebars->31->1966",
8626 - "default.handlebars->31->2064",
8642 + "default-mobile.handlebars->11->484",
8643 + "default.handlebars->31->1495",
8644 + "default.handlebars->31->1839",
8645 + "default.handlebars->31->1918",
8646 + "default.handlebars->31->1979",
8647 + "default.handlebars->31->2077",
8648 "default.handlebars->31->472",
8628 - "default.handlebars->31->812",
8629 - "default.handlebars->31->821"
8649 + "default.handlebars->31->825",
8650 + "default.handlebars->31->834"
8651 ]
8652 },
8653 {
@@ -8647,7 +8668,7 @@
8668 "zh-cht": "確認將1個副本複製到此位置?",
8669 "xloc": [
8670 "default-mobile.handlebars->11->363",
8650 - "default.handlebars->31->974"
8671 + "default.handlebars->31->987"
8672 ]
8673 },
8674 {
@@ -8667,7 +8688,7 @@
8688 "zh-chs": "确认{0}个条目的复制到此位置?",
8689 "zh-cht": "確認{0}個條目的複製到此位置?",
8690 "xloc": [
8670 - "default.handlebars->31->973"
8691 + "default.handlebars->31->986"
8692 ]
8693 },
8694 {
@@ -8707,7 +8728,7 @@
8728 "zh-chs": "确认删除选定的帐户?",
8729 "zh-cht": "確認刪除所選帳戶?",
8730 "xloc": [
8710 - "default.handlebars->31->1825"
8731 + "default.handlebars->31->1838"
8732 ]
8733 },
8734 {
@@ -8747,7 +8768,7 @@
8768 "zh-chs": "确认删除选定的用户组?",
8769 "zh-cht": "確認刪除所選用戶群?",
8770 "xloc": [
8750 - "default.handlebars->31->1904"
8771 + "default.handlebars->31->1917"
8772 ]
8773 },
8774 {
@@ -8767,7 +8788,7 @@
8788 "zh-chs": "确认删除用户{0}?",
8789 "zh-cht": "確認刪除用戶{0}?",
8790 "xloc": [
8770 - "default.handlebars->31->2063"
8791 + "default.handlebars->31->2076"
8792 ]
8793 },
8794 {
@@ -8787,7 +8808,7 @@
8808 "zh-chs": "确认删除用户“ {0} ”的成员身份?",
8809 "zh-cht": "確認刪除用戶“ {0} ”的成員身份?",
8810 "xloc": [
8790 - "default.handlebars->31->1969"
8811 + "default.handlebars->31->1982"
8812 ]
8813 },
8814 {
@@ -8807,7 +8828,7 @@
8828 "zh-chs": "确认删除用户组“ {0} ”的成员身份?",
8829 "zh-cht": "確認刪除用戶群“ {0} ”的成員身份?",
8830 "xloc": [
8810 - "default.handlebars->31->2095"
8831 + "default.handlebars->31->2108"
8832 ]
8833 },
8834 {
@@ -8828,7 +8849,7 @@
8849 "zh-cht": "確認將1個條目移動到此位置?",
8850 "xloc": [
8851 "default-mobile.handlebars->11->365",
8831 - "default.handlebars->31->976"
8852 + "default.handlebars->31->989"
8853 ]
8854 },
8855 {
@@ -8848,7 +8869,7 @@
8869 "zh-chs": "确认将{0}个条目移到此位置?",
8870 "zh-cht": "確認將{0}個條目移到該位置?",
8871 "xloc": [
8851 - "default.handlebars->31->975"
8872 + "default.handlebars->31->988"
8873 ]
8874 },
8875 {
@@ -8888,7 +8909,7 @@
8909 "zh-chs": "确认覆盖?",
8910 "zh-cht": "確認覆蓋?",
8911 "xloc": [
8891 - "default.handlebars->31->1651"
8912 + "default.handlebars->31->1664"
8913 ]
8914 },
8915 {
@@ -8908,8 +8929,8 @@
8929 "zh-chs": "确认删除设备“ {0} ”的访问权限?",
8930 "zh-cht": "確認刪除裝置“ {0} ”的訪問權限?",
8931 "xloc": [
8911 - "default.handlebars->31->1959",
8912 - "default.handlebars->31->2086"
8932 + "default.handlebars->31->1972",
8933 + "default.handlebars->31->2099"
8934 ]
8935 },
8936 {
@@ -8929,8 +8950,8 @@
8950 "zh-chs": "确认删除设备组“ {0} ”的访问权限?",
8951 "zh-cht": "確認刪除裝置群“ {0} ”的訪問權限?",
8952 "xloc": [
8932 - "default.handlebars->31->1961",
8933 - "default.handlebars->31->2099"
8953 + "default.handlebars->31->1974",
8954 + "default.handlebars->31->2112"
8955 ]
8956 },
8957 {
@@ -8950,7 +8971,7 @@
8971 "zh-chs": "确认删除用户“ {0} ”的访问权限?",
8972 "zh-cht": "確認刪除用戶“ {0} ”的訪問權限?",
8973 "xloc": [
8953 - "default.handlebars->31->2088"
8974 + "default.handlebars->31->2101"
8975 ]
8976 },
8977 {
@@ -8970,7 +8991,7 @@
8991 "zh-chs": "确认删除用户组“ {0} ”的访问权限?",
8992 "zh-cht": "確認刪除用戶群“ {0} ”的訪問權限?",
8993 "xloc": [
8973 - "default.handlebars->31->2091"
8994 + "default.handlebars->31->2104"
8995 ]
8996 },
8997 {
@@ -8990,8 +9011,8 @@
9011 "zh-chs": "确认删除访问权限?",
9012 "zh-cht": "確認刪除訪問權限?",
9013 "xloc": [
8993 - "default.handlebars->31->2089",
8994 - "default.handlebars->31->2092"
9014 + "default.handlebars->31->2102",
9015 + "default.handlebars->31->2105"
9016 ]
9017 },
9018 {
@@ -9012,7 +9033,7 @@
9033 "zh-cht": "確認刪除身份驗證軟體兩步登入?",
9034 "xloc": [
9035 "default-mobile.handlebars->11->85",
9015 - "default.handlebars->31->1111"
9036 + "default.handlebars->31->1124"
9037 ]
9038 },
9039 {
@@ -9049,7 +9070,7 @@
9070 "zh-chs": "确认删除设备共享“{0}”?",
9071 "zh-cht": "確認刪除設備共享“{0}”?",
9072 "xloc": [
9052 - "default.handlebars->31->2084"
9073 + "default.handlebars->31->2097"
9074 ]
9075 },
9076 {
@@ -9103,7 +9124,7 @@
9124 "zh-chs": "确认删除用户“ {0} ”的权限?",
9125 "zh-cht": "確認刪除用戶“ {0} ”的權限?",
9126 "xloc": [
9106 - "default.handlebars->31->1580"
9127 + "default.handlebars->31->1593"
9128 ]
9129 },
9130 {
@@ -9123,7 +9144,7 @@
9144 "zh-chs": "确认删除用户组“ {0} ”的权限?",
9145 "zh-cht": "確認刪除用戶群“ {0} ”的權限?",
9146 "xloc": [
9126 - "default.handlebars->31->1582"
9147 + "default.handlebars->31->1595"
9148 ]
9149 },
9150 {
@@ -9160,7 +9181,7 @@
9181 "zh-chs": "确认删除用户{0}?",
9182 "zh-cht": "確認刪除用戶{0}?",
9183 "xloc": [
9163 - "default-mobile.handlebars->11->518"
9184 + "default-mobile.handlebars->11->535"
9185 ]
9186 },
9187 {
@@ -9181,7 +9202,7 @@
9202 "zh-cht": "將{1}入口{2}中的{0}限製到此位置?",
9203 "xloc": [
9204 "default-mobile.handlebars->11->138",
9184 - "default.handlebars->31->1652"
9205 + "default.handlebars->31->1665"
9206 ]
9207 },
9208 {
@@ -9205,8 +9226,8 @@
9226 "default-mobile.handlebars->11->345",
9227 "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea1->1->3",
9228 "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->0->1->3",
9208 - "default.handlebars->31->1421",
9209 - "default.handlebars->31->946",
9229 + "default.handlebars->31->1434",
9230 + "default.handlebars->31->959",
9231 "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3->connectbutton1span",
9232 "default.handlebars->container->column_l->p12->termTable->1->1->0->1->3->connectbutton2span",
9233 "default.handlebars->container->column_l->p13->p13toolbar->1->0->1->3",
@@ -9254,7 +9275,7 @@
9275 "zh-chs": "连接到服务器",
9276 "zh-cht": "連接到伺服器",
9277 "xloc": [
9257 - "default.handlebars->31->1475"
9278 + "default.handlebars->31->1488"
9279 ]
9280 },
9281 {
@@ -9376,7 +9397,7 @@
9397 "zh-chs": "已连接的英特尔&reg;AMT",
9398 "zh-cht": "已連接的Intel&reg; AMT",
9399 "xloc": [
9379 - "default.handlebars->31->2187"
9400 + "default.handlebars->31->2200"
9401 ]
9402 },
9403 {
@@ -9396,7 +9417,7 @@
9417 "zh-chs": "已连接的用户",
9418 "zh-cht": "已连接的用户",
9419 "xloc": [
9399 - "default.handlebars->31->2192"
9420 + "default.handlebars->31->2205"
9421 ]
9422 },
9423 {
@@ -9416,8 +9437,8 @@
9437 "zh-chs": "现在已连接",
9438 "zh-cht": "現在已連接",
9439 "xloc": [
9419 - "default-mobile.handlebars->11->388",
9420 - "default.handlebars->31->1006"
9440 + "default-mobile.handlebars->11->405",
9441 + "default.handlebars->31->1019"
9442 ]
9443 },
9444 {
@@ -9460,11 +9481,11 @@
9481 "default-mobile.handlebars->11->2",
9482 "default-mobile.handlebars->11->381",
9483 "default-mobile.handlebars->11->48",
9484 + "default.handlebars->31->1010",
9485 "default.handlebars->31->244",
9486 "default.handlebars->31->247",
9487 "default.handlebars->31->291",
9488 "default.handlebars->31->9",
9467 - "default.handlebars->31->997",
9489 "desktop.handlebars->3->2",
9490 "terminal.handlebars->3->2",
9491 "xterm.handlebars->9->2"
@@ -9487,7 +9508,7 @@
9508 "zh-chs": "连接数量",
9509 "zh-cht": "連接數量",
9510 "xloc": [
9490 - "default.handlebars->31->2206"
9511 + "default.handlebars->31->2219"
9512 ]
9513 },
9514 {
@@ -9507,7 +9528,7 @@
9528 "zh-chs": "连接转发器",
9529 "zh-cht": "連接轉發器",
9530 "xloc": [
9510 - "default.handlebars->31->2238"
9531 + "default.handlebars->31->2251"
9532 ]
9533 },
9534 {
@@ -9568,9 +9589,9 @@
9589 "zh-cht": "連接性",
9590 "xloc": [
9591 "default-mobile.handlebars->11->266",
9571 - "default.handlebars->31->1615",
9592 + "default.handlebars->31->1628",
9593 "default.handlebars->31->235",
9573 - "default.handlebars->31->633",
9594 + "default.handlebars->31->646",
9595 "default.handlebars->container->column_l->p21->3->1->meshConnChartDiv->1"
9596 ]
9597 },
@@ -9591,8 +9612,8 @@
9612 "zh-chs": "控制台",
9613 "zh-cht": "控制台",
9614 "xloc": [
9594 - "default.handlebars->31->708",
9595 - "default.handlebars->31->729",
9615 + "default.handlebars->31->721",
9616 + "default.handlebars->31->742",
9617 "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevConsole",
9618 "default.handlebars->container->topbar->1->1->ServerSubMenuSpan->ServerSubMenu->1->0->ServerConsole",
9619 "default.handlebars->contextMenu->cxconsole"
@@ -9635,8 +9656,8 @@
9656 "zh-chs": "控制",
9657 "zh-cht": "控制",
9658 "xloc": [
9638 - "default.handlebars->31->707",
9639 - "default.handlebars->31->728",
9659 + "default.handlebars->31->720",
9660 + "default.handlebars->31->741",
9661 "messenger.handlebars->13->1"
9662 ]
9663 },
@@ -9657,7 +9678,7 @@
9678 "zh-chs": "Cookie编码器",
9679 "zh-cht": "Cookie編碼器",
9680 "xloc": [
9660 - "default.handlebars->31->2222"
9681 + "default.handlebars->31->2235"
9682 ]
9683 },
9684 {
@@ -9814,8 +9835,8 @@
9835 "zh-chs": "复制连结到剪贴板",
9836 "zh-cht": "複製連結到剪貼板",
9837 "xloc": [
9817 - "default.handlebars->31->1620",
9818 - "default.handlebars->31->1639",
9838 + "default.handlebars->31->1633",
9839 + "default.handlebars->31->1652",
9840 "default.handlebars->31->211",
9841 "default.handlebars->31->370"
9842 ]
@@ -9918,7 +9939,7 @@
9939 "zh-chs": "复制:“{0}”到“{1}”",
9940 "zh-cht": "複製:“{0}”到“{1}”",
9941 "xloc": [
9921 - "default.handlebars->31->1711"
9942 + "default.handlebars->31->1724"
9943 ]
9944 },
9945 {
@@ -10064,7 +10085,7 @@
10085 "zh-chs": "核心服务器",
10086 "zh-cht": "核心伺服器",
10087 "xloc": [
10067 - "default.handlebars->31->2221"
10088 + "default.handlebars->31->2234"
10089 ]
10090 },
10091 {
@@ -10084,7 +10105,7 @@
10105 "zh-chs": "科西嘉文",
10106 "zh-cht": "科西嘉文",
10107 "xloc": [
10087 - "default.handlebars->31->1162"
10108 + "default.handlebars->31->1175"
10109 ]
10110 },
10111 {
@@ -10104,7 +10125,7 @@
10125 "zh-chs": "创建帐号",
10126 "zh-cht": "創建帳號",
10127 "xloc": [
10107 - "default.handlebars->31->1873",
10128 + "default.handlebars->31->1886",
10129 "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->createpanel->1->1->9->1->12->1->1",
10130 "login.handlebars->container->column_l->centralTable->1->0->logincell->createpanel->1->9->1->12->1->1",
10131 "login2.handlebars->centralTable->1->0->logincell->createpanel->1->9->1->12->1->1"
@@ -10147,7 +10168,7 @@
10168 "zh-chs": "创建用户组",
10169 "zh-cht": "創建用戶群",
10170 "xloc": [
10150 - "default.handlebars->31->1912"
10171 + "default.handlebars->31->1925"
10172 ]
10173 },
10174 {
@@ -10167,7 +10188,7 @@
10188 "zh-chs": "创建连结以与访客共享此设备",
10189 "zh-cht": "創建鏈結以與訪客共享此裝置",
10190 "xloc": [
10170 - "default.handlebars->31->646"
10191 + "default.handlebars->31->659"
10192 ]
10193 },
10194 {
@@ -10187,7 +10208,7 @@
10208 "zh-chs": "使用以下选项创建一个新的设备组。",
10209 "zh-cht": "使用以下選項創建一個新的裝置群。",
10210 "xloc": [
10190 - "default.handlebars->31->1356"
10211 + "default.handlebars->31->1369"
10212 ]
10213 },
10214 {
@@ -10247,7 +10268,7 @@
10268 "zh-chs": "创建文件夹:“{0}”",
10269 "zh-cht": "創建文件夾:“{0}”",
10270 "xloc": [
10250 - "default.handlebars->31->1704"
10271 + "default.handlebars->31->1717"
10272 ]
10273 },
10274 {
@@ -10267,7 +10288,7 @@
10288 "zh-chs": "通过导入以下格式的JSON档案一次创建多个帐户:",
10289 "zh-cht": "通過導入以下格式的JSON檔案一次創建多個帳戶:",
10290 "xloc": [
10270 - "default.handlebars->31->1837"
10291 + "default.handlebars->31->1850"
10292 ]
10293 },
10294 {
@@ -10309,7 +10330,7 @@
10330 "zh-chs": "创建的设备组:{0}",
10331 "zh-cht": "創建的設備組:{0}",
10332 "xloc": [
10312 - "default.handlebars->31->1715"
10333 + "default.handlebars->31->1728"
10334 ]
10335 },
10336 {
@@ -10329,7 +10350,7 @@
10350 "zh-chs": "创建一个链接,该链接允许没有帐户的访客在有限的时间内远程控制此设备。",
10351 "zh-cht": "創建一個鏈接,該鏈接允許沒有帳戶的訪客在有限的時間內遠程控制此設備。",
10352 "xloc": [
10332 - "default.handlebars->31->747"
10353 + "default.handlebars->31->760"
10354 ]
10355 },
10356 {
@@ -10383,7 +10404,7 @@
10404 "zh-chs": "创建",
10405 "zh-cht": "創建",
10406 "xloc": [
10386 - "default.handlebars->31->1998"
10407 + "default.handlebars->31->2011"
10408 ]
10409 },
10410 {
@@ -10403,7 +10424,7 @@
10424 "zh-chs": "创建时间",
10425 "zh-cht": "創作時間",
10426 "xloc": [
10406 - "default.handlebars->31->1403"
10427 + "default.handlebars->31->1416"
10428 ]
10429 },
10430 {
@@ -10445,8 +10466,8 @@
10466 "zh-chs": "创建者",
10467 "zh-cht": "創作者",
10468 "xloc": [
10448 - "default.handlebars->31->1401",
10449 - "default.handlebars->31->1402"
10469 + "default.handlebars->31->1414",
10470 + "default.handlebars->31->1415"
10471 ]
10472 },
10473 {
@@ -10466,7 +10487,7 @@
10487 "zh-chs": "证书",
10488 "zh-cht": "證書",
10489 "xloc": [
10469 - "default.handlebars->31->1373"
10490 + "default.handlebars->31->1386"
10491 ]
10492 },
10493 {
@@ -10486,7 +10507,7 @@
10507 "zh-chs": "克里语",
10508 "zh-cht": "克里語",
10509 "xloc": [
10489 - "default.handlebars->31->1163"
10510 + "default.handlebars->31->1176"
10511 ]
10512 },
10513 {
@@ -10506,7 +10527,7 @@
10527 "zh-chs": "克罗地亚文",
10528 "zh-cht": "克羅地亞文",
10529 "xloc": [
10509 - "default.handlebars->31->1164"
10530 + "default.handlebars->31->1177"
10531 ]
10532 },
10533 {
@@ -10571,8 +10592,8 @@
10592 "default-mobile.handlebars->11->334",
10593 "default-mobile.handlebars->11->338",
10594 "default.handlebars->31->57",
10574 - "default.handlebars->31->901",
10575 - "default.handlebars->31->905",
10595 + "default.handlebars->31->914",
10596 + "default.handlebars->31->918",
10597 "terminal.handlebars->3->6"
10598 ]
10599 },
@@ -10680,8 +10701,8 @@
10701 "nl": "Huidig wachtwoord is niet correct.",
10702 "fr": "Le mot de passe actuel n'est pas correct.",
10703 "xloc": [
10683 - "default-mobile.handlebars->11->549",
10684 - "default.handlebars->31->2161"
10704 + "default-mobile.handlebars->11->566",
10705 + "default.handlebars->31->2174"
10706 ]
10707 },
10708 {
@@ -10739,7 +10760,7 @@
10760 "zh-chs": "捷克文",
10761 "zh-cht": "捷克文",
10762 "xloc": [
10742 - "default.handlebars->31->1165"
10763 + "default.handlebars->31->1178"
10764 ]
10765 },
10766 {
@@ -10779,7 +10800,7 @@
10800 "zh-chs": "丹麦文",
10801 "zh-cht": "丹麥文",
10802 "xloc": [
10782 - "default.handlebars->31->1166"
10803 + "default.handlebars->31->1179"
10804 ]
10805 },
10806 {
@@ -10799,7 +10820,7 @@
10820 "zh-chs": "数据通道",
10821 "zh-cht": "數據通道",
10822 "xloc": [
10802 - "default.handlebars->31->869",
10823 + "default.handlebars->31->882",
10824 "desktop.handlebars->3->11"
10825 ]
10826 },
@@ -10820,7 +10841,7 @@
10841 "zh-chs": "日期和时间",
10842 "zh-cht": "日期和時間",
10843 "xloc": [
10823 - "default.handlebars->31->1324"
10844 + "default.handlebars->31->1337"
10845 ]
10846 },
10847 {
@@ -10841,7 +10862,7 @@
10862 "zh-cht": "天",
10863 "xloc": [
10864 "default-mobile.handlebars->11->291",
10844 - "default.handlebars->31->796"
10865 + "default.handlebars->31->809"
10866 ]
10867 },
10868 {
@@ -10861,7 +10882,7 @@
10882 "zh-chs": "停用",
10883 "zh-cht": "停用",
10884 "xloc": [
10864 - "default.handlebars->31->1454"
10885 + "default.handlebars->31->1467"
10886 ]
10887 },
10888 {
@@ -10881,7 +10902,7 @@
10902 "zh-chs": "如果设置停用CCM",
10903 "zh-cht": "如果設置停用CCM",
10904 "xloc": [
10884 - "default.handlebars->31->1466"
10905 + "default.handlebars->31->1479"
10906 ]
10907 },
10908 {
@@ -10939,10 +10960,10 @@
10960 "zh-chs": "默认",
10961 "zh-cht": "默認",
10962 "xloc": [
10942 - "default.handlebars->31->1860",
10943 - "default.handlebars->31->1908",
10944 - "default.handlebars->31->1919",
10945 - "default.handlebars->31->1987"
10963 + "default.handlebars->31->1873",
10964 + "default.handlebars->31->1921",
10965 + "default.handlebars->31->1932",
10966 + "default.handlebars->31->2000"
10967 ]
10968 },
10969 {
@@ -10951,7 +10972,7 @@
10972 "nl": "Del",
10973 "xloc": [
10974 "default-mobile.handlebars->11->322",
10954 - "default.handlebars->31->889"
10975 + "default.handlebars->31->902"
10976 ]
10977 },
10978 {
@@ -10975,9 +10996,9 @@
10996 "default-mobile.handlebars->11->355",
10997 "default-mobile.handlebars->container->page_content->column_l->p10->p10files->p13toolbar->1->2->1->1",
10998 "default-mobile.handlebars->container->page_content->column_l->p5->p5myfiles->p5toolbar->1->0->1->1",
10978 - "default.handlebars->31->1646",
10999 + "default.handlebars->31->1659",
11000 "default.handlebars->31->535",
10980 - "default.handlebars->31->965",
11001 + "default.handlebars->31->978",
11002 "default.handlebars->container->column_l->p13->p13toolbar->1->2->1->3",
11003 "default.handlebars->container->column_l->p5->p5toolbar->1->0->p5filehead->3",
11004 "default.handlebars->container->dialog->idx_dlgButtonBar->5",
@@ -11006,7 +11027,7 @@
11027 "zh-cht": "刪除帳戶",
11028 "xloc": [
11029 "default-mobile.handlebars->11->95",
11009 - "default.handlebars->31->1341"
11030 + "default.handlebars->31->1354"
11031 ]
11032 },
11033 {
@@ -11026,7 +11047,7 @@
11047 "zh-chs": "删除帐户",
11048 "zh-cht": "刪除帳戶",
11049 "xloc": [
11029 - "default.handlebars->31->1827"
11050 + "default.handlebars->31->1840"
11051 ]
11052 },
11053 {
@@ -11047,7 +11068,7 @@
11068 "zh-cht": "刪除裝置",
11069 "xloc": [
11070 "default-mobile.handlebars->11->271",
11050 - "default.handlebars->31->650"
11071 + "default.handlebars->31->663"
11072 ]
11073 },
11074 {
@@ -11067,10 +11088,10 @@
11088 "zh-chs": "删除群组",
11089 "zh-cht": "刪除群組",
11090 "xloc": [
11070 - "default-mobile.handlebars->11->465",
11071 - "default-mobile.handlebars->11->468",
11072 - "default.handlebars->31->1450",
11073 - "default.handlebars->31->1483"
11091 + "default-mobile.handlebars->11->482",
11092 + "default-mobile.handlebars->11->485",
11093 + "default.handlebars->31->1463",
11094 + "default.handlebars->31->1496"
11095 ]
11096 },
11097 {
@@ -11091,7 +11112,7 @@
11112 "zh-cht": "刪除節點",
11113 "xloc": [
11114 "default-mobile.handlebars->11->299",
11094 - "default.handlebars->31->822"
11115 + "default.handlebars->31->835"
11116 ]
11117 },
11118 {
@@ -11131,7 +11152,7 @@
11152 "zh-chs": "删除用户",
11153 "zh-cht": "刪除用戶",
11154 "xloc": [
11134 - "default.handlebars->31->2039"
11155 + "default.handlebars->31->2052"
11156 ]
11157 },
11158 {
@@ -11151,8 +11172,8 @@
11172 "zh-chs": "删除用户群组",
11173 "zh-cht": "刪除用戶群組",
11174 "xloc": [
11154 - "default.handlebars->31->1957",
11155 - "default.handlebars->31->1967"
11175 + "default.handlebars->31->1970",
11176 + "default.handlebars->31->1980"
11177 ]
11178 },
11179 {
@@ -11172,7 +11193,7 @@
11193 "zh-chs": "删除用户群组",
11194 "zh-cht": "刪除用戶群組",
11195 "xloc": [
11175 - "default.handlebars->31->1906"
11196 + "default.handlebars->31->1919"
11197 ]
11198 },
11199 {
@@ -11192,7 +11213,7 @@
11213 "zh-chs": "删除用户{0}",
11214 "zh-cht": "刪除用戶{0}",
11215 "xloc": [
11195 - "default.handlebars->31->2062"
11216 + "default.handlebars->31->2075"
11217 ]
11218 },
11219 {
@@ -11213,7 +11234,7 @@
11234 "zh-cht": "刪除帳戶",
11235 "xloc": [
11236 "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->p3AccountActions->p2AccountActions->3->9->0",
11216 - "default.handlebars->31->1823",
11237 + "default.handlebars->31->1836",
11238 "default.handlebars->container->column_l->p2->p2info->p2AccountActions->3->p2AccountPassActions->7"
11239 ]
11240 },
@@ -11254,7 +11275,7 @@
11275 "zh-chs": "删除群组",
11276 "zh-cht": "刪除群組",
11277 "xloc": [
11257 - "default.handlebars->31->1902"
11278 + "default.handlebars->31->1915"
11279 ]
11280 },
11281 {
@@ -11294,7 +11315,7 @@
11315 "zh-chs": "递归删除:“{0}”,{1}个元素已删除",
11316 "zh-cht": "遞歸刪除:“{0}”,{1}個元素已刪除",
11317 "xloc": [
11297 - "default.handlebars->31->1706"
11318 + "default.handlebars->31->1719"
11319 ]
11320 },
11321 {
@@ -11316,8 +11337,8 @@
11337 "xloc": [
11338 "default-mobile.handlebars->11->135",
11339 "default-mobile.handlebars->11->357",
11319 - "default.handlebars->31->1648",
11320 - "default.handlebars->31->967"
11340 + "default.handlebars->31->1661",
11341 + "default.handlebars->31->980"
11342 ]
11343 },
11344 {
@@ -11337,7 +11358,7 @@
11358 "zh-chs": "删除用户群组{0}?",
11359 "zh-cht": "刪除用戶群組{0}?",
11360 "xloc": [
11340 - "default.handlebars->31->1965"
11361 + "default.handlebars->31->1978"
11362 ]
11363 },
11364 {
@@ -11359,8 +11380,8 @@
11380 "xloc": [
11381 "default-mobile.handlebars->11->134",
11382 "default-mobile.handlebars->11->356",
11362 - "default.handlebars->31->1647",
11363 - "default.handlebars->31->966"
11383 + "default.handlebars->31->1660",
11384 + "default.handlebars->31->979"
11385 ]
11386 },
11387 {
@@ -11400,7 +11421,7 @@
11421 "zh-chs": "删除:“{0}”",
11422 "zh-cht": "刪除:“{0}”",
11423 "xloc": [
11403 - "default.handlebars->31->1705"
11424 + "default.handlebars->31->1718"
11425 ]
11426 },
11427 {
@@ -11420,7 +11441,7 @@
11441 "zh-chs": "删除:“{0}”,{1}个元素已删除",
11442 "zh-cht": "刪除:“{0}”,已刪除{1}個元素",
11443 "xloc": [
11423 - "default.handlebars->31->1707"
11444 + "default.handlebars->31->1720"
11445 ]
11446 },
11447 {
@@ -11441,7 +11462,7 @@
11462 "zh-cht": "被拒絕",
11463 "xloc": [
11464 "default-mobile.handlebars->11->310",
11444 - "default.handlebars->31->865",
11465 + "default.handlebars->31->878",
11466 "desktop.handlebars->3->7",
11467 "terminal.handlebars->3->11"
11468 ]
@@ -11536,21 +11557,21 @@
11557 "default-mobile.handlebars->11->236",
11558 "default-mobile.handlebars->11->237",
11559 "default-mobile.handlebars->11->305",
11539 - "default-mobile.handlebars->11->400",
11540 - "default-mobile.handlebars->11->457",
11541 - "default-mobile.handlebars->11->470",
11542 - "default.handlebars->31->1018",
11543 - "default.handlebars->31->1028",
11544 - "default.handlebars->31->1361",
11545 - "default.handlebars->31->1398",
11546 - "default.handlebars->31->1485",
11547 - "default.handlebars->31->1911",
11548 - "default.handlebars->31->1921",
11549 - "default.handlebars->31->1922",
11550 - "default.handlebars->31->1963",
11560 + "default-mobile.handlebars->11->417",
11561 + "default-mobile.handlebars->11->474",
11562 + "default-mobile.handlebars->11->487",
11563 + "default.handlebars->31->1031",
11564 + "default.handlebars->31->1041",
11565 + "default.handlebars->31->1374",
11566 + "default.handlebars->31->1411",
11567 + "default.handlebars->31->1498",
11568 + "default.handlebars->31->1924",
11569 + "default.handlebars->31->1934",
11570 + "default.handlebars->31->1935",
11571 + "default.handlebars->31->1976",
11572 "default.handlebars->31->576",
11573 "default.handlebars->31->577",
11553 - "default.handlebars->31->860",
11574 + "default.handlebars->31->873",
11575 "default.handlebars->31->88",
11576 "default.handlebars->container->column_l->p42->p42tbl->1->0->3"
11577 ]
@@ -11590,12 +11611,12 @@
11611 "zh-cht": "桌面",
11612 "xloc": [
11613 "default-mobile.handlebars->11->278",
11593 - "default.handlebars->31->1491",
11594 - "default.handlebars->31->2111",
11614 + "default.handlebars->31->1504",
11615 + "default.handlebars->31->2124",
11616 "default.handlebars->31->541",
11596 - "default.handlebars->31->695",
11597 - "default.handlebars->31->750",
11598 - "default.handlebars->31->931",
11617 + "default.handlebars->31->708",
11618 + "default.handlebars->31->763",
11619 + "default.handlebars->31->944",
11620 "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevDesktop",
11621 "default.handlebars->contextMenu->cxdesktop",
11622 "desktop.handlebars->3->23"
@@ -11638,10 +11659,10 @@
11659 "zh-chs": "桌面通知",
11660 "zh-cht": "桌面通知",
11661 "xloc": [
11641 - "default.handlebars->31->1412",
11642 - "default.handlebars->31->1926",
11643 - "default.handlebars->31->2013",
11644 - "default.handlebars->31->614"
11662 + "default.handlebars->31->1425",
11663 + "default.handlebars->31->1939",
11664 + "default.handlebars->31->2026",
11665 + "default.handlebars->31->627"
11666 ]
11667 },
11668 {
@@ -11661,10 +11682,10 @@
11682 "zh-chs": "桌面提示",
11683 "zh-cht": "桌面提示",
11684 "xloc": [
11664 - "default.handlebars->31->1411",
11665 - "default.handlebars->31->1925",
11666 - "default.handlebars->31->2012",
11667 - "default.handlebars->31->613"
11685 + "default.handlebars->31->1424",
11686 + "default.handlebars->31->1938",
11687 + "default.handlebars->31->2025",
11688 + "default.handlebars->31->626"
11689 ]
11690 },
11691 {
@@ -11684,10 +11705,10 @@
11705 "zh-chs": "桌面提示+工具栏",
11706 "zh-cht": "桌面提示+工具欄",
11707 "xloc": [
11687 - "default.handlebars->31->1409",
11688 - "default.handlebars->31->1923",
11689 - "default.handlebars->31->2010",
11690 - "default.handlebars->31->611"
11708 + "default.handlebars->31->1422",
11709 + "default.handlebars->31->1936",
11710 + "default.handlebars->31->2023",
11711 + "default.handlebars->31->624"
11712 ]
11713 },
11714 {
@@ -11749,17 +11770,17 @@
11770 "zh-chs": "桌面工具栏",
11771 "zh-cht": "桌面工具欄",
11772 "xloc": [
11752 - "default.handlebars->31->1410",
11753 - "default.handlebars->31->1924",
11754 - "default.handlebars->31->2011",
11755 - "default.handlebars->31->612"
11773 + "default.handlebars->31->1423",
11774 + "default.handlebars->31->1937",
11775 + "default.handlebars->31->2024",
11776 + "default.handlebars->31->625"
11777 ]
11778 },
11779 {
11780 "en": "Desktop, View only",
11781 "nl": "Desktop, Alleen kijken",
11782 "xloc": [
11762 - "default.handlebars->31->751"
11783 + "default.handlebars->31->764"
11784 ]
11785 },
11786 {
@@ -11779,7 +11800,7 @@
11800 "zh-chs": "桌面时段",
11801 "zh-cht": "桌面時段",
11802 "xloc": [
11782 - "default.handlebars->31->930"
11803 + "default.handlebars->31->943"
11804 ]
11805 },
11806 {
@@ -11862,11 +11883,11 @@
11883 "zh-chs": "设备",
11884 "zh-cht": "裝置",
11885 "xloc": [
11865 - "default-mobile.handlebars->11->395",
11866 - "default.handlebars->31->1013",
11867 - "default.handlebars->31->1514",
11886 + "default-mobile.handlebars->11->412",
11887 + "default.handlebars->31->1026",
11888 + "default.handlebars->31->1527",
11889 "default.handlebars->31->197",
11869 - "default.handlebars->31->2081",
11890 + "default.handlebars->31->2094",
11891 "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->9->devListToolbarSort->sortselect->5"
11892 ]
11893 },
@@ -11889,7 +11910,7 @@
11910 "xloc": [
11911 "default-mobile.handlebars->11->288",
11912 "default-mobile.handlebars->11->289",
11892 - "default.handlebars->31->787"
11913 + "default.handlebars->31->800"
11914 ]
11915 },
11916 {
@@ -11930,16 +11951,16 @@
11951 "zh-cht": "裝置群",
11952 "xloc": [
11953 "agent-translations.json",
11933 - "default-mobile.handlebars->11->527",
11934 - "default.handlebars->31->1509",
11935 - "default.handlebars->31->1512",
11936 - "default.handlebars->31->1513",
11937 - "default.handlebars->31->1774",
11938 - "default.handlebars->31->1949",
11939 - "default.handlebars->31->1955",
11940 - "default.handlebars->31->2069",
11941 - "default.handlebars->31->2120",
11942 - "default.handlebars->31->2139"
11954 + "default-mobile.handlebars->11->544",
11955 + "default.handlebars->31->1522",
11956 + "default.handlebars->31->1525",
11957 + "default.handlebars->31->1526",
11958 + "default.handlebars->31->1787",
11959 + "default.handlebars->31->1962",
11960 + "default.handlebars->31->1968",
11961 + "default.handlebars->31->2082",
11962 + "default.handlebars->31->2133",
11963 + "default.handlebars->31->2152"
11964 ]
11965 },
11966 {
@@ -11959,8 +11980,8 @@
11980 "zh-chs": "设备组用户",
11981 "zh-cht": "裝置群用戶",
11982 "xloc": [
11962 - "default-mobile.handlebars->11->516",
11963 - "default.handlebars->31->1578"
11983 + "default-mobile.handlebars->11->533",
11984 + "default.handlebars->31->1591"
11985 ]
11986 },
11987 {
@@ -11981,11 +12002,11 @@
12002 "zh-cht": "裝置群",
12003 "xloc": [
12004 "default-mobile.handlebars->container->page_content->column_l->p3->p3info->1->3",
11984 - "default.handlebars->31->1790",
11985 - "default.handlebars->31->1896",
11986 - "default.handlebars->31->1936",
11987 - "default.handlebars->31->2007",
11988 - "default.handlebars->31->2190",
12005 + "default.handlebars->31->1803",
12006 + "default.handlebars->31->1909",
12007 + "default.handlebars->31->1949",
12008 + "default.handlebars->31->2020",
12009 + "default.handlebars->31->2203",
12010 "default.handlebars->container->column_l->p2->p2info->7"
12011 ]
12012 },
@@ -12026,7 +12047,7 @@
12047 "zh-chs": "设备位置",
12048 "zh-cht": "裝置位置",
12049 "xloc": [
12029 - "default.handlebars->31->823"
12050 + "default.handlebars->31->836"
12051 ]
12052 },
12053 {
@@ -12046,7 +12067,7 @@
12067 "zh-chs": "设备消息",
12068 "zh-cht": "裝置訊息",
12069 "xloc": [
12049 - "default.handlebars->31->744"
12070 + "default.handlebars->31->757"
12071 ]
12072 },
12073 {
@@ -12067,9 +12088,9 @@
12088 "zh-cht": "裝置名稱",
12089 "xloc": [
12090 "default-mobile.handlebars->11->303",
12070 - "default.handlebars->31->2119",
12091 + "default.handlebars->31->2132",
12092 "default.handlebars->31->305",
12072 - "default.handlebars->31->858",
12093 + "default.handlebars->31->871",
12094 "player.handlebars->3->9"
12095 ]
12096 },
@@ -12091,7 +12112,7 @@
12112 "zh-cht": "裝置通知",
12113 "xloc": [
12114 "default.handlebars->31->494",
12094 - "default.handlebars->31->746"
12115 + "default.handlebars->31->759"
12116 ]
12117 },
12118 {
@@ -12128,7 +12149,7 @@
12149 "zh-chs": "设备共享链接",
12150 "zh-cht": "設備共享鏈接",
12151 "xloc": [
12131 - "default.handlebars->31->691"
12152 + "default.handlebars->31->704"
12153 ]
12154 },
12155 {
@@ -12168,8 +12189,8 @@
12189 "zh-chs": "设备连接。",
12190 "zh-cht": "裝置連接。",
12191 "xloc": [
12171 - "default.handlebars->31->1329",
12172 - "default.handlebars->31->1599"
12192 + "default.handlebars->31->1342",
12193 + "default.handlebars->31->1612"
12194 ]
12195 },
12196 {
@@ -12189,8 +12210,8 @@
12210 "zh-chs": "设备断开连接。",
12211 "zh-cht": "裝置斷開連接。",
12212 "xloc": [
12192 - "default.handlebars->31->1330",
12193 - "default.handlebars->31->1600"
12213 + "default.handlebars->31->1343",
12214 + "default.handlebars->31->1613"
12215 ]
12216 },
12217 {
@@ -12210,7 +12231,7 @@
12231 "zh-chs": "创建的设备组:{0}",
12232 "zh-cht": "設備組已創建:{0}",
12233 "xloc": [
12213 - "default.handlebars->31->1736"
12234 + "default.handlebars->31->1749"
12235 ]
12236 },
12237 {
@@ -12230,7 +12251,7 @@
12251 "zh-chs": "设备组已删除:{0}",
12252 "zh-cht": "設備組已刪除:{0}",
12253 "xloc": [
12233 - "default.handlebars->31->1737"
12254 + "default.handlebars->31->1750"
12255 ]
12256 },
12257 {
@@ -12250,7 +12271,7 @@
12271 "zh-chs": "设备组成员身份已更改:{0}",
12272 "zh-cht": "設備組成員身份已更改:{0}",
12273 "xloc": [
12253 - "default.handlebars->31->1738"
12274 + "default.handlebars->31->1751"
12275 ]
12276 },
12277 {
@@ -12270,7 +12291,7 @@
12291 "zh-chs": "其他设备组管理员可以查看和更改设备组注释。",
12292 "zh-cht": "其他裝置群管理員可以查看和更改裝置群註釋。",
12293 "xloc": [
12273 - "default.handlebars->31->741"
12294 + "default.handlebars->31->754"
12295 ]
12296 },
12297 {
@@ -12290,7 +12311,7 @@
12311 "zh-chs": "设备组通知已更改",
12312 "zh-cht": "設備組通知已更改",
12313 "xloc": [
12293 - "default.handlebars->31->1733"
12314 + "default.handlebars->31->1746"
12315 ]
12316 },
12317 {
@@ -12310,7 +12331,7 @@
12331 "zh-chs": "未删除的设备组:{0}",
12332 "zh-cht": "未刪除的設備組:{0}",
12333 "xloc": [
12313 - "default.handlebars->31->1716"
12334 + "default.handlebars->31->1729"
12335 ]
12336 },
12337 {
@@ -12703,7 +12724,7 @@
12724 "zh-chs": "设备请求激活Intel(R)AMT ACM,FQDN:{0}",
12725 "zh-cht": "設備請求激活Intel(R)AMT ACM,FQDN:{0}",
12726 "xloc": [
12706 - "default.handlebars->31->1718"
12727 + "default.handlebars->31->1731"
12728 ]
12729 },
12730 {
@@ -12740,8 +12761,8 @@
12761 "zh-chs": "设备",
12762 "zh-cht": "裝置",
12763 "xloc": [
12743 - "default.handlebars->31->1897",
12744 - "default.handlebars->31->1937"
12764 + "default.handlebars->31->1910",
12765 + "default.handlebars->31->1950"
12766 ]
12767 },
12768 {
@@ -12761,7 +12782,8 @@
12782 "zh-chs": "已禁用",
12783 "zh-cht": "已禁用",
12784 "xloc": [
12764 - "default.handlebars->31->607"
12785 + "default-mobile.handlebars->11->398",
12786 + "default.handlebars->31->620"
12787 ]
12788 },
12789 {
@@ -12781,7 +12803,7 @@
12803 "zh-chs": "禁用的电子邮件两因素身份验证",
12804 "zh-cht": "禁用的電子郵件兩因素身份驗證",
12805 "xloc": [
12784 - "default.handlebars->31->1749"
12806 + "default.handlebars->31->1762"
12807 ]
12808 },
12809 {
@@ -12804,8 +12826,8 @@
12826 "agent-translations.json",
12827 "default-mobile.handlebars->11->346",
12828 "default-mobile.handlebars->container->page_content->column_l->p10->p10desktop->deskarea1->1->3",
12807 - "default.handlebars->31->1422",
12808 - "default.handlebars->31->947",
12829 + "default.handlebars->31->1435",
12830 + "default.handlebars->31->960",
12831 "default.handlebars->container->column_l->p11->deskarea0->deskarea1->3->disconnectbutton1span",
12832 "default.handlebars->container->column_l->p12->termTable->1->1->0->1->3->disconnectbutton2span",
12833 "desktop.handlebars->p11->deskarea0->deskarea1->3->disconnectbutton1span",
@@ -12905,7 +12927,7 @@
12927 "zh-chs": "在远程设备上显示一个消息框。",
12928 "zh-cht": "在遠程裝置上顯示一個訊息框。",
12929 "xloc": [
12908 - "default.handlebars->31->745"
12930 + "default.handlebars->31->758"
12931 ]
12932 },
12933 {
@@ -12945,7 +12967,7 @@
12967 "zh-chs": "在远程设备上显示短信",
12968 "zh-cht": "在遠程裝置上顯示短信",
12969 "xloc": [
12948 - "default.handlebars->31->644"
12970 + "default.handlebars->31->657"
12971 ]
12972 },
12973 {
@@ -12965,7 +12987,7 @@
12987 "zh-chs": "显示设备组名称",
12988 "zh-cht": "顯示裝置群名稱",
12989 "xloc": [
12968 - "default.handlebars->31->1328"
12990 + "default.handlebars->31->1341"
12991 ]
12992 },
12993 {
@@ -12985,7 +13007,7 @@
13007 "zh-chs": "显示名称",
13008 "zh-cht": "顯示名稱",
13009 "xloc": [
12988 - "default.handlebars->31->916"
13010 + "default.handlebars->31->929"
13011 ]
13012 },
13013 {
@@ -13005,7 +13027,7 @@
13027 "zh-chs": "显示公共连结",
13028 "zh-cht": "顯示公共鏈結",
13029 "xloc": [
13008 - "default.handlebars->31->1619"
13030 + "default.handlebars->31->1632"
13031 ]
13032 },
13033 {
@@ -13025,7 +13047,7 @@
13047 "zh-chs": "显示消息框,标题= “{0}”,消息= “{1}”",
13048 "zh-cht": "顯示消息框,標題= “{0}”,消息= “{1}”",
13049 "xloc": [
13028 - "default.handlebars->31->1678"
13050 + "default.handlebars->31->1691"
13051 ]
13052 },
13053 {
@@ -13045,7 +13067,7 @@
13067 "zh-chs": "显示吐司消息,标题= “{0}”,消息= “{1}”",
13068 "zh-cht": "顯示吐司消息,標題= “{0}”,消息= “{1}”",
13069 "xloc": [
13048 - "default.handlebars->31->1686"
13070 + "default.handlebars->31->1699"
13071 ]
13072 },
13073 {
@@ -13065,8 +13087,8 @@
13087 "zh-chs": "什么都不做",
13088 "zh-cht": "什麼都不做",
13089 "xloc": [
13068 - "default.handlebars->31->1469",
13069 - "default.handlebars->31->1473"
13090 + "default.handlebars->31->1482",
13091 + "default.handlebars->31->1486"
13092 ]
13093 },
13094 {
@@ -13086,10 +13108,10 @@
13108 "zh-chs": "域",
13109 "zh-cht": "域",
13110 "xloc": [
13089 - "default.handlebars->31->1861",
13090 - "default.handlebars->31->1909",
13091 - "default.handlebars->31->1918",
13092 - "default.handlebars->31->1986",
13111 + "default.handlebars->31->1874",
13112 + "default.handlebars->31->1922",
13113 + "default.handlebars->31->1931",
13114 + "default.handlebars->31->1999",
13115 "mstsc.handlebars->main->1->3->1->2->1->0",
13116 "mstsc.handlebars->main->1->3->1->2->3"
13117 ]
@@ -13111,7 +13133,7 @@
13133 "zh-chs": "请勿更改,如果设置请保留CCM",
13134 "zh-cht": "請勿更改,如果設置請保留CCM",
13135 "xloc": [
13114 - "default.handlebars->31->1465"
13136 + "default.handlebars->31->1478"
13137 ]
13138 },
13139 {
@@ -13148,7 +13170,7 @@
13170 "zh-chs": "不要连接到服务器",
13171 "zh-cht": "不要連接到伺服器",
13172 "xloc": [
13151 - "default.handlebars->31->1474"
13173 + "default.handlebars->31->1487"
13174 ]
13175 },
13176 {
@@ -13213,7 +13235,7 @@
13235 "nl": "Omlaag",
13236 "xloc": [
13237 "default-mobile.handlebars->11->330",
13216 - "default.handlebars->31->897"
13238 + "default.handlebars->31->910"
13239 ]
13240 },
13241 {
@@ -13277,7 +13299,7 @@
13299 "zh-cht": "下載檔案",
13300 "xloc": [
13301 "default-mobile.handlebars->11->376",
13280 - "default.handlebars->31->986"
13302 + "default.handlebars->31->999"
13303 ]
13304 },
13305 {
@@ -13317,7 +13339,7 @@
13339 "zh-chs": "下载MeshCmd",
13340 "zh-cht": "下載MeshCmd",
13341 "xloc": [
13320 - "default.handlebars->31->848"
13342 + "default.handlebars->31->861"
13343 ]
13344 },
13345 {
@@ -13377,7 +13399,7 @@
13399 "zh-chs": "下载报告",
13400 "zh-cht": "下載報告",
13401 "xloc": [
13380 - "default.handlebars->31->1779",
13402 + "default.handlebars->31->1792",
13403 "default.handlebars->container->column_l->p3->3->1->0->3"
13404 ]
13405 },
@@ -13398,7 +13420,7 @@
13420 "zh-chs": "下载带有指令档案的“ meshcmd”,以通过此服务器将网络讯息发送到该设备。紧记编辑meshaction.txt并添加您的帐户密码或进行任何必要的更改。",
13421 "zh-cht": "下載帶有指令檔案的“ meshcmd”,以通過此服務器將網絡讯息發送到該裝置。緊記編輯meshaction.txt並新增你的帳戶密碼或進行任何必要的更改。",
13422 "xloc": [
13401 - "default.handlebars->31->841"
13423 + "default.handlebars->31->854"
13424 ]
13425 },
13426 {
@@ -13478,7 +13500,7 @@
13500 "zh-chs": "下载电源事件",
13501 "zh-cht": "下載電源事件",
13502 "xloc": [
13481 - "default.handlebars->31->797"
13503 + "default.handlebars->31->810"
13504 ]
13505 },
13506 {
@@ -13578,7 +13600,7 @@
13600 "zh-chs": "使用以下一种档案格式下载事件列表。",
13601 "zh-cht": "使用以下一種檔案格式下載事件列表。",
13602 "xloc": [
13581 - "default.handlebars->31->1780"
13603 + "default.handlebars->31->1793"
13604 ]
13605 },
13606 {
@@ -13598,7 +13620,7 @@
13620 "zh-chs": "使用以下一种档案格式下载用户列表。",
13621 "zh-cht": "使用以下一種檔案格式下載用戶列表。",
13622 "xloc": [
13601 - "default.handlebars->31->1845"
13623 + "default.handlebars->31->1858"
13624 ]
13625 },
13626 {
@@ -13679,7 +13701,7 @@
13701 "zh-chs": "下载:“{0}”",
13702 "zh-cht": "下載:“{0}”",
13703 "xloc": [
13682 - "default.handlebars->31->1709"
13704 + "default.handlebars->31->1722"
13705 ]
13706 },
13707 {
@@ -13719,7 +13741,7 @@
13741 "zh-chs": "代理重复",
13742 "zh-cht": "代理重複",
13743 "xloc": [
13722 - "default.handlebars->31->2186"
13744 + "default.handlebars->31->2199"
13745 ]
13746 },
13747 {
@@ -13759,7 +13781,7 @@
13781 "zh-chs": "复制用户组",
13782 "zh-cht": "複製用戶群",
13783 "xloc": [
13762 - "default.handlebars->31->1913"
13784 + "default.handlebars->31->1926"
13785 ]
13786 },
13787 {
@@ -13796,8 +13818,8 @@
13818 "zh-chs": "持续时间",
13819 "zh-cht": "持續時間",
13820 "xloc": [
13799 - "default.handlebars->31->2105",
13800 - "default.handlebars->31->2125",
13821 + "default.handlebars->31->2118",
13822 + "default.handlebars->31->2138",
13823 "player.handlebars->3->2"
13824 ]
13825 },
@@ -13835,7 +13857,7 @@
13857 "zh-chs": "荷兰文(比利时)",
13858 "zh-cht": "荷蘭文(比利時)",
13859 "xloc": [
13838 - "default.handlebars->31->1168"
13860 + "default.handlebars->31->1181"
13861 ]
13862 },
13863 {
@@ -13855,7 +13877,7 @@
13877 "zh-chs": "荷兰文(标准)",
13878 "zh-cht": "荷蘭文(標準)",
13879 "xloc": [
13858 - "default.handlebars->31->1167"
13880 + "default.handlebars->31->1180"
13881 ]
13882 },
13883 {
@@ -14144,7 +14166,7 @@
14166 "zh-cht": "編輯裝置",
14167 "xloc": [
14168 "default-mobile.handlebars->11->308",
14147 - "default.handlebars->31->863"
14169 + "default.handlebars->31->876"
14170 ]
14171 },
14172 {
@@ -14164,13 +14186,13 @@
14186 "zh-chs": "编辑设备组",
14187 "zh-cht": "編輯裝置群",
14188 "xloc": [
14167 - "default-mobile.handlebars->11->471",
14168 - "default-mobile.handlebars->11->473",
14169 - "default-mobile.handlebars->11->493",
14170 - "default.handlebars->31->1486",
14171 - "default.handlebars->31->1518",
14172 - "default.handlebars->31->1542",
14173 - "default.handlebars->31->1554"
14189 + "default-mobile.handlebars->11->488",
14190 + "default-mobile.handlebars->11->490",
14191 + "default-mobile.handlebars->11->510",
14192 + "default.handlebars->31->1499",
14193 + "default.handlebars->31->1531",
14194 + "default.handlebars->31->1555",
14195 + "default.handlebars->31->1567"
14196 ]
14197 },
14198 {
@@ -14190,7 +14212,7 @@
14212 "zh-chs": "编辑设备组功能",
14213 "zh-cht": "編輯裝置群功能",
14214 "xloc": [
14193 - "default.handlebars->31->1504"
14215 + "default.handlebars->31->1517"
14216 ]
14217 },
14218 {
@@ -14210,8 +14232,8 @@
14232 "zh-chs": "编辑设备组权限",
14233 "zh-cht": "編輯裝置群權限",
14234 "xloc": [
14213 - "default.handlebars->31->1539",
14214 - "default.handlebars->31->1551"
14235 + "default.handlebars->31->1552",
14236 + "default.handlebars->31->1564"
14237 ]
14238 },
14239 {
@@ -14231,7 +14253,7 @@
14253 "zh-chs": "编辑设备组用户同意",
14254 "zh-cht": "編輯裝置群用戶同意",
14255 "xloc": [
14234 - "default.handlebars->31->1487"
14256 + "default.handlebars->31->1500"
14257 ]
14258 },
14259 {
@@ -14251,8 +14273,8 @@
14273 "zh-chs": "编辑设备笔记",
14274 "zh-cht": "編輯裝置筆記",
14275 "xloc": [
14254 - "default-mobile.handlebars->11->485",
14255 - "default.handlebars->31->1531"
14276 + "default-mobile.handlebars->11->502",
14277 + "default.handlebars->31->1544"
14278 ]
14279 },
14280 {
@@ -14272,8 +14294,8 @@
14294 "zh-chs": "编辑设备权限",
14295 "zh-cht": "編輯裝置權限",
14296 "xloc": [
14275 - "default.handlebars->31->1544",
14276 - "default.handlebars->31->1546"
14297 + "default.handlebars->31->1557",
14298 + "default.handlebars->31->1559"
14299 ]
14300 },
14301 {
@@ -14313,7 +14335,7 @@
14335 "zh-chs": "编辑设备用户同意",
14336 "zh-cht": "編輯裝置用戶同意",
14337 "xloc": [
14316 - "default.handlebars->31->1489"
14338 + "default.handlebars->31->1502"
14339 ]
14340 },
14341 {
@@ -14333,7 +14355,7 @@
14355 "zh-chs": "编辑群组",
14356 "zh-cht": "編輯群組",
14357 "xloc": [
14336 - "default.handlebars->31->719"
14358 + "default.handlebars->31->732"
14359 ]
14360 },
14361 {
@@ -14360,7 +14382,7 @@
14382 "default.handlebars->31->591",
14383 "default.handlebars->31->594",
14384 "default.handlebars->31->597",
14363 - "default.handlebars->31->804"
14385 + "default.handlebars->31->817"
14386 ]
14387 },
14388 {
@@ -14380,8 +14402,8 @@
14402 "zh-chs": "编辑笔记",
14403 "zh-cht": "編輯筆記",
14404 "xloc": [
14383 - "default-mobile.handlebars->11->500",
14384 - "default.handlebars->31->1561"
14405 + "default-mobile.handlebars->11->517",
14406 + "default.handlebars->31->1574"
14407 ]
14408 },
14409 {
@@ -14401,7 +14423,7 @@
14423 "zh-chs": "编辑用户同意",
14424 "zh-cht": "編輯用戶同意",
14425 "xloc": [
14404 - "default.handlebars->31->1488"
14426 + "default.handlebars->31->1501"
14427 ]
14428 },
14429 {
@@ -14421,7 +14443,7 @@
14443 "zh-chs": "编辑用户设备组权限",
14444 "zh-cht": "編輯用戶裝置群權限",
14445 "xloc": [
14424 - "default.handlebars->31->1552"
14446 + "default.handlebars->31->1565"
14447 ]
14448 },
14449 {
@@ -14441,7 +14463,7 @@
14463 "zh-chs": "编辑用户设备权限",
14464 "zh-cht": "編輯用戶裝置權限",
14465 "xloc": [
14444 - "default.handlebars->31->1547"
14466 + "default.handlebars->31->1560"
14467 ]
14468 },
14469 {
@@ -14461,7 +14483,7 @@
14483 "zh-chs": "编辑用户组",
14484 "zh-cht": "編輯用戶群",
14485 "xloc": [
14464 - "default.handlebars->31->1964"
14486 + "default.handlebars->31->1977"
14487 ]
14488 },
14489 {
@@ -14481,7 +14503,7 @@
14503 "zh-chs": "编辑用户组设备权限",
14504 "zh-cht": "編輯用戶群裝置權限",
14505 "xloc": [
14484 - "default.handlebars->31->1549"
14506 + "default.handlebars->31->1562"
14507 ]
14508 },
14509 {
@@ -14501,7 +14523,7 @@
14523 "zh-chs": "编辑用户组用户同意",
14524 "zh-cht": "編輯用戶組用戶同意",
14525 "xloc": [
14504 - "default.handlebars->31->1490"
14526 + "default.handlebars->31->1503"
14527 ]
14528 },
14529 {
@@ -14583,11 +14605,11 @@
14605 "zh-cht": "電郵",
14606 "xloc": [
14607 "default-mobile.handlebars->11->89",
14586 - "default.handlebars->31->1863",
14587 - "default.handlebars->31->1990",
14588 - "default.handlebars->31->1992",
14589 - "default.handlebars->31->2032",
14590 - "default.handlebars->31->2050",
14608 + "default.handlebars->31->1876",
14609 + "default.handlebars->31->2003",
14610 + "default.handlebars->31->2005",
14611 + "default.handlebars->31->2045",
14612 + "default.handlebars->31->2063",
14613 "default.handlebars->31->337",
14614 "login-mobile.handlebars->5->42",
14615 "login-mobile.handlebars->container->page_content->column_l->1->1->0->1->tokenpanel->1->7->1->4->1->3",
@@ -14620,7 +14642,7 @@
14642 "zh-cht": "電郵地址變更",
14643 "xloc": [
14644 "default-mobile.handlebars->11->90",
14623 - "default.handlebars->31->1337"
14645 + "default.handlebars->31->1350"
14646 ]
14647 },
14648 {
@@ -14641,7 +14663,7 @@
14663 "zh-cht": "電郵認證",
14664 "xloc": [
14665 "default-mobile.handlebars->11->79",
14644 - "default.handlebars->31->1105"
14666 + "default.handlebars->31->1118"
14667 ]
14668 },
14669 {
@@ -14701,7 +14723,7 @@
14723 "zh-cht": "電郵驗證",
14724 "xloc": [
14725 "default-mobile.handlebars->11->88",
14704 - "default.handlebars->31->1335"
14726 + "default.handlebars->31->1348"
14727 ]
14728 },
14729 {
@@ -14741,7 +14763,7 @@
14763 "zh-chs": "电邮未验证",
14764 "zh-cht": "電郵未驗證",
14765 "xloc": [
14744 - "default.handlebars->31->1809"
14766 + "default.handlebars->31->1822"
14767 ]
14768 },
14769 {
@@ -14761,8 +14783,8 @@
14783 "zh-chs": "电子邮件已验证",
14784 "zh-cht": "電子郵件已驗證",
14785 "xloc": [
14764 - "default.handlebars->31->1810",
14765 - "default.handlebars->31->1984"
14786 + "default.handlebars->31->1823",
14787 + "default.handlebars->31->1997"
14788 ]
14789 },
14790 {
@@ -14782,7 +14804,7 @@
14804 "zh-chs": "电邮已验证。",
14805 "zh-cht": "電郵已驗證。",
14806 "xloc": [
14785 - "default.handlebars->31->1869"
14807 + "default.handlebars->31->1882"
14808 ]
14809 },
14810 {
@@ -14802,7 +14824,7 @@
14824 "zh-chs": "电邮未验证",
14825 "zh-cht": "電郵未驗證",
14826 "xloc": [
14805 - "default.handlebars->31->1985"
14827 + "default.handlebars->31->1998"
14828 ]
14829 },
14830 {
@@ -14822,8 +14844,8 @@
14844 "zh-chs": "电邮已发送。",
14845 "zh-cht": "電郵已發送。",
14846 "xloc": [
14825 - "default-mobile.handlebars->11->542",
14826 - "default.handlebars->31->2154",
14847 + "default-mobile.handlebars->11->559",
14848 + "default.handlebars->31->2167",
14849 "login-mobile.handlebars->5->2",
14850 "login.handlebars->5->2",
14851 "login2.handlebars->7->3"
@@ -14868,7 +14890,7 @@
14890 "zh-chs": "已通过电邮验证,并且需要重置密码。",
14891 "zh-cht": "已通過電郵驗證,並且需要重置密碼。",
14892 "xloc": [
14871 - "default.handlebars->31->1870"
14893 + "default.handlebars->31->1883"
14894 ]
14895 },
14896 {
@@ -14888,7 +14910,7 @@
14910 "zh-chs": "电邮/短信流量",
14911 "zh-cht": "電郵/短信流量",
14912 "xloc": [
14891 - "default.handlebars->31->2230"
14913 + "default.handlebars->31->2243"
14914 ]
14915 },
14916 {
@@ -14934,7 +14956,7 @@
14956 "zh-chs": "启用邀请代码",
14957 "zh-cht": "啟用邀請代碼",
14958 "xloc": [
14937 - "default.handlebars->31->1584"
14959 + "default.handlebars->31->1597"
14960 ]
14961 },
14962 {
@@ -14975,7 +14997,7 @@
14997 "zh-cht": "啟用電郵二因子鑑別。",
14998 "xloc": [
14999 "default-mobile.handlebars->11->81",
14978 - "default.handlebars->31->1107"
15000 + "default.handlebars->31->1120"
15001 ]
15002 },
15003 {
@@ -15015,7 +15037,7 @@
15037 "zh-chs": "已启用",
15038 "zh-cht": "已啟用",
15039 "xloc": [
15018 - "default.handlebars->31->2127"
15040 + "default.handlebars->31->2140"
15041 ]
15042 },
15043 {
@@ -15035,7 +15057,7 @@
15057 "zh-chs": "启用电子邮件两因素身份验证",
15058 "zh-cht": "啟用電子郵件兩因素身份驗證",
15059 "xloc": [
15038 - "default.handlebars->31->1748"
15060 + "default.handlebars->31->1761"
15061 ]
15062 },
15063 {
@@ -15064,7 +15086,7 @@
15086 "nl": "End",
15087 "xloc": [
15088 "default-mobile.handlebars->11->324",
15067 - "default.handlebars->31->891"
15089 + "default.handlebars->31->904"
15090 ]
15091 },
15092 {
@@ -15084,7 +15106,7 @@
15106 "zh-chs": "时间结束",
15107 "zh-cht": "時間結束",
15108 "xloc": [
15087 - "default.handlebars->31->2124"
15109 + "default.handlebars->31->2137"
15110 ]
15111 },
15112 {
@@ -15104,7 +15126,7 @@
15126 "zh-chs": "从{1}到{2},{3}秒结束了桌面会话“{0}”",
15127 "zh-cht": "從{1}到{2},{3}秒結束了桌面會話“{0}”",
15128 "xloc": [
15107 - "default.handlebars->31->1671"
15129 + "default.handlebars->31->1684"
15130 ]
15131 },
15132 {
@@ -15124,7 +15146,7 @@
15146 "zh-chs": "从{1}到{2},{3}秒结束了文件管理会话“{0}”",
15147 "zh-cht": "從{1}到{2},{3}秒結束了文件管理會話“{0}”",
15148 "xloc": [
15127 - "default.handlebars->31->1672"
15149 + "default.handlebars->31->1685"
15150 ]
15151 },
15152 {
@@ -15144,7 +15166,7 @@
15166 "zh-chs": "从{1}到{2},{3}秒结束了中继会话“{0}”",
15167 "zh-cht": "從{1}到{2},{3}秒結束了中繼會話“{0}”",
15168 "xloc": [
15147 - "default.handlebars->31->1669"
15169 + "default.handlebars->31->1682"
15170 ]
15171 },
15172 {
@@ -15164,7 +15186,7 @@
15186 "zh-chs": "从{1}到{2},{3}秒结束了终端会话“{0}”",
15187 "zh-cht": "從{1}到{2},{3}秒結束了終端會話“{0}”",
15188 "xloc": [
15167 - "default.handlebars->31->1670"
15189 + "default.handlebars->31->1683"
15190 ]
15191 },
15192 {
@@ -15184,7 +15206,7 @@
15206 "zh-chs": "英文",
15207 "zh-cht": "英文",
15208 "xloc": [
15187 - "default.handlebars->31->1169"
15209 + "default.handlebars->31->1182"
15210 ]
15211 },
15212 {
@@ -15204,7 +15226,7 @@
15226 "zh-chs": "英文(澳洲)",
15227 "zh-cht": "英文(澳洲)",
15228 "xloc": [
15207 - "default.handlebars->31->1170"
15229 + "default.handlebars->31->1183"
15230 ]
15231 },
15232 {
@@ -15224,7 +15246,7 @@
15246 "zh-chs": "英文(伯利茲)",
15247 "zh-cht": "英文(伯利茲)",
15248 "xloc": [
15227 - "default.handlebars->31->1171"
15249 + "default.handlebars->31->1184"
15250 ]
15251 },
15252 {
@@ -15244,7 +15266,7 @@
15266 "zh-chs": "英文(加拿大)",
15267 "zh-cht": "英文(加拿大)",
15268 "xloc": [
15247 - "default.handlebars->31->1172"
15269 + "default.handlebars->31->1185"
15270 ]
15271 },
15272 {
@@ -15264,7 +15286,7 @@
15286 "zh-chs": "英文(爱尔兰)",
15287 "zh-cht": "英文(愛爾蘭)",
15288 "xloc": [
15267 - "default.handlebars->31->1173"
15289 + "default.handlebars->31->1186"
15290 ]
15291 },
15292 {
@@ -15284,7 +15306,7 @@
15306 "zh-chs": "英文(牙买加)",
15307 "zh-cht": "英文(牙買加)",
15308 "xloc": [
15287 - "default.handlebars->31->1174"
15309 + "default.handlebars->31->1187"
15310 ]
15311 },
15312 {
@@ -15304,7 +15326,7 @@
15326 "zh-chs": "英文(纽西兰)",
15327 "zh-cht": "英文(紐西蘭)",
15328 "xloc": [
15307 - "default.handlebars->31->1175"
15329 + "default.handlebars->31->1188"
15330 ]
15331 },
15332 {
@@ -15324,7 +15346,7 @@
15346 "zh-chs": "英文(菲律宾)",
15347 "zh-cht": "英文(菲律賓)",
15348 "xloc": [
15327 - "default.handlebars->31->1176"
15349 + "default.handlebars->31->1189"
15350 ]
15351 },
15352 {
@@ -15344,7 +15366,7 @@
15366 "zh-chs": "英语(南非)",
15367 "zh-cht": "英語(南非)",
15368 "xloc": [
15347 - "default.handlebars->31->1177"
15369 + "default.handlebars->31->1190"
15370 ]
15371 },
15372 {
@@ -15364,7 +15386,7 @@
15386 "zh-chs": "英文(特立尼达和多巴哥)",
15387 "zh-cht": "英文(特立尼達和多巴哥)",
15388 "xloc": [
15367 - "default.handlebars->31->1178"
15389 + "default.handlebars->31->1191"
15390 ]
15391 },
15392 {
@@ -15384,7 +15406,7 @@
15406 "zh-chs": "英文(英国)",
15407 "zh-cht": "英文(英國)",
15408 "xloc": [
15387 - "default.handlebars->31->1179"
15409 + "default.handlebars->31->1192"
15410 ]
15411 },
15412 {
@@ -15404,7 +15426,7 @@
15426 "zh-chs": "美国英文",
15427 "zh-cht": "美國英語",
15428 "xloc": [
15407 - "default.handlebars->31->1180"
15429 + "default.handlebars->31->1193"
15430 ]
15431 },
15432 {
@@ -15424,7 +15446,7 @@
15446 "zh-chs": "英文(津巴布韦)",
15447 "zh-cht": "英文(津巴布韋)",
15448 "xloc": [
15427 - "default.handlebars->31->1181"
15449 + "default.handlebars->31->1194"
15450 ]
15451 },
15452 {
@@ -15445,10 +15467,10 @@
15467 "zh-cht": "輸入",
15468 "xloc": [
15469 "default-mobile.handlebars->11->319",
15448 - "default.handlebars->31->1363",
15449 - "default.handlebars->31->1364",
15450 - "default.handlebars->31->886",
15451 - "default.handlebars->31->959"
15470 + "default.handlebars->31->1376",
15471 + "default.handlebars->31->1377",
15472 + "default.handlebars->31->899",
15473 + "default.handlebars->31->972"
15474 ]
15475 },
15476 {
@@ -15468,7 +15490,7 @@
15490 "zh-chs": "输入管理领域名称的逗号分隔列表。",
15491 "zh-cht": "輸入管理領域名稱的逗號分隔列表。",
15492 "xloc": [
15471 - "default.handlebars->31->1874"
15493 + "default.handlebars->31->1887"
15494 ]
15495 },
15496 {
@@ -15528,7 +15550,7 @@
15550 "zh-chs": "输入文本,然后单击确定以远程键入它。在继续操作之前,请确保将远程光标放置在正确的位置。",
15551 "zh-cht": "輸入文本,然後單擊確定以遠程鍵入它。在繼續操作之前,請確保將遠程光標放置在正確的位置。",
15552 "xloc": [
15531 - "default.handlebars->31->910"
15553 + "default.handlebars->31->923"
15554 ]
15555 },
15556 {
@@ -15590,7 +15612,7 @@
15612 "zh-chs": "输入支持SMS的电话号码。验证后,该号码可用于登录验证和其他通知。",
15613 "zh-cht": "輸入支持SMS的電話號碼。驗證後,該號碼可用於登入驗證和其他通知。",
15614 "xloc": [
15593 - "default.handlebars->31->1102"
15615 + "default.handlebars->31->1115"
15616 ]
15617 },
15618 {
@@ -15618,8 +15640,8 @@
15640 "nl": "Fout, uitnodigingscode \\\"{0}\\\" al in gebruik.",
15641 "fr": "Erreur, code d'invitation \\\"{0}\\\" déjà utilisé.",
15642 "xloc": [
15621 - "default-mobile.handlebars->11->550",
15622 - "default.handlebars->31->2162"
15643 + "default-mobile.handlebars->11->567",
15644 + "default.handlebars->31->2175"
15645 ]
15646 },
15647 {
@@ -15627,8 +15649,8 @@
15649 "nl": "Fout, wachtwoord niet gewijzigd.",
15650 "fr": "Erreur, mot de passe non modifié.",
15651 "xloc": [
15630 - "default-mobile.handlebars->11->547",
15631 - "default.handlebars->31->2159"
15652 + "default-mobile.handlebars->11->564",
15653 + "default.handlebars->31->2172"
15654 ]
15655 },
15656 {
@@ -15636,8 +15658,8 @@
15658 "nl": "Fout, het is niet mogelijk om naar algemeen gebruikt wachtwoord te veranderen.",
15659 "fr": "Erreur, impossible de changer le mot de passe couramment utilisé.",
15660 "xloc": [
15639 - "default-mobile.handlebars->11->546",
15640 - "default.handlebars->31->2158"
15661 + "default-mobile.handlebars->11->563",
15662 + "default.handlebars->31->2171"
15663 ]
15664 },
15665 {
@@ -15645,8 +15667,8 @@
15667 "nl": "Fout, kan niet wijzigen naar eerder gebruikt wachtwoord.",
15668 "fr": "Erreur, impossible de changer le mot de passe précédemment utilisé.",
15669 "xloc": [
15648 - "default-mobile.handlebars->11->545",
15649 - "default.handlebars->31->2157"
15670 + "default-mobile.handlebars->11->562",
15671 + "default.handlebars->31->2170"
15672 ]
15673 },
15674 {
@@ -15675,7 +15697,7 @@
15697 "nl": "Escape",
15698 "xloc": [
15699 "default-mobile.handlebars->11->320",
15678 - "default.handlebars->31->887"
15700 + "default.handlebars->31->900"
15701 ]
15702 },
15703 {
@@ -15695,7 +15717,7 @@
15717 "zh-chs": "世界文",
15718 "zh-cht": "世界語",
15719 "xloc": [
15698 - "default.handlebars->31->1182"
15720 + "default.handlebars->31->1195"
15721 ]
15722 },
15723 {
@@ -15715,7 +15737,7 @@
15737 "zh-chs": "爱沙尼亚文",
15738 "zh-cht": "愛沙尼亞語",
15739 "xloc": [
15718 - "default.handlebars->31->1183"
15740 + "default.handlebars->31->1196"
15741 ]
15742 },
15743 {
@@ -15735,7 +15757,7 @@
15757 "zh-chs": "事件详情",
15758 "zh-cht": "事件詳情",
15759 "xloc": [
15738 - "default.handlebars->31->999"
15760 + "default.handlebars->31->1012"
15761 ]
15762 },
15763 {
@@ -15755,7 +15777,7 @@
15777 "zh-chs": "事件列表输出",
15778 "zh-cht": "事件列表輸出",
15779 "xloc": [
15758 - "default.handlebars->31->1785"
15780 + "default.handlebars->31->1798"
15781 ]
15782 },
15783 {
@@ -15861,7 +15883,7 @@
15883 "zh-cht": "到期時間",
15884 "xloc": [
15885 "default.handlebars->31->203",
15864 - "default.handlebars->31->771"
15886 + "default.handlebars->31->784"
15887 ]
15888 },
15889 {
@@ -15943,7 +15965,7 @@
15965 "zh-chs": "扩充式ASCII",
15966 "zh-cht": "擴充式ASCII",
15967 "xloc": [
15946 - "default.handlebars->31->938",
15968 + "default.handlebars->31->951",
15969 "terminal.handlebars->3->16"
15970 ]
15971 },
@@ -15985,7 +16007,7 @@
16007 "zh-chs": "外部",
16008 "zh-cht": "外部",
16009 "xloc": [
15988 - "default.handlebars->31->2213"
16010 + "default.handlebars->31->2226"
16011 ]
16012 },
16013 {
@@ -16025,7 +16047,7 @@
16047 "zh-chs": "FYRO马其顿语",
16048 "zh-cht": "FYRO馬其頓語",
16049 "xloc": [
16028 - "default.handlebars->31->1233"
16050 + "default.handlebars->31->1246"
16051 ]
16052 },
16053 {
@@ -16045,7 +16067,7 @@
16067 "zh-chs": "法罗语",
16068 "zh-cht": "法羅語",
16069 "xloc": [
16048 - "default.handlebars->31->1184"
16070 + "default.handlebars->31->1197"
16071 ]
16072 },
16073 {
@@ -16073,8 +16095,8 @@
16095 "nl": "E-mailadres kan niet worden gewijzigd, een ander account gebruikt al: {0}.",
16096 "fr": "Échec de la modification de l'adresse e-mail, un autre compte utilise déjà: {0}.",
16097 "xloc": [
16076 - "default-mobile.handlebars->11->541",
16077 - "default.handlebars->31->2153"
16098 + "default-mobile.handlebars->11->558",
16099 + "default.handlebars->31->2166"
16100 ]
16101 },
16102 {
@@ -16094,7 +16116,7 @@
16116 "zh-chs": "本地用户拒绝后无法启动远程桌面",
16117 "zh-cht": "本地用戶拒絕後無法啟動遠程桌面",
16118 "xloc": [
16097 - "default.handlebars->31->1694"
16119 + "default.handlebars->31->1707"
16120 ]
16121 },
16122 {
@@ -16114,7 +16136,7 @@
16136 "zh-chs": "本地用户拒绝后无法启动远程文件",
16137 "zh-cht": "本地用戶拒絕後無法啟動遠程文件",
16138 "xloc": [
16117 - "default.handlebars->31->1701"
16139 + "default.handlebars->31->1714"
16140 ]
16141 },
16142 {
@@ -16135,7 +16157,7 @@
16157 "zh-cht": "無法啟動遠程終端接合{0}({1})",
16158 "xloc": [
16159 "default-mobile.handlebars->11->311",
16138 - "default.handlebars->31->866",
16160 + "default.handlebars->31->879",
16161 "desktop.handlebars->3->8",
16162 "terminal.handlebars->3->12"
16163 ]
@@ -16157,7 +16179,7 @@
16179 "zh-chs": "波斯文(波斯文)",
16180 "zh-cht": "波斯語(波斯語)",
16181 "xloc": [
16160 - "default.handlebars->31->1185"
16182 + "default.handlebars->31->1198"
16183 ]
16184 },
16185 {
@@ -16199,7 +16221,7 @@
16221 "zh-chs": "功能",
16222 "zh-cht": "功能",
16223 "xloc": [
16202 - "default.handlebars->31->1408"
16224 + "default.handlebars->31->1421"
16225 ]
16226 },
16227 {
@@ -16219,7 +16241,7 @@
16241 "zh-chs": "斐济",
16242 "zh-cht": "斐濟",
16243 "xloc": [
16222 - "default.handlebars->31->1186"
16244 + "default.handlebars->31->1199"
16245 ]
16246 },
16247 {
@@ -16261,7 +16283,7 @@
16283 "xloc": [
16284 "default-mobile.handlebars->11->360",
16285 "default.handlebars->31->533",
16264 - "default.handlebars->31->970"
16286 + "default.handlebars->31->983"
16287 ]
16288 },
16289 {
@@ -16297,8 +16319,8 @@
16319 "zh-chs": "档案操作",
16320 "zh-cht": "檔案操作",
16321 "xloc": [
16300 - "default.handlebars->31->950",
16301 - "default.handlebars->31->952"
16322 + "default.handlebars->31->963",
16323 + "default.handlebars->31->965"
16324 ]
16325 },
16326 {
@@ -16338,7 +16360,7 @@
16360 "zh-chs": "文件系统驱动",
16361 "zh-cht": "FileSystemDriver",
16362 "xloc": [
16341 - "default.handlebars->31->919"
16363 + "default.handlebars->31->932"
16364 ]
16365 },
16366 {
@@ -16360,8 +16382,8 @@
16382 "xloc": [
16383 "default-mobile.handlebars->11->182",
16384 "default-mobile.handlebars->11->279",
16363 - "default.handlebars->31->1498",
16364 - "default.handlebars->31->2112",
16385 + "default.handlebars->31->1511",
16386 + "default.handlebars->31->2125",
16387 "default.handlebars->31->276",
16388 "default.handlebars->container->topbar->1->1->MainSubMenuSpan->MainSubMenu->1->0->MainDevFiles",
16389 "default.handlebars->contextMenu->cxfiles"
@@ -16404,10 +16426,10 @@
16426 "zh-chs": "档案通知",
16427 "zh-cht": "檔案通知",
16428 "xloc": [
16407 - "default.handlebars->31->1416",
16408 - "default.handlebars->31->1930",
16409 - "default.handlebars->31->2017",
16410 - "default.handlebars->31->618"
16429 + "default.handlebars->31->1429",
16430 + "default.handlebars->31->1943",
16431 + "default.handlebars->31->2030",
16432 + "default.handlebars->31->631"
16433 ]
16434 },
16435 {
@@ -16427,10 +16449,10 @@
16449 "zh-chs": "档案提示",
16450 "zh-cht": "檔案提示",
16451 "xloc": [
16430 - "default.handlebars->31->1415",
16431 - "default.handlebars->31->1929",
16432 - "default.handlebars->31->2016",
16433 - "default.handlebars->31->617"
16452 + "default.handlebars->31->1428",
16453 + "default.handlebars->31->1942",
16454 + "default.handlebars->31->2029",
16455 + "default.handlebars->31->630"
16456 ]
16457 },
16458 {
@@ -16451,7 +16473,7 @@
16473 "zh-cht": "過濾",
16474 "xloc": [
16475 "default-mobile.handlebars->container->page_content->column_l->p2->xdevicesBar->1",
16454 - "default.handlebars->31->955",
16476 + "default.handlebars->31->968",
16477 "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar",
16478 "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->kvmListToolbar",
16479 "default.handlebars->container->column_l->p4->3->1->0->3->3"
@@ -16494,7 +16516,7 @@
16516 "zh-chs": "查找文件",
16517 "zh-cht": "查找文件",
16518 "xloc": [
16497 - "default.handlebars->31->958"
16519 + "default.handlebars->31->971"
16520 ]
16521 },
16522 {
@@ -16514,7 +16536,7 @@
16536 "zh-chs": "录制会话已完成,{0}秒",
16537 "zh-cht": "錄製會話已完成,{0}秒",
16538 "xloc": [
16517 - "default.handlebars->31->1667"
16539 + "default.handlebars->31->1680"
16540 ]
16541 },
16542 {
@@ -16534,7 +16556,16 @@
16556 "zh-chs": "芬兰",
16557 "zh-cht": "芬蘭",
16558 "xloc": [
16537 - "default.handlebars->31->1187"
16559 + "default.handlebars->31->1200"
16560 + ]
16561 + },
16562 + {
16563 + "en": "Firewall",
16564 + "xloc": [
16565 + "default-mobile.handlebars->11->393",
16566 + "default-mobile.handlebars->11->395",
16567 + "default.handlebars->31->615",
16568 + "default.handlebars->31->617"
16569 ]
16570 },
16571 {
@@ -16701,8 +16732,8 @@
16732 "zh-chs": "下次登录时强制重置密码。",
16733 "zh-cht": "下次登入時強制重置密碼。",
16734 "xloc": [
16704 - "default.handlebars->31->1868",
16705 - "default.handlebars->31->2059"
16735 + "default.handlebars->31->1881",
16736 + "default.handlebars->31->2072"
16737 ]
16738 },
16739 {
@@ -16785,7 +16816,7 @@
16816 "zh-chs": "格式化",
16817 "zh-cht": "格式化",
16818 "xloc": [
16788 - "default.handlebars->31->1776"
16819 + "default.handlebars->31->1789"
16820 ]
16821 },
16822 {
@@ -16826,8 +16857,8 @@
16857 "zh-chs": "自由",
16858 "zh-cht": "自由",
16859 "xloc": [
16829 - "default.handlebars->31->2171",
16830 - "default.handlebars->31->2173"
16860 + "default.handlebars->31->2184",
16861 + "default.handlebars->31->2186"
16862 ]
16863 },
16864 {
@@ -16868,7 +16899,7 @@
16899 "zh-chs": "法文(比利时)",
16900 "zh-cht": "法語(比利時)",
16901 "xloc": [
16871 - "default.handlebars->31->1189"
16902 + "default.handlebars->31->1202"
16903 ]
16904 },
16905 {
@@ -16888,7 +16919,7 @@
16919 "zh-chs": "法文(加拿大)",
16920 "zh-cht": "法語(加拿大)",
16921 "xloc": [
16891 - "default.handlebars->31->1190"
16922 + "default.handlebars->31->1203"
16923 ]
16924 },
16925 {
@@ -16908,7 +16939,7 @@
16939 "zh-chs": "法文(法国)",
16940 "zh-cht": "法語(法國)",
16941 "xloc": [
16911 - "default.handlebars->31->1191"
16942 + "default.handlebars->31->1204"
16943 ]
16944 },
16945 {
@@ -16928,7 +16959,7 @@
16959 "zh-chs": "法文(卢森堡)",
16960 "zh-cht": "法語(盧森堡)",
16961 "xloc": [
16931 - "default.handlebars->31->1192"
16962 + "default.handlebars->31->1205"
16963 ]
16964 },
16965 {
@@ -16948,7 +16979,7 @@
16979 "zh-chs": "法文(摩纳哥)",
16980 "zh-cht": "法語(摩納哥)",
16981 "xloc": [
16951 - "default.handlebars->31->1193"
16982 + "default.handlebars->31->1206"
16983 ]
16984 },
16985 {
@@ -16968,7 +16999,7 @@
16999 "zh-chs": "法文(标准)",
17000 "zh-cht": "法語(標準)",
17001 "xloc": [
16971 - "default.handlebars->31->1188"
17002 + "default.handlebars->31->1201"
17003 ]
17004 },
17005 {
@@ -16988,7 +17019,7 @@
17019 "zh-chs": "法文(瑞士)",
17020 "zh-cht": "法語(瑞士)",
17021 "xloc": [
16991 - "default.handlebars->31->1194"
17022 + "default.handlebars->31->1207"
17023 ]
17024 },
17025 {
@@ -17008,7 +17039,7 @@
17039 "zh-chs": "弗里斯兰文",
17040 "zh-cht": "弗里斯蘭語",
17041 "xloc": [
17011 - "default.handlebars->31->1195"
17042 + "default.handlebars->31->1208"
17043 ]
17044 },
17045 {
@@ -17028,7 +17059,7 @@
17059 "zh-chs": "弗留利",
17060 "zh-cht": "弗留利",
17061 "xloc": [
17031 - "default.handlebars->31->1196"
17062 + "default.handlebars->31->1209"
17063 ]
17064 },
17065 {
@@ -17049,12 +17080,12 @@
17080 "zh-cht": "完整管理員",
17081 "xloc": [
17082 "default-mobile.handlebars->11->116",
17052 - "default-mobile.handlebars->11->463",
17053 - "default-mobile.handlebars->11->472",
17054 - "default-mobile.handlebars->11->492",
17055 - "default.handlebars->31->1370",
17056 - "default.handlebars->31->1517",
17057 - "default.handlebars->31->1880"
17083 + "default-mobile.handlebars->11->480",
17084 + "default-mobile.handlebars->11->489",
17085 + "default-mobile.handlebars->11->509",
17086 + "default.handlebars->31->1383",
17087 + "default.handlebars->31->1530",
17088 + "default.handlebars->31->1893"
17089 ]
17090 },
17091 {
@@ -17074,7 +17105,7 @@
17105 "zh-chs": "完整管理员(保留所有权利)",
17106 "zh-cht": "完整管理員(保留所有權利)",
17107 "xloc": [
17077 - "default.handlebars->31->1553"
17108 + "default.handlebars->31->1566"
17109 ]
17110 },
17111 {
@@ -17111,7 +17142,7 @@
17142 "zh-chs": "完整设备权限",
17143 "zh-cht": "完整裝置權限",
17144 "xloc": [
17114 - "default.handlebars->31->700"
17145 + "default.handlebars->31->713"
17146 ]
17147 },
17148 {
@@ -17131,7 +17162,7 @@
17162 "zh-chs": "全部权限",
17163 "zh-cht": "全部權限",
17164 "xloc": [
17134 - "default.handlebars->31->718"
17165 + "default.handlebars->31->731"
17166 ]
17167 },
17168 {
@@ -17193,7 +17224,7 @@
17224 "zh-chs": "完整管理员",
17225 "zh-cht": "完整管理員",
17226 "xloc": [
17196 - "default.handlebars->31->1978"
17227 + "default.handlebars->31->1991"
17228 ]
17229 },
17230 {
@@ -17213,8 +17244,8 @@
17244 "zh-chs": "全自动的",
17245 "zh-cht": "全自動的",
17246 "xloc": [
17216 - "default.handlebars->31->1433",
17217 - "default.handlebars->31->1456"
17247 + "default.handlebars->31->1446",
17248 + "default.handlebars->31->1469"
17249 ]
17250 },
17251 {
@@ -17234,8 +17265,8 @@
17265 "zh-chs": "GPU",
17266 "zh-cht": "GPU",
17267 "xloc": [
17237 - "default-mobile.handlebars->11->439",
17238 - "default.handlebars->31->1067"
17268 + "default-mobile.handlebars->11->456",
17269 + "default.handlebars->31->1080"
17270 ]
17271 },
17272 {
@@ -17255,7 +17286,7 @@
17286 "zh-chs": "盖尔文(爱尔兰)",
17287 "zh-cht": "蓋爾語(愛爾蘭)",
17288 "xloc": [
17258 - "default.handlebars->31->1198"
17289 + "default.handlebars->31->1211"
17290 ]
17291 },
17292 {
@@ -17275,7 +17306,7 @@
17306 "zh-chs": "盖尔文(苏格兰文)",
17307 "zh-cht": "蓋爾語(蘇格蘭語)",
17308 "xloc": [
17278 - "default.handlebars->31->1197"
17309 + "default.handlebars->31->1210"
17310 ]
17311 },
17312 {
@@ -17295,7 +17326,7 @@
17326 "zh-chs": "加拉契文",
17327 "zh-cht": "加拉契語",
17328 "xloc": [
17298 - "default.handlebars->31->1199"
17329 + "default.handlebars->31->1212"
17330 ]
17331 },
17332 {
@@ -17421,7 +17452,7 @@
17452 "zh-chs": "格鲁吉亚文",
17453 "zh-cht": "格魯吉亞文",
17454 "xloc": [
17424 - "default.handlebars->31->1200"
17455 + "default.handlebars->31->1213"
17456 ]
17457 },
17458 {
@@ -17441,7 +17472,7 @@
17472 "zh-chs": "德文(奥地利)",
17473 "zh-cht": "德語(奧地利)",
17474 "xloc": [
17444 - "default.handlebars->31->1202"
17475 + "default.handlebars->31->1215"
17476 ]
17477 },
17478 {
@@ -17461,7 +17492,7 @@
17492 "zh-chs": "德文(德国)",
17493 "zh-cht": "德文(德國)",
17494 "xloc": [
17464 - "default.handlebars->31->1203"
17495 + "default.handlebars->31->1216"
17496 ]
17497 },
17498 {
@@ -17481,7 +17512,7 @@
17512 "zh-chs": "德文(列支敦士登)",
17513 "zh-cht": "德文(列支敦士登)",
17514 "xloc": [
17484 - "default.handlebars->31->1204"
17515 + "default.handlebars->31->1217"
17516 ]
17517 },
17518 {
@@ -17501,7 +17532,7 @@
17532 "zh-chs": "德文(卢森堡)",
17533 "zh-cht": "德語(盧森堡)",
17534 "xloc": [
17504 - "default.handlebars->31->1205"
17535 + "default.handlebars->31->1218"
17536 ]
17537 },
17538 {
@@ -17521,7 +17552,7 @@
17552 "zh-chs": "德文(标准)",
17553 "zh-cht": "德語(標準)",
17554 "xloc": [
17524 - "default.handlebars->31->1201"
17555 + "default.handlebars->31->1214"
17556 ]
17557 },
17558 {
@@ -17541,7 +17572,7 @@
17572 "zh-chs": "德文(瑞士)",
17573 "zh-cht": "德文(瑞士)",
17574 "xloc": [
17544 - "default.handlebars->31->1206"
17575 + "default.handlebars->31->1219"
17576 ]
17577 },
17578 {
@@ -17561,7 +17592,7 @@
17592 "zh-chs": "获取此设备的MQTT登录凭证。",
17593 "zh-cht": "獲取此裝置的MQTT登入憑證。",
17594 "xloc": [
17564 - "default.handlebars->31->669"
17595 + "default.handlebars->31->682"
17596 ]
17597 },
17598 {
@@ -17602,7 +17633,7 @@
17633 "zh-chs": "正在获取剪贴板内容,{0}个字节",
17634 "zh-cht": "正在獲取剪貼板內容,{0}個字節",
17635 "xloc": [
17605 - "default.handlebars->31->1681"
17636 + "default.handlebars->31->1694"
17637 ]
17638 },
17639 {
@@ -17664,7 +17695,7 @@
17695 "zh-chs": "好",
17696 "zh-cht": "好",
17697 "xloc": [
17667 - "default.handlebars->31->1366"
17698 + "default.handlebars->31->1379"
17699 ]
17700 },
17701 {
@@ -17709,8 +17740,8 @@
17740 "zh-chs": "Google云端硬盘备份",
17741 "zh-cht": "Google雲端硬盤備份",
17742 "xloc": [
17712 - "default.handlebars->31->1377",
17713 - "default.handlebars->31->1380",
17743 + "default.handlebars->31->1390",
17744 + "default.handlebars->31->1393",
17745 "default.handlebars->31->220"
17746 ]
17747 },
@@ -17731,7 +17762,7 @@
17762 "zh-chs": "Google云端硬盘控制台",
17763 "zh-cht": "Google雲端硬盤控制台",
17764 "xloc": [
17734 - "default.handlebars->31->1374"
17765 + "default.handlebars->31->1387"
17766 ]
17767 },
17768 {
@@ -17771,7 +17802,7 @@
17802 "zh-chs": "Google云端硬盘备份当前处于活动状态。",
17803 "zh-cht": "Google雲端硬盤備份當前處於活動狀態。",
17804 "xloc": [
17774 - "default.handlebars->31->1378"
17805 + "default.handlebars->31->1391"
17806 ]
17807 },
17808 {
@@ -17791,7 +17822,7 @@
17822 "zh-chs": "希腊文",
17823 "zh-cht": "希臘文",
17824 "xloc": [
17794 - "default.handlebars->31->1207"
17825 + "default.handlebars->31->1220"
17826 ]
17827 },
17828 {
@@ -17833,8 +17864,8 @@
17864 "zh-chs": "集体指令",
17865 "zh-cht": "集體指令",
17866 "xloc": [
17836 - "default.handlebars->31->1824",
17837 - "default.handlebars->31->1903",
17867 + "default.handlebars->31->1837",
17868 + "default.handlebars->31->1916",
17869 "default.handlebars->31->470",
17870 "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar",
17871 "default.handlebars->container->column_l->p4->3->1->0->3->3",
@@ -17858,7 +17889,7 @@
17889 "zh-chs": "通过...分组",
17890 "zh-cht": "通過...分群",
17891 "xloc": [
17861 - "default.handlebars->31->1772"
17892 + "default.handlebars->31->1785"
17893 ]
17894 },
17895 {
@@ -17878,7 +17909,7 @@
17909 "zh-chs": "组标识符",
17910 "zh-cht": "群標識符",
17911 "xloc": [
17881 - "default.handlebars->31->1920"
17912 + "default.handlebars->31->1933"
17913 ]
17914 },
17915 {
@@ -17898,7 +17929,7 @@
17929 "zh-chs": "群组成员",
17930 "zh-cht": "群組成員",
17931 "xloc": [
17901 - "default.handlebars->31->1941"
17932 + "default.handlebars->31->1954"
17933 ]
17934 },
17935 {
@@ -17918,7 +17949,7 @@
17949 "zh-chs": "用户{0}的群组权限。",
17950 "zh-cht": "用戶{0}的群組權限。",
17951 "xloc": [
17921 - "default.handlebars->31->1516"
17952 + "default.handlebars->31->1529"
17953 ]
17954 },
17955 {
@@ -17938,7 +17969,7 @@
17969 "zh-chs": "{0}的群组权限。",
17970 "zh-cht": "{0}的群組權限。",
17971 "xloc": [
17941 - "default.handlebars->31->1515"
17972 + "default.handlebars->31->1528"
17973 ]
17974 },
17975 {
@@ -18019,7 +18050,7 @@
18050 "zh-cht": "來賓姓名",
18051 "xloc": [
18052 "default.handlebars->31->198",
18022 - "default.handlebars->31->748"
18053 + "default.handlebars->31->761"
18054 ]
18055 },
18056 {
@@ -18039,7 +18070,7 @@
18070 "zh-chs": "古久拉提",
18071 "zh-cht": "古久拉提",
18072 "xloc": [
18042 - "default.handlebars->31->1208"
18073 + "default.handlebars->31->1221"
18074 ]
18075 },
18076 {
@@ -18082,7 +18113,7 @@
18113 "zh-chs": "海地文",
18114 "zh-cht": "海地文",
18115 "xloc": [
18085 - "default.handlebars->31->1209"
18116 + "default.handlebars->31->1222"
18117 ]
18118 },
18119 {
@@ -18122,7 +18153,7 @@
18153 "zh-chs": "强行断开代理",
18154 "zh-cht": "強行斷開代理",
18155 "xloc": [
18125 - "default.handlebars->31->1097"
18156 + "default.handlebars->31->1110"
18157 ]
18158 },
18159 {
@@ -18142,7 +18173,7 @@
18173 "zh-chs": "堆总数",
18174 "zh-cht": "堆總數",
18175 "xloc": [
18145 - "default.handlebars->31->2215"
18176 + "default.handlebars->31->2228"
18177 ]
18178 },
18179 {
@@ -18162,7 +18193,7 @@
18193 "zh-chs": "堆使用",
18194 "zh-cht": "堆使用",
18195 "xloc": [
18165 - "default.handlebars->31->2214"
18196 + "default.handlebars->31->2227"
18197 ]
18198 },
18199 {
@@ -18182,7 +18213,7 @@
18213 "zh-chs": "希伯来文",
18214 "zh-cht": "希伯來文",
18215 "xloc": [
18185 - "default.handlebars->31->1210"
18216 + "default.handlebars->31->1223"
18217 ]
18218 },
18219 {
@@ -18243,7 +18274,7 @@
18274 "zh-chs": "已请求帮助,用户:{0},详细信息:{1}",
18275 "zh-cht": "已請求幫助,用戶:{0},詳細信息:{1}",
18276 "xloc": [
18246 - "default.handlebars->31->1758"
18277 + "default.handlebars->31->1771"
18278 ]
18279 },
18280 {
@@ -18304,7 +18335,7 @@
18335 "zh-chs": "帮助翻译MeshCentral",
18336 "zh-cht": "幫助翻譯MeshCentral",
18337 "xloc": [
18307 - "default.handlebars->31->1325"
18338 + "default.handlebars->31->1338"
18339 ]
18340 },
18341 {
@@ -18408,7 +18439,7 @@
18439 "zh-chs": "印地文",
18440 "zh-cht": "印地文",
18441 "xloc": [
18411 - "default.handlebars->31->1211"
18442 + "default.handlebars->31->1224"
18443 ]
18444 },
18445 {
@@ -18446,7 +18477,7 @@
18477 "zh-cht": "保存1個項目進行複製",
18478 "xloc": [
18479 "default-mobile.handlebars->11->369",
18449 - "default.handlebars->31->980"
18480 + "default.handlebars->31->993"
18481 ]
18482 },
18483 {
@@ -18467,7 +18498,7 @@
18498 "zh-cht": "保存1個項目進行移動",
18499 "xloc": [
18500 "default-mobile.handlebars->11->373",
18470 - "default.handlebars->31->984"
18501 + "default.handlebars->31->997"
18502 ]
18503 },

This file is too large to show in full.

views/default-mobile.handlebars
+33 -4
@@ -1579,6 +1579,8 @@
1579 if (message.event.node.intelamt.flags != null) { node.intelamt.flags = message.event.node.intelamt.flags; }
1580 if (message.event.node.intelamt.warn != null) { node.intelamt.warn = message.event.node.intelamt.warn; } else { delete node.intelamt.warn; }
1581 }
1582 + if (message.event.node.av != null) { node.av = message.event.node.av; }
1583 + if (message.event.node.wsc != null) { node.wsc = message.event.node.wsc; }
1584 node.namel = node.name.toLowerCase();
1585 if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
1586 if (message.event.node.icon) { node.icon = message.event.node.icon; }
@@ -1588,6 +1590,7 @@
1590 refreshDevice(node._id);
1591 //updateMapMarkers();
1592 updateDevices();
1593 + if (currentNode == node) { updateDeviceDetails(); }
1594
1595 //if ((currentNode == node) && (xxdialogMode != null) && (xxdialogTag == '@xxmap')) { p10showNodeLocationDialog(); }
1596 }
@@ -4293,6 +4296,32 @@
4296 var m = hardware.windows.osinfo;
4297 if (m.OSArchitecture) { x += addDetailItem("Architecture", EscapeHtml(m.OSArchitecture), s); }
4298 }
4299 +
4300 + // Windows Security Central
4301 + if (node.wsc) {
4302 + var y = [];
4303 + if (node.wsc.antiVirus != null) { if (node.wsc.antiVirus == 'OK') { y.push("AV" + ' - <span style=color:green>' + "OK" + '</span>'); } else { y.push("AV" + ' - <span style=color:red>' + "BAD" + '</span>'); } }
4304 + if (node.wsc.autoUpdate != null) { if (node.wsc.autoUpdate == 'OK') { y.push("Update" + ' - <span style=color:green>' + "OK" + '</span>'); } else { y.push("Update" + ' - <span style=color:red>' + "BAD" + '</span>'); } }
4305 + if (node.wsc.firewall != null) { if (node.wsc.firewall == 'OK') { y.push("Firewall" + ' - <span style=color:green>' + "OK" + '</span>'); } else { y.push("Firewall" + ' - <span style=color:red>' + "BAD" + '</span>'); } }
4306 + x += addDetailItem("Windows Security", y.join(', '));
4307 + }
4308 +
4309 + // Antivirus
4310 + if (node.av && node.av.length > 0) {
4311 + var y = [];
4312 + for (var i in node.av) {
4313 + if (node.av[i].product) {
4314 + var avx = EscapeHtml(node.av[i].product);
4315 + if (node.av[i].enabled !== true) { avx += ' - <span style=color:red>' + "Disabled" + '</span>'; }
4316 + if (node.av[i].updated !== true) { avx += ' - <span style=color:red>' + "Out of date" + '</span>'; }
4317 + if ((node.av[i].enabled == true) && (node.av[i].updated == true)) { avx += ' - <span style=color:green>' + "OK" + '</span>'; }
4318 + y.push(avx);
4319 + }
4320 + }
4321 + x += addDetailItem("Antivirus", y.join('<br />'));
4322 + }
4323 +
4324 +
4325 if (x != '') { sections.push({ name: "Operating System", html: x, img: 'software' }); }
4326 }
4327
@@ -4361,16 +4390,16 @@
4390 var iplayer = m[j];
4391 if (iplayer.family == 'IPv4') {
4392 if (iplayer.gateway && iplayer.netmask) {
4364 - x += addDetailItem("IPv4 Layer", format("IP: {0}, Mask: {1}, Gateway: {2}", EscapeHtml(iplayer.address), EscapeHtml(iplayer.netmask), EscapeHtml(iplayer.gateway)));
4393 + x += addDetailItem("IPv4 Layer", format("{0}, Mask: {1}, Gateway: {2}", EscapeHtml(iplayer.address), EscapeHtml(iplayer.netmask), EscapeHtml(iplayer.gateway)));
4394 } else {
4366 - x += addDetailItem("IPv4 Layer", format("IP: {0}", EscapeHtml(iplayer.address)));
4395 + x += addDetailItem("IPv4 Layer", format("{0}", EscapeHtml(iplayer.address)));
4396 }
4397 }
4398 if (iplayer.family == 'IPv6') {
4399 if (iplayer.gateway && iplayer.netmask) {
4371 - x += addDetailItem("IPv6 Layer", format("IP: {0}, Mask: {1}, Gateway: {2}", EscapeHtml(iplayer.address), EscapeHtml(iplayer.netmask), EscapeHtml(iplayer.gateway)));
4400 + x += addDetailItem("IPv6 Layer", format("{0}, Mask: {1}, Gateway: {2}", EscapeHtml(iplayer.address), EscapeHtml(iplayer.netmask), EscapeHtml(iplayer.gateway)));
4401 } else {
4373 - x += addDetailItem("IPv6 Layer", format("IP: {0}", EscapeHtml(iplayer.address)));
4402 + x += addDetailItem("IPv6 Layer", format("{0}", EscapeHtml(iplayer.address)));
4403 }
4404 }
4405 }
views/default.handlebars
+13 -1
@@ -2866,6 +2866,7 @@
2866 if (message.event.node.intelamt.warn != null) { node.intelamt.warn = message.event.node.intelamt.warn; } else { delete node.intelamt.warn; }
2867 }
2868 if (message.event.node.av != null) { node.av = message.event.node.av; }
2869 + if (message.event.node.wsc != null) { node.wsc = message.event.node.wsc; }
2870 node.namel = node.name.toLowerCase();
2871 if (node.rname) { node.rnamel = node.rname.toLowerCase(); } else { node.rnamel = node.namel; }
2872 if (message.event.node.icon) { node.icon = message.event.node.icon; }
@@ -4358,7 +4359,9 @@
4359 if (xxdialogMode) return false;
4360 var mesh = meshes[meshid], x = '', installType = 0, moreoptions = '';
4361
4361 - var opts = '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>' + "Windows" + '</option><option value=1>' + "Linux / BSD" + '</option><option value=5>' + "Linux / BSD / macOS Binary Installer" + '</option><option value=2>' + "Apple macOS" + '</option><option value=6>' + "Mobile device" + '</option><option value=3>' + "Windows (UnInstall)" + '</option><option value=4>' + "Linux / BSD (UnInstall)" + '</option></select>';
4362 + var opts = '<select id=aginsSelect onchange=addAgentToMeshClick() style=width:236px><option value=0>' + "Windows" + '</option><option value=1>' + "Linux / BSD" + '</option><option value=5>' + "Linux / BSD / macOS Binary Installer" + '</option><option value=2>' + "Apple macOS" + '</option>';
4363 + if ((features & 2) == 0) { opts += '<option value=6>' + "Mobile device" + '</option>'; } // Don't display mobile setup in LAN mode.
4364 + opts += '<option value=3>' + "Windows (UnInstall)" + '</option><option value=4>' + "Linux / BSD (UnInstall)" + '</option></select>';
4365 x += addHtmlValue("Operating System", opts);
4366
4367 var servername = serverinfo.name;
@@ -5901,6 +5904,15 @@
5904 // Operating system description
5905 if (node.osdesc) { x += addDeviceAttribute("Operating System", node.osdesc); }
5906
5907 + // Windows Security Central
5908 + if (node.wsc) {
5909 + var y = [];
5910 + if (node.wsc.antiVirus != null) { if (node.wsc.antiVirus == 'OK') { y.push("AV" + ' - <span style=color:green>' + "OK" + '</span>'); } else { y.push("AV" + ' - <span style=color:red>' + "BAD" + '</span>'); } }
5911 + if (node.wsc.autoUpdate != null) { if (node.wsc.autoUpdate == 'OK') { y.push("Update" + ' - <span style=color:green>' + "OK" + '</span>'); } else { y.push("Update" + ' - <span style=color:red>' + "BAD" + '</span>'); } }
5912 + if (node.wsc.firewall != null) { if (node.wsc.firewall == 'OK') { y.push("Firewall" + ' - <span style=color:green>' + "OK" + '</span>'); } else { y.push("Firewall" + ' - <span style=color:red>' + "BAD" + '</span>'); } }
5913 + x += addDeviceAttribute("Windows Security", y.join(', '));
5914 + }
5915 +
5916 // Antivirus
5917 if (node.av && node.av.length > 0) {
5918 var y = [];