Refactor for #2868

Ylian Saint-Hilaire committed Jul 7, 2021 at 19:22 UTC 591d73cf64866b4571f0892e5c1633643ea5ba3e
1 file changed +646 -546
meshuser.js
+646 -546
@@ -911,552 +911,8 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
911 const cmd = cmdargs[0].toLowerCase();
912 cmdargs = parseArgs(cmdargs);
913
914 - switch (cmd) {
915 - case 'help': {
916 - var fin = '', f = '', availcommands = 'help,maintenance,info,versions,resetserver,usersessions,closeusersessions,tasklimiter,setmaxtasks,cores,migrationagents,agentstats,agentissues,webstats,trafficstats,trafficdelta,mpsstats,swarmstats,acceleratorsstats,updatecheck,serverupdate,nodeconfig,heapdump,relays,autobackup,backupconfig,dupagents,dispatchtable,badlogins,showpaths,le,lecheck,leevents,dbstats,dbcounters,sms,amtacm,certhashes,watchdog,amtmanager,amtpasswords,certexpire,email';
917 - if (parent.parent.config.settings.heapdump === true) { availcommands += ',heapdump'; }
918 - availcommands = availcommands.split(',').sort();
919 - while (availcommands.length > 0) { if (f.length > 80) { fin += (f + ',\r\n'); f = ''; } f += (((f != '') ? ', ' : ' ') + availcommands.shift()); }
920 - if (f != '') { fin += f; }
921 - if (cmdargs['_'].length == 0) {
922 - r = 'Available commands: \r\n' + fin + '\r\nType help <command> for details.';
923 - } else {
924 - var cmd2 = cmdargs['_'][0].toLowerCase();
925 - switch (cmd2) {
926 - case 'info': { r = "info: Returns the most immidiatly useful information about this server, including MeshCentral and NodeJS versions. This is often information required to file a bug."; break; }
927 - case 'versions': { r = "versions: Returns all internal versions for NodeJS running this server."; break; }
928 - case 'resetserver': { r = "resetserver: Causes the server to reset, this is sometimes useful is the config.json file was changed."; break; }
929 - case 'usersessions': { r = "usersessions: Returns a list of active sessions grouped by user."; break; }
930 - case 'closeusersessions': { r = "closeusersessions: Disconnects all sessions for a specified user."; break; }
931 - case 'tasklimiter': { r = "tasklimiter: Returns the internal status of the tasklimiter. This is a system used to smooth out work done by the server. It's used by, for example, agent updates so that not all agents are updated at the same time."; break; }
932 - case 'serverupdate': { r = "serverupdate: Updates server to latest version. Optional version argument to install specific version. Example: serverupdate 0.8.49"; break; }
933 - default: { r = 'No help information about this command.'; break; }
934 - }
935 - }
936 - break;
937 - }
938 - case 'certexpire': {
939 - const now = Date.now();
940 - for (var i in parent.webCertificateExpire) {
941 - const domainName = (i == '') ? '[Default]' : i;
942 - r += domainName + ', expires in ' + Math.floor((parent.webCertificateExpire[i] - now) / 86400000) + ' day(s)\r\n';
943 - }
944 - break;
945 - }
946 - case 'webpush': {
947 - if (parent.parent.webpush == null) {
948 - r = "Web push not supported.";
949 - } else {
950 - if (cmdargs['_'].length != 1) {
951 - r = "Usage: WebPush \"Message\"";
952 - } else {
953 - const pushSubscription = { "endpoint": "https://updates.push.services.mozilla.com/wpush/v2/gAAAAABgIkO9hjXHWhMPiuk-ppNRw7r_pUZitddwCEK4ykdzeIxOIjFnYhIt_nr-qUca2mpZziwQsSEhYTUCiuYrhWnVDRweMtiUj16yJJq8V5jneaEaUYjEIe5jp3DOMNpoTm1aHgX74gCR8uTXSITcM97bNi-hRxcQ4f6Ie4WSAmoXpd89B_g", "keys": { "auth": "UB2sbLVK7ALnSHw5P1dahg", "p256dh": "BIoRbcNSxBuTjN39CCCUCHo1f4NxBJ1YDdu_k4MbPW_q3NK1_RufnydUzLPDp8ibBVItSI72-s48QJvOjQ_S8Ok" } }
954 - parent.parent.webpush.sendNotification(pushSubscription, cmdargs['_'][0]).then(
955 - function (value) { try { ws.send(JSON.stringify({ action: 'OK', value: r, tag: command.tag })); } catch (ex) { } },
956 - function (error) { try { ws.send(JSON.stringify({ action: 'Error', value: r, tag: command.tag })); } catch (ex) { } }
957 - );
958 - }
959 - }
960 - break;
961 - }
962 - case 'amtmanager': {
963 - if (parent.parent.amtManager == null) { r = 'Intel AMT Manager not active.'; } else { r = parent.parent.amtManager.getStatusString(); }
964 - break;
965 - }
966 - case 'certhashes': {
967 - r += 'AgentCertHash: ' + parent.agentCertificateHashHex;
968 - for (var i in parent.webCertificateHashs) { r += '\r\nwebCertificateHash (' + i + '): ' + common.rstr2hex(parent.webCertificateHashs[i]); }
969 - for (var i in parent.webCertificateFullHashs) { r += '\r\nwebCertificateFullHash (' + i + '): ' + common.rstr2hex(parent.webCertificateFullHashs[i]); }
970 - r += '\r\ndefaultWebCertificateHash: ' + common.rstr2hex(parent.defaultWebCertificateHash);
971 - r += '\r\ndefaultWebCertificateFullHash: ' + common.rstr2hex(parent.defaultWebCertificateFullHash);
972 - break;
973 - }
974 - case 'amtacm': {
975 - if ((domain.amtacmactivation == null) || (domain.amtacmactivation.acmmatch == null) || (domain.amtacmactivation.acmmatch.length == 0)) {
976 - r = 'No Intel AMT activation certificates.';
977 - } else {
978 - if (domain.amtacmactivation.log != null) { r += '--- Activation Log ---\r\nFile : ' + domain.amtacmactivation.log + '\r\n'; }
979 - for (var i in domain.amtacmactivation.acmmatch) {
980 - var acmcert = domain.amtacmactivation.acmmatch[i];
981 - r += '--- Activation Certificate ' + (parseInt(i) + 1) + ' ---\r\nName : ' + acmcert.cn + '\r\nSHA1 : ' + acmcert.sha1 + '\r\nSHA256: ' + acmcert.sha256 + '\r\n';
982 - }
983 - }
984 - break;
985 - }
986 - case 'heapdump': {
987 - // Heapdump support, see example at:
988 - // https://www.arbazsiddiqui.me/a-practical-guide-to-memory-leaks-in-nodejs/
989 - if (parent.parent.config.settings.heapdump === true) {
990 - var dumpFileName = parent.path.join(parent.parent.datapath, `heapDump-${Date.now()}.heapsnapshot`);
991 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: "Generating dump file at: " + dumpFileName, tag: command.tag })); } catch (ex) { }
992 - require('heapdump').writeSnapshot(dumpFileName, (err, filename) => {
993 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: "Done.", tag: command.tag })); } catch (ex) { }
994 - });
995 - } else {
996 - r = "Heapdump not supported, add \"heapdump\":true to settings section of config.json.";
997 - }
998 - break;
999 - }
1000 - case 'sms': {
1001 - if (parent.parent.smsserver == null) {
1002 - r = "No SMS gateway in use.";
1003 - } else {
1004 - if (cmdargs['_'].length != 2) {
1005 - r = "Usage: SMS \"PhoneNumber\" \"Message\".";
1006 - } else {
1007 - parent.parent.smsserver.sendSMS(cmdargs['_'][0], cmdargs['_'][1], function (status, msg) {
1008 - if (typeof msg == 'string') {
1009 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: status ? ('Success: ' + msg) : ('Failed: ' + msg), tag: command.tag })); } catch (ex) { }
1010 - } else {
1011 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: status ? 'Success' : 'Failed', tag: command.tag })); } catch (ex) { }
1012 - }
1013 - });
1014 - }
1015 - }
1016 - break;
1017 - }
1018 - case 'email': {
1019 - if (domain.mailserver == null) {
1020 - r = "No email service enabled.";
1021 - } else {
1022 - if (cmdargs['_'].length != 3) {
1023 - r = "Usage: email \"user@sample.com\" \"Subject\" \"Message\".";
1024 - } else {
1025 - domain.mailserver.sendMail(cmdargs['_'][0], cmdargs['_'][1], cmdargs['_'][2]);
1026 - r = "Done.";
1027 - }
1028 - }
1029 - break;
1030 - }
1031 - case 'le': {
1032 - if (parent.parent.letsencrypt == null) {
1033 - r = "Let's Encrypt not in use.";
1034 - } else {
1035 - r = JSON.stringify(parent.parent.letsencrypt.getStats(), null, 4);
1036 - }
1037 - break;
1038 - }
1039 - case 'lecheck': {
1040 - if (parent.parent.letsencrypt == null) {
1041 - r = "Let's Encrypt not in use.";
1042 - } else {
1043 - r = ["CertOK", "Request:NoCert", "Request:Expire", "Request:MissingNames"][parent.parent.letsencrypt.checkRenewCertificate()];
1044 - }
1045 - break;
1046 - }
1047 - case 'leevents': {
1048 - if (parent.parent.letsencrypt == null) {
1049 - r = "Let's Encrypt not in use.";
1050 - } else {
1051 - r = parent.parent.letsencrypt.events.join('\r\n');
1052 - }
1053 - break;
1054 - }
1055 - case 'badlogins': {
1056 - if (parent.parent.config.settings.maxinvalidlogin == false) {
1057 - r = 'Bad login filter is disabled.';
1058 - } else {
1059 - if (cmdargs['_'] == 'reset') {
1060 - // Reset bad login table
1061 - parent.badLoginTable = {};
1062 - parent.badLoginTableLastClean = 0;
1063 - r = 'Done.'
1064 - } else if (cmdargs['_'] == '') {
1065 - // Show current bad login table
1066 - if (typeof parent.parent.config.settings.maxinvalidlogin.coolofftime == 'number') {
1067 - r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s), " + parent.parent.config.settings.maxinvalidlogin.coolofftime + " minute(s) cooloff.\r\n";
1068 - } else {
1069 - r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s).\r\n";
1070 - }
1071 - var badLoginCount = 0;
1072 - parent.cleanBadLoginTable();
1073 - for (var i in parent.badLoginTable) {
1074 - badLoginCount++;
1075 - if (typeof parent.badLoginTable[i] == 'number') {
1076 - r += "Cooloff for " + Math.floor((parent.badLoginTable[i] - Date.now()) / 60000) + " minute(s)\r\n";
1077 - } else {
1078 - if (parent.badLoginTable[i].length > 1) {
1079 - r += (i + ' - ' + parent.badLoginTable[i].length + " records\r\n");
1080 - } else {
1081 - r += (i + ' - ' + parent.badLoginTable[i].length + " record\r\n");
1082 - }
1083 - }
1084 - }
1085 - if (badLoginCount == 0) { r += 'No bad logins.'; }
1086 - } else {
1087 - r = 'Usage: badlogin [reset]';
1088 - }
1089 - }
1090 - break;
1091 - }
1092 - case 'dispatchtable': {
1093 - r = '';
1094 - for (var i in parent.parent.eventsDispatch) { r += (i + ', ' + parent.parent.eventsDispatch[i].length + '\r\n'); }
1095 - break;
1096 - }
1097 - case 'dupagents': {
1098 - for (var i in parent.duplicateAgentsLog) { r += JSON.stringify(parent.duplicateAgentsLog[i]) + '\r\n'; }
1099 - if (r == '') { r = 'No duplicate agents in log.'; }
1100 - break;
1101 - }
1102 - case 'agentstats': {
1103 - var stats = parent.getAgentStats();
1104 - for (var i in stats) {
1105 - if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
1106 - }
1107 - break;
1108 - }
1109 - case 'agentissues': {
1110 - var stats = parent.getAgentIssues();
1111 - if (stats.length == 0) {
1112 - r = "No agent issues.";
1113 - } else {
1114 - for (var i in stats) { r += stats[i].join(', ') + '\r\n'; }
1115 - }
1116 - break;
1117 - }
1118 - case 'webstats': {
1119 - var stats = parent.getStats();
1120 - for (var i in stats) {
1121 - if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
1122 - }
1123 - break;
1124 - }
1125 - case 'trafficstats': {
1126 - var stats = parent.getTrafficStats();
1127 - for (var i in stats) {
1128 - if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
1129 - }
1130 - break;
1131 - }
1132 - case 'trafficdelta': {
1133 - const stats = parent.getTrafficDelta(obj.trafficStats);
1134 - obj.trafficStats = stats.current;
1135 - for (var i in stats.delta) {
1136 - if (typeof stats.delta[i] == 'object') { r += (i + ': ' + JSON.stringify(stats.delta[i]) + '\r\n'); } else { r += (i + ': ' + stats.delta[i] + '\r\n'); }
1137 - }
1138 - break;
1139 - }
1140 - case 'watchdog': {
1141 - if (parent.parent.watchdog == null) {
1142 - r = 'Server watchdog not active.';
1143 - } else {
1144 - r = 'Server watchdog active.\r\n';
1145 - if (parent.parent.watchdogmaxtime != null) { r += 'Largest timeout was ' + parent.parent.watchdogmax + 'ms on ' + parent.parent.watchdogmaxtime + '\r\n'; }
1146 - for (var i in parent.parent.watchdogtable) { r += parent.parent.watchdogtable[i] + '\r\n'; }
1147 - }
1148 - break;
1149 - }
1150 - case 'acceleratorsstats': {
1151 - var stats = parent.parent.certificateOperations.getAcceleratorStats();
1152 - for (var i in stats) {
1153 - if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
1154 - }
1155 - break;
1156 - }
1157 - case 'mpsstats': {
1158 - if (parent.parent.mpsserver == null) {
1159 - r = 'MPS not enabled.';
1160 - } else {
1161 - var stats = parent.parent.mpsserver.getStats();
1162 - for (var i in stats) {
1163 - if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
1164 - }
1165 - }
1166 - break;
1167 - }
1168 - case 'mps': { // List all MPS connections and types.
1169 - if (parent.parent.mpsserver == null) {
1170 - r = 'MPS not enabled.';
1171 - } else {
1172 - const connectionTypes = ['CIRA', 'Relay', 'LMS'];
1173 - for (var nodeid in parent.parent.mpsserver.ciraConnections) {
1174 - r += nodeid;
1175 - var connections = parent.parent.mpsserver.ciraConnections[nodeid];
1176 - for (var i in connections) { r += ', ' + connectionTypes[connections[i].tag.connType]; }
1177 - r += '\r\n';
1178 - }
1179 - if (r == '') { r = 'MPS has not connections.'; }
1180 - }
1181 - break;
1182 - }
1183 - case 'dbstats': {
1184 - parent.parent.db.getStats(function (stats) {
1185 - var r2 = '';
1186 - for (var i in stats) { r2 += (i + ': ' + stats[i] + '\r\n'); }
1187 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: r2, tag: command.tag })); } catch (ex) { }
1188 - });
1189 - break;
1190 - }
1191 - case 'dbcounters': {
1192 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: JSON.stringify(parent.parent.db.dbCounters, null, 2), tag: command.tag })); } catch (ex) { }
1193 - break;
1194 - }
1195 - case 'serverupdate': {
1196 - r = 'Performing server update...';
1197 - var version = null;
1198 -
1199 - if (cmdargs['_'].length > 0) {
1200 - version = cmdargs['_'][0];
1201 -
1202 - // This call is SLOW. We only want to validate version if we have to
1203 - if (version != 'stable' && version != 'latest') {
1204 - parent.parent.getServerVersions((data) => {
1205 - var versions = JSON.parse(data);
1206 -
1207 - if (versions.includes(version)) {
1208 - if (parent.parent.performServerUpdate(version) == false) {
1209 - try {
1210 - ws.send(JSON.stringify({ action: 'serverconsole',
1211 - value: 'Server self-update not possible.'}));
1212 - } catch (ex) { }
1213 - }
1214 - } else {
1215 - try {
1216 - ws.send(JSON.stringify({ action: 'serverconsole',
1217 - value: 'Invalid version. Aborting update'}));
1218 - } catch (ex) { }
1219 - }
1220 - });
1221 - } else {
1222 - if (parent.parent.performServerUpdate(version) == false) {
1223 - r = 'Server self-update not possible.';
1224 - }
1225 - }
1226 - } else {
1227 - if (parent.parent.performServerUpdate(version) == false) {
1228 - r = 'Server self-update not possible.';
1229 - }
1230 - }
1231 -
1232 - break;
1233 - }
1234 - case 'print': {
1235 - console.log(cmdargs['_'][0]);
1236 - break;
1237 - }
1238 - case 'amtpasswords': {
1239 - if (parent.parent.amtPasswords == null) {
1240 - r = "No Intel AMT password table."
1241 - } else {
1242 - for (var i in parent.parent.amtPasswords) { r += (i + ' - ' + parent.parent.amtPasswords[i].join(', ') + '\r\n'); }
1243 - }
1244 - break;
1245 - }
1246 - case 'updatecheck': {
1247 - parent.parent.getServerTags(function (tags, error) {
1248 - var r2 = '';
1249 - if (error != null) { r2 += 'Exception: ' + error + '\r\n'; }
1250 - else { for (var i in tags) { r2 += i + ': ' + tags[i] + '\r\n'; } }
1251 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: r2, tag: command.tag })); } catch (ex) { }
1252 - });
1253 - r = "Checking server update...";
1254 - break;
1255 - }
1256 - case 'maintenance': {
1257 - var arg = null, changed = false;
1258 - if ((cmdargs['_'] != null) && (cmdargs['_'][0] != null)) { arg = cmdargs['_'][0].toLowerCase(); }
1259 - if (arg == 'enabled') { parent.parent.config.settings.maintenancemode = 1; changed = true; }
1260 - else if (arg == 'disabled') { delete parent.parent.config.settings.maintenancemode; changed = true; }
1261 - r = 'Maintenance mode: ' + ((parent.parent.config.settings.maintenancemode == null) ? 'Disabled' : 'Enabled');
1262 - if (changed == false) { r += '\r\nTo change type: maintenance [enabled|disabled]'; }
1263 - break;
1264 - }
1265 - case 'info': {
1266 - var info = process.memoryUsage();
1267 - info.dbType = ['None', 'NeDB', 'MongoJS', 'MongoDB'][parent.db.databaseType];
1268 - try { if (parent.parent.multiServer != null) { info.serverId = parent.parent.multiServer.serverid; } } catch (ex) { }
1269 - if (parent.db.databaseType == 3) { info.dbChangeStream = parent.db.changeStream; }
1270 - if (parent.parent.pluginHandler != null) { info.plugins = []; for (var i in parent.parent.pluginHandler.plugins) { info.plugins.push(i); } }
1271 - try { info.nodeVersion = process.version; } catch (ex) { }
1272 - try { info.meshVersion = parent.parent.currentVer; } catch (ex) { }
1273 - try { info.platform = process.platform; } catch (ex) { }
1274 - try { info.arch = process.arch; } catch (ex) { }
1275 - try { info.pid = process.pid; } catch (ex) { }
1276 - try { info.uptime = process.uptime(); } catch (ex) { }
1277 - try { info.cpuUsage = process.cpuUsage(); } catch (ex) { }
1278 - try { info.warnings = parent.parent.getServerWarnings(); } catch (ex) { }
1279 - try { info.database = ["Unknown", "NeDB", "MongoJS", "MongoDB", "MariaDB", "MySQL"][parent.parent.db.databaseType]; } catch (ex) { }
1280 - try { info.productionMode = ((process.env.NODE_ENV != null) && (process.env.NODE_ENV == 'production')); } catch (ex) { }
1281 - try { info.allDevGroupManagers = parent.parent.config.settings.managealldevicegroups; } catch (ex) { }
1282 - r = JSON.stringify(info, null, 4);
1283 - break;
1284 - }
1285 - case 'nodeconfig': {
1286 - r = JSON.stringify(process.config, null, 4);
1287 - break;
1288 - }
1289 - case 'versions': {
1290 - r = JSON.stringify(process.versions, null, 4);
1291 - break;
1292 - }
1293 - case 'args': {
1294 - r = cmd + ': ' + JSON.stringify(cmdargs);
1295 - break;
1296 - }
1297 - case 'usersessions': {
1298 - var userSessionCount = 0;
1299 - var filter = null;
1300 - var arg = cmdargs['_'][0];
1301 - if (typeof arg == 'string') { if (arg.indexOf('/') >= 0) { filter = arg; } else { filter = ('user/' + domain.id + '/' + arg); } }
1302 - for (var i in parent.wssessions) {
1303 - if ((filter == null) || (filter == i)) {
1304 - userSessionCount++;
1305 - r += (i + ', ' + parent.wssessions[i].length + ' session' + ((parent.wssessions[i].length > 1) ? 's' : '') + '.\r\n');
1306 - for (var j in parent.wssessions[i]) {
1307 - r += ' ' + parent.wssessions[i][j].clientIp + ' --> ' + parent.wssessions[i][j].sessionId + '\r\n';
1308 - }
1309 - }
1310 - }
1311 - if (userSessionCount == 0) { r = 'None.'; }
1312 - break;
1313 - }
1314 - case 'closeusersessions': {
1315 - var userSessionCount = 0;
1316 - var filter = null;
1317 - var arg = cmdargs['_'][0];
1318 - if (typeof arg == 'string') { if (arg.indexOf('/') >= 0) { filter = arg; } else { filter = ('user/' + domain.id + '/' + arg); } }
1319 - if (filter == null) {
1320 - r += "Usage: closeusersessions <username>";
1321 - } else {
1322 - r += "Closing user sessions for: " + filter + '\r\n';
1323 - for (var i in parent.wssessions) {
1324 - if (filter == i) {
1325 - userSessionCount++;
1326 - for (var j in parent.wssessions[i]) {
1327 - parent.wssessions[i][j].send(JSON.stringify({ action: 'stopped', msg: "Administrator forced disconnection" }));
1328 - parent.wssessions[i][j].close();
1329 - }
1330 - }
1331 - }
1332 - if (userSessionCount < 2) { r += 'Disconnected ' + userSessionCount + ' session.'; } else { r += 'Disconnected ' + userSessionCount + ' sessions.'; };
1333 - }
1334 - break;
1335 - }
1336 - case 'resetserver': {
1337 - console.log("Server restart...");
1338 - process.exit(0);
1339 - break;
1340 - }
1341 - case 'tasklimiter': {
1342 - if (parent.parent.taskLimiter != null) {
1343 - //var obj = { maxTasks: maxTasks, maxTaskTime: (maxTaskTime * 1000), nextTaskId: 0, currentCount: 0, current: {}, pending: [[], [], []], timer: null };
1344 - const tl = parent.parent.taskLimiter;
1345 - r += 'MaxTasks: ' + tl.maxTasks + ', NextTaskId: ' + tl.nextTaskId + '\r\n';
1346 - r += 'MaxTaskTime: ' + (tl.maxTaskTime / 1000) + ' seconds, Timer: ' + (tl.timer != null) + '\r\n';
1347 - var c = [];
1348 - for (var i in tl.current) { c.push(i); }
1349 - r += 'Current (' + tl.currentCount + '): [' + c.join(', ') + ']\r\n';
1350 - r += 'Pending (High/Med/Low): ' + tl.pending[0].length + ', ' + tl.pending[1].length + ', ' + tl.pending[2].length + '\r\n';
1351 - }
1352 - break;
1353 - }
1354 - case 'setmaxtasks': {
1355 - if ((cmdargs["_"].length != 1) || (parseInt(cmdargs["_"][0]) < 1) || (parseInt(cmdargs["_"][0]) > 1000)) {
1356 - r = 'Usage: setmaxtasks [1 to 1000]';
1357 - } else {
1358 - parent.parent.taskLimiter.maxTasks = parseInt(cmdargs["_"][0]);
1359 - r = 'MaxTasks set to ' + parent.parent.taskLimiter.maxTasks + '.';
1360 - }
1361 - break;
1362 - }
1363 - case 'cores': {
1364 - if (parent.parent.defaultMeshCores != null) { for (var i in parent.parent.defaultMeshCores) { r += i + ': ' + parent.parent.defaultMeshCores[i].length + ' bytes\r\n'; } }
1365 - break;
1366 - }
1367 - case 'showpaths': {
1368 - r = 'Parent: ' + parent.parent.parentpath + '\r\n';
1369 - r += 'Data: ' + parent.parent.datapath + '\r\n';
1370 - r += 'Files: ' + parent.parent.filespath + '\r\n';
1371 - r += 'Backup: ' + parent.parent.backuppath + '\r\n';
1372 - r += 'Record: ' + parent.parent.recordpath + '\r\n';
1373 - r += 'WebPublic: ' + parent.parent.webPublicPath + '\r\n';
1374 - r += 'WebViews: ' + parent.parent.webViewsPath + '\r\n';
1375 - if (parent.parent.webViewsOverridePath) { r += 'XWebPublic: ' + parent.parent.webViewsOverridePath + '\r\n'; }
1376 - if (parent.parent.webViewsOverridePath) { r += 'XWebViews: ' + parent.parent.webPublicOverridePath + '\r\n'; }
1377 - break;
1378 - }
1379 - case 'migrationagents': {
1380 - if (parent.parent.swarmserver == null) {
1381 - r = 'Swarm server not running.';
1382 - } else {
1383 - for (var i in parent.parent.swarmserver.migrationAgents) {
1384 - var arch = parent.parent.swarmserver.migrationAgents[i];
1385 - for (var j in arch) { var agent = arch[j]; r += 'Arch ' + agent.arch + ', Ver ' + agent.ver + ', Size ' + ((agent.binary == null) ? 0 : agent.binary.length) + '<br />'; }
1386 - }
1387 - }
1388 - break;
1389 - }
1390 - case 'swarmstats': {
1391 - if (parent.parent.swarmserver == null) {
1392 - r = 'Swarm server not running.';
1393 - } else {
1394 - for (var i in parent.parent.swarmserver.stats) {
1395 - if (typeof parent.parent.swarmserver.stats[i] == 'object') {
1396 - r += i + ': ' + JSON.stringify(parent.parent.swarmserver.stats[i]) + '\r\n';
1397 - } else {
1398 - r += i + ': ' + parent.parent.swarmserver.stats[i] + '\r\n';
1399 - }
1400 - }
1401 - }
1402 - break;
1403 - }
1404 - case 'heapdump': {
1405 - var heapdump = null;
1406 - try { heapdump = require('heapdump'); } catch (ex) { }
1407 - if (heapdump == null) {
1408 - r = 'Heapdump module not installed, run "npm install heapdump".';
1409 - } else {
1410 - heapdump.writeSnapshot(function (err, filename) {
1411 - if (err != null) {
1412 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: 'Unable to write heapdump: ' + err })); } catch (ex) { }
1413 - } else {
1414 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: 'Wrote heapdump at ' + filename })); } catch (ex) { }
1415 - }
1416 - });
1417 - }
1418 - break;
1419 - }
1420 - case 'relays': {
1421 - for (var i in parent.wsrelays) {
1422 - r += 'id: ' + i + ', ' + ((parent.wsrelays[i].state == 2) ? 'connected' : 'pending');
1423 - if (parent.wsrelays[i].peer1 != null) {
1424 - r += ', ' + cleanRemoteAddr(parent.wsrelays[i].peer1.req.clientIp);
1425 - if (parent.wsrelays[i].peer1.user) { r += ' (User:' + parent.wsrelays[i].peer1.user.name + ')' }
1426 - }
1427 - if (parent.wsrelays[i].peer2 != null) {
1428 - r += ' to ' + cleanRemoteAddr(parent.wsrelays[i].peer2.req.clientIp);
1429 - if (parent.wsrelays[i].peer2.user) { r += ' (User:' + parent.wsrelays[i].peer2.user.name + ')' }
1430 - }
1431 - r += '\r\n';
1432 - }
1433 - if (r == '') { r = 'No relays.'; }
1434 - break;
1435 - }
1436 - case 'autobackup': {
1437 - var backupResult = parent.db.performBackup(function (msg) {
1438 - try { ws.send(JSON.stringify({ action: 'serverconsole', value: msg, tag: command.tag })); } catch (ex) { }
1439 - });
1440 - if (backupResult == 0) { r = 'Starting auto-backup...'; } else { r = 'Backup alreay in progress.'; }
1441 - break;
1442 - }
1443 - case 'backupconfig': {
1444 - r = parent.db.getBackupConfig();
1445 - break;
1446 - }
1447 - case 'firebase': {
1448 - if (parent.parent.firebase == null) {
1449 - r = "Firebase push messaging not supported";
1450 - } else {
1451 - r = JSON.stringify(parent.parent.firebase.stats, null, 2);
1452 - }
1453 - break;
1454 - }
1455 - default: { // This is an unknown command, return an error message
1456 - r = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
1457 - break;
1458 - }
1459 - }
914 + var cmdData = serverUserCommand[cmd];
915 + if (cmdData != null) { r = cmdData[0](cmdargs); } else { r = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.'; }
916
917 if (r != '') { try { ws.send(JSON.stringify({ action: 'serverconsole', value: r, tag: command.tag })); } catch (ex) { } }
918 break;
@@ -6078,6 +5534,650 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
5534 }
5535 }
5536
5537 + const serverUserCommand = {
5538 + 'acceleratorsstats': [serverUserCommandAcceleratorsStats, "Show data on work being offloaded to other CPU's"],
5539 + 'agentissues': [serverUserCommandAgentIssues, ""],
5540 + 'agentstats': [serverUserCommandAgentStats, ""],
5541 + 'amtacm': [serverUserCommandAmtAcm, ""],
5542 + 'amtmanager': [serverUserCommandAmtManager, ""],
5543 + 'amtpasswords': [serverUserCommandAmtPasswords, ""],
5544 + 'args': [serverUserCommandArgs, ""],
5545 + 'autobackup': [serverUserCommandAutoBackup, ""],
5546 + 'backupconfig': [serverUserCommandBackupConfig, ""],
5547 + 'badlogins': [serverUserCommandBadLogins, ""],
5548 + 'certexpire': [serverUserCommandCertExpire, ""],
5549 + 'certhashes': [serverUserCommandCertHashes, ""],
5550 + 'closeusersessions': [serverUserCommandCloseUserSessions, "Disconnects all sessions for a specified user."],
5551 + 'cores': [serverUserCommandCores, ""],
5552 + 'dbcounters': [serverUserCommandDbCounters, ""],
5553 + 'dbstats': [serverUserCommandDbStats, ""],
5554 + 'dispatchtable': [serverUserCommandDispatchTable, ""],
5555 + 'dupagents': [serverUserCommandDupAgents, ""],
5556 + 'email': [serverUserCommandEmail, ""],
5557 + 'firebase': [serverUserCommandFirebase, ""],
5558 + 'heapdump': [serverUserCommandHeapDump, ""],
5559 + 'heapdump2': [serverUserCommandHeapDump2, ""],
5560 + 'help': [serverUserCommandHelp, ""],
5561 + 'info': [serverUserCommandInfo, "Returns the most immidiatly useful information about this server, including MeshCentral and NodeJS versions. This is often information required to file a bug."],
5562 + 'le': [serverUserCommandLe, ""],
5563 + 'lecheck': [serverUserCommandLeCheck, ""],
5564 + 'leevents': [serverUserCommandLeEvents, ""],
5565 + 'maintenance': [serverUserCommandMaintenance, ""],
5566 + 'migrationagents': [serverUserCommandMigrationAgents, ""],
5567 + 'mps': [serverUserCommandMps, ""],
5568 + 'mpsstats': [serverUserCommandMpsStats, ""],
5569 + 'nodeconfig': [serverUserCommandNodeConfig, ""],
5570 + 'print': [serverUserCommandPrint, ""],
5571 + 'relays': [serverUserCommandRelays, ""],
5572 + 'resetserver': [serverUserCommandResetServer, "Causes the server to reset, this is sometimes useful is the config.json file was changed."],
5573 + 'serverupdate': [serverUserCommandServerUpdate, "Updates server to latest version. Optional version argument to install specific version. Example: serverupdate 0.8.49"],
5574 + 'setmaxtasks': [serverUserCommandSetMaxTasks, ""],
5575 + 'showpaths': [serverUserCommandShowPaths, ""],
5576 + 'sms': [serverUserCommandSMS, ""],
5577 + 'swarmstats': [serverUserCommandSwarmStats, ""],
5578 + 'tasklimiter': [serverUserCommandTaslkLimiter, "Returns the internal status of the tasklimiter. This is a system used to smooth out work done by the server. It's used by, for example, agent updates so that not all agents are updated at the same time."],
5579 + 'trafficdelta': [serverUserCommandTrafficDelta, ""],
5580 + 'trafficstats': [serverUserCommandTrafficStats, ""],
5581 + 'updatecheck': [serverUserCommandUpdateCheck, ""],
5582 + 'usersessions': [serverUserCommandUserSessions, "Returns a list of active sessions grouped by user."],
5583 + 'versions': [serverUserCommandVersions, "Returns all internal versions for NodeJS running this server."],
5584 + 'watchdog': [serverUserCommandWatchdog, ""],
5585 + 'webpush': [serverUserCommandWebPush, ""],
5586 + 'webstats': [serverUserCommandWebStats, ""]
5587 + }
5588 +
5589 + function serverUserCommandHelp(cmdargs) {
5590 + var r, fin = '', f = '', availcommands = [];
5591 + for (var i in serverUserCommand) { availcommands.push(i); }
5592 + availcommands = availcommands.sort();
5593 + while (availcommands.length > 0) { if (f.length > 80) { fin += (f + ',\r\n'); f = ''; } f += (((f != '') ? ', ' : ' ') + availcommands.shift()); }
5594 + if (f != '') { fin += f; }
5595 + if (cmdargs['_'].length == 0) {
5596 + r = 'Available commands: \r\n' + fin + '\r\nType help <command> for details.';
5597 + } else {
5598 + var cmd2 = cmdargs['_'][0].toLowerCase();
5599 + var cmddata = serverUserCommand[cmd2];
5600 + if (cmddata) { if (cmddata[1] == '') { r = "No help available for this command."; } else { r = cmddata[1]; } } else { r = "This command does not exist."; }
5601 + }
5602 + return r;
5603 + }
5604 +
5605 + function serverUserCommandCertExpire(cmdargs) {
5606 + var r = '';
5607 + const now = Date.now();
5608 + for (var i in parent.webCertificateExpire) {
5609 + const domainName = (i == '') ? '[Default]' : i;
5610 + r += domainName + ', expires in ' + Math.floor((parent.webCertificateExpire[i] - now) / 86400000) + ' day(s)\r\n';
5611 + }
5612 + return r;
5613 + }
5614 +
5615 + function serverUserCommandWebPush(cmdargs) {
5616 + if (parent.parent.webpush == null) {
5617 + r = "Web push not supported.";
5618 + } else {
5619 + if (cmdargs['_'].length != 1) {
5620 + r = "Usage: WebPush \"Message\"";
5621 + } else {
5622 + const pushSubscription = { "endpoint": "https://updates.push.services.mozilla.com/wpush/v2/gAAAAABgIkO9hjXHWhMPiuk-ppNRw7r_pUZitddwCEK4ykdzeIxOIjFnYhIt_nr-qUca2mpZziwQsSEhYTUCiuYrhWnVDRweMtiUj16yJJq8V5jneaEaUYjEIe5jp3DOMNpoTm1aHgX74gCR8uTXSITcM97bNi-hRxcQ4f6Ie4WSAmoXpd89B_g", "keys": { "auth": "UB2sbLVK7ALnSHw5P1dahg", "p256dh": "BIoRbcNSxBuTjN39CCCUCHo1f4NxBJ1YDdu_k4MbPW_q3NK1_RufnydUzLPDp8ibBVItSI72-s48QJvOjQ_S8Ok" } }
5623 + parent.parent.webpush.sendNotification(pushSubscription, cmdargs['_'][0]).then(
5624 + function (value) { try { ws.send(JSON.stringify({ action: 'OK', value: r, tag: command.tag })); } catch (ex) { } },
5625 + function (error) { try { ws.send(JSON.stringify({ action: 'Error', value: r, tag: command.tag })); } catch (ex) { } }
5626 + );
5627 + }
5628 + }
5629 + return r;
5630 + }
5631 +
5632 + function serverUserCommandAmtManager(cmdargs) {
5633 + if (parent.parent.amtManager == null) { return 'Intel AMT Manager not active.'; }
5634 + return parent.parent.amtManager.getStatusString();
5635 + }
5636 +
5637 + function serverUserCommandCertHashes(cmdargs) {
5638 + var r = 'AgentCertHash: ' + parent.agentCertificateHashHex;
5639 + for (var i in parent.webCertificateHashs) { r += '\r\nwebCertificateHash (' + i + '): ' + common.rstr2hex(parent.webCertificateHashs[i]); }
5640 + for (var i in parent.webCertificateFullHashs) { r += '\r\nwebCertificateFullHash (' + i + '): ' + common.rstr2hex(parent.webCertificateFullHashs[i]); }
5641 + r += '\r\ndefaultWebCertificateHash: ' + common.rstr2hex(parent.defaultWebCertificateHash);
5642 + r += '\r\ndefaultWebCertificateFullHash: ' + common.rstr2hex(parent.defaultWebCertificateFullHash);
5643 + return r;
5644 + }
5645 +
5646 + function serverUserCommandAmtAcm(cmdargs) {
5647 + var r = '';
5648 + if ((domain.amtacmactivation == null) || (domain.amtacmactivation.acmmatch == null) || (domain.amtacmactivation.acmmatch.length == 0)) {
5649 + r = 'No Intel AMT activation certificates.';
5650 + } else {
5651 + if (domain.amtacmactivation.log != null) { r += '--- Activation Log ---\r\nFile : ' + domain.amtacmactivation.log + '\r\n'; }
5652 + for (var i in domain.amtacmactivation.acmmatch) {
5653 + var acmcert = domain.amtacmactivation.acmmatch[i];
5654 + r += '--- Activation Certificate ' + (parseInt(i) + 1) + ' ---\r\nName : ' + acmcert.cn + '\r\nSHA1 : ' + acmcert.sha1 + '\r\nSHA256: ' + acmcert.sha256 + '\r\n';
5655 + }
5656 + }
5657 + return r;
5658 + }
5659 +
5660 + function serverUserCommandHeapDump(cmdargs) {
5661 + var r = '';
5662 + // Heapdump support, see example at:
5663 + // https://www.arbazsiddiqui.me/a-practical-guide-to-memory-leaks-in-nodejs/
5664 + if (parent.parent.config.settings.heapdump === true) {
5665 + var dumpFileName = parent.path.join(parent.parent.datapath, `heapDump-${Date.now()}.heapsnapshot`);
5666 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: "Generating dump file at: " + dumpFileName, tag: command.tag })); } catch (ex) { }
5667 + require('heapdump').writeSnapshot(dumpFileName, (err, filename) => {
5668 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: "Done.", tag: command.tag })); } catch (ex) { }
5669 + });
5670 + } else {
5671 + r = "Heapdump not supported, add \"heapdump\":true to settings section of config.json.";
5672 + }
5673 + return r;
5674 + }
5675 +
5676 + function serverUserCommandHeapDump2(cmdargs) {
5677 + var r = '';
5678 + var heapdump = null;
5679 + try { heapdump = require('heapdump'); } catch (ex) { }
5680 + if (heapdump == null) {
5681 + r = 'Heapdump module not installed, run "npm install heapdump".';
5682 + } else {
5683 + heapdump.writeSnapshot(function (err, filename) {
5684 + if (err != null) {
5685 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: 'Unable to write heapdump: ' + err })); } catch (ex) { }
5686 + } else {
5687 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: 'Wrote heapdump at ' + filename })); } catch (ex) { }
5688 + }
5689 + });
5690 + }
5691 + break;
5692 + }
5693 +
5694 + function serverUserCommandSMS(cmdargs) {
5695 + var r = '';
5696 + if (parent.parent.smsserver == null) {
5697 + r = "No SMS gateway in use.";
5698 + } else {
5699 + if (cmdargs['_'].length != 2) {
5700 + r = "Usage: SMS \"PhoneNumber\" \"Message\".";
5701 + } else {
5702 + parent.parent.smsserver.sendSMS(cmdargs['_'][0], cmdargs['_'][1], function (status, msg) {
5703 + if (typeof msg == 'string') {
5704 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: status ? ('Success: ' + msg) : ('Failed: ' + msg), tag: command.tag })); } catch (ex) { }
5705 + } else {
5706 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: status ? 'Success' : 'Failed', tag: command.tag })); } catch (ex) { }
5707 + }
5708 + });
5709 + }
5710 + }
5711 + return r;
5712 + }
5713 +
5714 + function serverUserCommandEmail(cmdargs) {
5715 + var r = '';
5716 + if (domain.mailserver == null) {
5717 + r = "No email service enabled.";
5718 + } else {
5719 + if (cmdargs['_'].length != 3) {
5720 + r = "Usage: email \"user@sample.com\" \"Subject\" \"Message\".";
5721 + } else {
5722 + domain.mailserver.sendMail(cmdargs['_'][0], cmdargs['_'][1], cmdargs['_'][2]);
5723 + r = "Done.";
5724 + }
5725 + }
5726 + return r;
5727 + }
5728 +
5729 + function serverUserCommandLe(cmdargs) {
5730 + if (parent.parent.letsencrypt == null) { return "Let's Encrypt not in use."; }
5731 + return JSON.stringify(parent.parent.letsencrypt.getStats(), null, 4);
5732 + }
5733 +
5734 + function serverUserCommandLeCheck(cmdargs) {
5735 + if (parent.parent.letsencrypt == null) { return "Let's Encrypt not in use."; }
5736 + return ["CertOK", "Request:NoCert", "Request:Expire", "Request:MissingNames"][parent.parent.letsencrypt.checkRenewCertificate()];
5737 + }
5738 +
5739 + function serverUserCommandLeEvents(cmdargs) {
5740 + if (parent.parent.letsencrypt == null) { return "Let's Encrypt not in use."; }
5741 + return parent.parent.letsencrypt.events.join('\r\n');
5742 + }
5743 +
5744 + function serverUserCommandBadLogins(cmdargs) {
5745 + var r = '';
5746 + if (parent.parent.config.settings.maxinvalidlogin == false) {
5747 + r = 'Bad login filter is disabled.';
5748 + } else {
5749 + if (cmdargs['_'] == 'reset') {
5750 + // Reset bad login table
5751 + parent.badLoginTable = {};
5752 + parent.badLoginTableLastClean = 0;
5753 + r = 'Done.'
5754 + } else if (cmdargs['_'] == '') {
5755 + // Show current bad login table
5756 + if (typeof parent.parent.config.settings.maxinvalidlogin.coolofftime == 'number') {
5757 + r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s), " + parent.parent.config.settings.maxinvalidlogin.coolofftime + " minute(s) cooloff.\r\n";
5758 + } else {
5759 + r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s).\r\n";
5760 + }
5761 + var badLoginCount = 0;
5762 + parent.cleanBadLoginTable();
5763 + for (var i in parent.badLoginTable) {
5764 + badLoginCount++;
5765 + if (typeof parent.badLoginTable[i] == 'number') {
5766 + r += "Cooloff for " + Math.floor((parent.badLoginTable[i] - Date.now()) / 60000) + " minute(s)\r\n";
5767 + } else {
5768 + if (parent.badLoginTable[i].length > 1) {
5769 + r += (i + ' - ' + parent.badLoginTable[i].length + " records\r\n");
5770 + } else {
5771 + r += (i + ' - ' + parent.badLoginTable[i].length + " record\r\n");
5772 + }
5773 + }
5774 + }
5775 + if (badLoginCount == 0) { r += 'No bad logins.'; }
5776 + } else {
5777 + r = 'Usage: badlogin [reset]';
5778 + }
5779 + }
5780 + return r;
5781 + }
5782 +
5783 + function serverUserCommandDispatchTable(cmdargs) {
5784 + var r = '';
5785 + for (var i in parent.parent.eventsDispatch) { r += (i + ', ' + parent.parent.eventsDispatch[i].length + '\r\n'); }
5786 + return r;
5787 + }
5788 +
5789 + function serverUserCommandDupAgents(cmdargs) {
5790 + var r = '';
5791 + for (var i in parent.duplicateAgentsLog) { r += JSON.stringify(parent.duplicateAgentsLog[i]) + '\r\n'; }
5792 + if (r == '') { r = 'No duplicate agents in log.'; }
5793 + return r;
5794 + }
5795 +
5796 + function serverUserCommandAgentStats(cmdargs) {
5797 + var r = '', stats = parent.getAgentStats();
5798 + for (var i in stats) {
5799 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
5800 + }
5801 + return r;
5802 + }
5803 +
5804 + function serverUserCommandAgentIssues(cmdargs) {
5805 + var r = '', stats = parent.getAgentIssues();
5806 + if (stats.length == 0) {
5807 + r = "No agent issues.";
5808 + } else {
5809 + for (var i in stats) { r += stats[i].join(', ') + '\r\n'; }
5810 + }
5811 + return r;
5812 + }
5813 +
5814 + function serverUserCommandWebStats(cmdargs) {
5815 + var r = '', stats = parent.getStats();
5816 + for (var i in stats) {
5817 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
5818 + }
5819 + return r;
5820 + }
5821 +
5822 + function serverUserCommandTrafficStats(cmdargs) {
5823 + var r = '';
5824 + var stats = parent.getTrafficStats();
5825 + for (var i in stats) {
5826 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
5827 + }
5828 + return r;
5829 + }
5830 +
5831 + function serverUserCommandTrafficDelta(cmdargs) {
5832 + var r = '';
5833 + const stats = parent.getTrafficDelta(obj.trafficStats);
5834 + obj.trafficStats = stats.current;
5835 + for (var i in stats.delta) {
5836 + if (typeof stats.delta[i] == 'object') { r += (i + ': ' + JSON.stringify(stats.delta[i]) + '\r\n'); } else { r += (i + ': ' + stats.delta[i] + '\r\n'); }
5837 + }
5838 + return r;
5839 + }
5840 +
5841 + function serverUserCommandWatchdog(cmdargs) {
5842 + var r = '';
5843 + if (parent.parent.watchdog == null) {
5844 + r = 'Server watchdog not active.';
5845 + } else {
5846 + r = 'Server watchdog active.\r\n';
5847 + if (parent.parent.watchdogmaxtime != null) { r += 'Largest timeout was ' + parent.parent.watchdogmax + 'ms on ' + parent.parent.watchdogmaxtime + '\r\n'; }
5848 + for (var i in parent.parent.watchdogtable) { r += parent.parent.watchdogtable[i] + '\r\n'; }
5849 + }
5850 + return r;
5851 + }
5852 +
5853 + function serverUserCommandAcceleratorsStats(cmdargs) {
5854 + var r = '', stats = parent.parent.certificateOperations.getAcceleratorStats();
5855 + for (var i in stats) {
5856 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
5857 + }
5858 + return r;
5859 + }
5860 +
5861 + function serverUserCommandMpsStats(cmdargs) {
5862 + var r = '';
5863 + if (parent.parent.mpsserver == null) {
5864 + r = 'MPS not enabled.';
5865 + } else {
5866 + var stats = parent.parent.mpsserver.getStats();
5867 + for (var i in stats) {
5868 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
5869 + }
5870 + }
5871 + return r;
5872 + }
5873 +
5874 + // List all MPS connections and types.
5875 + function serverUserCommandMps(cmdargs) {
5876 + var r = '';
5877 + if (parent.parent.mpsserver == null) {
5878 + r = 'MPS not enabled.';
5879 + } else {
5880 + const connectionTypes = ['CIRA', 'Relay', 'LMS'];
5881 + for (var nodeid in parent.parent.mpsserver.ciraConnections) {
5882 + r += nodeid;
5883 + var connections = parent.parent.mpsserver.ciraConnections[nodeid];
5884 + for (var i in connections) { r += ', ' + connectionTypes[connections[i].tag.connType]; }
5885 + r += '\r\n';
5886 + }
5887 + if (r == '') { r = 'MPS has not connections.'; }
5888 + }
5889 + return r;
5890 + }
5891 +
5892 + function serverUserCommandDbStats(cmdargs) {
5893 + parent.parent.db.getStats(function (stats) {
5894 + var r2 = '';
5895 + for (var i in stats) { r2 += (i + ': ' + stats[i] + '\r\n'); }
5896 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: r2, tag: command.tag })); } catch (ex) { }
5897 + });
5898 + }
5899 +
5900 + function serverUserCommandDbCounters(cmdargs) {
5901 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: JSON.stringify(parent.parent.db.dbCounters, null, 2), tag: command.tag })); } catch (ex) { }
5902 + }
5903 +
5904 + function serverUserCommandServerUpdate(cmdargs) {
5905 + var r = 'Performing server update...';
5906 + var version = null;
5907 + if (cmdargs['_'].length > 0) {
5908 + version = cmdargs['_'][0];
5909 +
5910 + // This call is SLOW. We only want to validate version if we have to
5911 + if (version != 'stable' && version != 'latest') {
5912 + parent.parent.getServerVersions((data) => {
5913 + var versions = JSON.parse(data);
5914 +
5915 + if (versions.includes(version)) {
5916 + if (parent.parent.performServerUpdate(version) == false) {
5917 + try {
5918 + ws.send(JSON.stringify({
5919 + action: 'serverconsole',
5920 + value: 'Server self-update not possible.'
5921 + }));
5922 + } catch (ex) { }
5923 + }
5924 + } else {
5925 + try {
5926 + ws.send(JSON.stringify({
5927 + action: 'serverconsole',
5928 + value: 'Invalid version. Aborting update'
5929 + }));
5930 + } catch (ex) { }
5931 + }
5932 + });
5933 + } else {
5934 + if (parent.parent.performServerUpdate(version) == false) {
5935 + r = 'Server self-update not possible.';
5936 + }
5937 + }
5938 + } else {
5939 + if (parent.parent.performServerUpdate(version) == false) {
5940 + r = 'Server self-update not possible.';
5941 + }
5942 + }
5943 + return r;
5944 + }
5945 +
5946 + function serverUserCommandPrint(cmdargs) {
5947 + console.log(cmdargs['_'][0]);
5948 + }
5949 +
5950 + function serverUserCommandAmtPasswords(cmdargs) {
5951 + var r = '';
5952 + if (parent.parent.amtPasswords == null) {
5953 + r = "No Intel AMT password table."
5954 + } else {
5955 + for (var i in parent.parent.amtPasswords) { r += (i + ' - ' + parent.parent.amtPasswords[i].join(', ') + '\r\n'); }
5956 + }
5957 + return r;
5958 + }
5959 +
5960 + function serverUserCommandUpdateCheck(cmdargs) {
5961 + parent.parent.getServerTags(function (tags, error) {
5962 + var r2 = '';
5963 + if (error != null) { r2 += 'Exception: ' + error + '\r\n'; }
5964 + else { for (var i in tags) { r2 += i + ': ' + tags[i] + '\r\n'; } }
5965 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: r2, tag: command.tag })); } catch (ex) { }
5966 + });
5967 + return "Checking server update...";
5968 + }
5969 +
5970 + function serverUserCommandMaintenance(cmdargs) {
5971 + var arg = null, changed = false, r = '';
5972 + if ((cmdargs['_'] != null) && (cmdargs['_'][0] != null)) { arg = cmdargs['_'][0].toLowerCase(); }
5973 + if (arg == 'enabled') { parent.parent.config.settings.maintenancemode = 1; changed = true; }
5974 + else if (arg == 'disabled') { delete parent.parent.config.settings.maintenancemode; changed = true; }
5975 + r = 'Maintenance mode: ' + ((parent.parent.config.settings.maintenancemode == null) ? 'Disabled' : 'Enabled');
5976 + if (changed == false) { r += '\r\nTo change type: maintenance [enabled|disabled]'; }
5977 + return r;
5978 + }
5979 +
5980 + function serverUserCommandInfo(cmdargs) {
5981 + var info = process.memoryUsage();
5982 + info.dbType = ['None', 'NeDB', 'MongoJS', 'MongoDB'][parent.db.databaseType];
5983 + try { if (parent.parent.multiServer != null) { info.serverId = parent.parent.multiServer.serverid; } } catch (ex) { }
5984 + if (parent.db.databaseType == 3) { info.dbChangeStream = parent.db.changeStream; }
5985 + if (parent.parent.pluginHandler != null) { info.plugins = []; for (var i in parent.parent.pluginHandler.plugins) { info.plugins.push(i); } }
5986 + try { info.nodeVersion = process.version; } catch (ex) { }
5987 + try { info.meshVersion = parent.parent.currentVer; } catch (ex) { }
5988 + try { info.platform = process.platform; } catch (ex) { }
5989 + try { info.arch = process.arch; } catch (ex) { }
5990 + try { info.pid = process.pid; } catch (ex) { }
5991 + try { info.uptime = process.uptime(); } catch (ex) { }
5992 + try { info.cpuUsage = process.cpuUsage(); } catch (ex) { }
5993 + try { info.warnings = parent.parent.getServerWarnings(); } catch (ex) { }
5994 + try { info.database = ["Unknown", "NeDB", "MongoJS", "MongoDB", "MariaDB", "MySQL"][parent.parent.db.databaseType]; } catch (ex) { }
5995 + try { info.productionMode = ((process.env.NODE_ENV != null) && (process.env.NODE_ENV == 'production')); } catch (ex) { }
5996 + try { info.allDevGroupManagers = parent.parent.config.settings.managealldevicegroups; } catch (ex) { }
5997 + return JSON.stringify(info, null, 4);
5998 + }
5999 +
6000 + function serverUserCommandNodeConfig(cmdargs) {
6001 + return JSON.stringify(process.config, null, 4);
6002 + }
6003 +
6004 + function serverUserCommandVersions(cmdargs) {
6005 + return JSON.stringify(process.versions, null, 4);
6006 + }
6007 +
6008 + function serverUserCommandArgs(cmdargs) {
6009 + return cmd + ': ' + JSON.stringify(cmdargs);
6010 + }
6011 +
6012 + function serverUserCommandUserSessions(cmdargs) {
6013 + var r = '';
6014 + var userSessionCount = 0;
6015 + var filter = null;
6016 + var arg = cmdargs['_'][0];
6017 + if (typeof arg == 'string') { if (arg.indexOf('/') >= 0) { filter = arg; } else { filter = ('user/' + domain.id + '/' + arg); } }
6018 + for (var i in parent.wssessions) {
6019 + if ((filter == null) || (filter == i)) {
6020 + userSessionCount++;
6021 + r += (i + ', ' + parent.wssessions[i].length + ' session' + ((parent.wssessions[i].length > 1) ? 's' : '') + '.\r\n');
6022 + for (var j in parent.wssessions[i]) {
6023 + r += ' ' + parent.wssessions[i][j].clientIp + ' --> ' + parent.wssessions[i][j].sessionId + '\r\n';
6024 + }
6025 + }
6026 + }
6027 + if (userSessionCount == 0) { r = 'None.'; }
6028 + break;
6029 + }
6030 +
6031 + function serverUserCommandCloseUserSessions(cmdargs) {
6032 + var r = '';
6033 + var userSessionCount = 0;
6034 + var filter = null;
6035 + var arg = cmdargs['_'][0];
6036 + if (typeof arg == 'string') { if (arg.indexOf('/') >= 0) { filter = arg; } else { filter = ('user/' + domain.id + '/' + arg); } }
6037 + if (filter == null) {
6038 + r += "Usage: closeusersessions <username>";
6039 + } else {
6040 + r += "Closing user sessions for: " + filter + '\r\n';
6041 + for (var i in parent.wssessions) {
6042 + if (filter == i) {
6043 + userSessionCount++;
6044 + for (var j in parent.wssessions[i]) {
6045 + parent.wssessions[i][j].send(JSON.stringify({ action: 'stopped', msg: "Administrator forced disconnection" }));
6046 + parent.wssessions[i][j].close();
6047 + }
6048 + }
6049 + }
6050 + if (userSessionCount < 2) { r += 'Disconnected ' + userSessionCount + ' session.'; } else { r += 'Disconnected ' + userSessionCount + ' sessions.'; };
6051 + }
6052 + break;
6053 + }
6054 +
6055 + function serverUserCommandResetServer(cmdargs) {
6056 + var r = '';
6057 + console.log("Server restart...");
6058 + process.exit(0);
6059 + break;
6060 + }
6061 +
6062 + function serverUserCommandTaslkLimiter(cmdargs) {
6063 + var r = '';
6064 + if (parent.parent.taskLimiter != null) {
6065 + //var obj = { maxTasks: maxTasks, maxTaskTime: (maxTaskTime * 1000), nextTaskId: 0, currentCount: 0, current: {}, pending: [[], [], []], timer: null };
6066 + const tl = parent.parent.taskLimiter;
6067 + r += 'MaxTasks: ' + tl.maxTasks + ', NextTaskId: ' + tl.nextTaskId + '\r\n';
6068 + r += 'MaxTaskTime: ' + (tl.maxTaskTime / 1000) + ' seconds, Timer: ' + (tl.timer != null) + '\r\n';
6069 + var c = [];
6070 + for (var i in tl.current) { c.push(i); }
6071 + r += 'Current (' + tl.currentCount + '): [' + c.join(', ') + ']\r\n';
6072 + r += 'Pending (High/Med/Low): ' + tl.pending[0].length + ', ' + tl.pending[1].length + ', ' + tl.pending[2].length + '\r\n';
6073 + }
6074 + break;
6075 + }
6076 +
6077 + function serverUserCommandSetMaxTasks(cmdargs) {
6078 + var r = '';
6079 + if ((cmdargs["_"].length != 1) || (parseInt(cmdargs["_"][0]) < 1) || (parseInt(cmdargs["_"][0]) > 1000)) {
6080 + r = 'Usage: setmaxtasks [1 to 1000]';
6081 + } else {
6082 + parent.parent.taskLimiter.maxTasks = parseInt(cmdargs["_"][0]);
6083 + r = 'MaxTasks set to ' + parent.parent.taskLimiter.maxTasks + '.';
6084 + }
6085 + break;
6086 + }
6087 +
6088 + function serverUserCommandCores(cmdargs) {
6089 + var r = '';
6090 + if (parent.parent.defaultMeshCores != null) { for (var i in parent.parent.defaultMeshCores) { r += i + ': ' + parent.parent.defaultMeshCores[i].length + ' bytes\r\n'; } }
6091 + break;
6092 + }
6093 +
6094 + function serverUserCommandShowPaths(cmdargs) {
6095 + var r = '';
6096 + r = 'Parent: ' + parent.parent.parentpath + '\r\n';
6097 + r += 'Data: ' + parent.parent.datapath + '\r\n';
6098 + r += 'Files: ' + parent.parent.filespath + '\r\n';
6099 + r += 'Backup: ' + parent.parent.backuppath + '\r\n';
6100 + r += 'Record: ' + parent.parent.recordpath + '\r\n';
6101 + r += 'WebPublic: ' + parent.parent.webPublicPath + '\r\n';
6102 + r += 'WebViews: ' + parent.parent.webViewsPath + '\r\n';
6103 + if (parent.parent.webViewsOverridePath) { r += 'XWebPublic: ' + parent.parent.webViewsOverridePath + '\r\n'; }
6104 + if (parent.parent.webViewsOverridePath) { r += 'XWebViews: ' + parent.parent.webPublicOverridePath + '\r\n'; }
6105 + break;
6106 + }
6107 +
6108 + function serverUserCommandMigrationAgents(cmdargs) {
6109 + var r = '';
6110 + if (parent.parent.swarmserver == null) {
6111 + r = 'Swarm server not running.';
6112 + } else {
6113 + for (var i in parent.parent.swarmserver.migrationAgents) {
6114 + var arch = parent.parent.swarmserver.migrationAgents[i];
6115 + for (var j in arch) { var agent = arch[j]; r += 'Arch ' + agent.arch + ', Ver ' + agent.ver + ', Size ' + ((agent.binary == null) ? 0 : agent.binary.length) + '<br />'; }
6116 + }
6117 + }
6118 + break;
6119 + }
6120 +
6121 + function serverUserCommandSwarmStats(cmdargs) {
6122 + var r = '';
6123 + if (parent.parent.swarmserver == null) {
6124 + r = 'Swarm server not running.';
6125 + } else {
6126 + for (var i in parent.parent.swarmserver.stats) {
6127 + if (typeof parent.parent.swarmserver.stats[i] == 'object') {
6128 + r += i + ': ' + JSON.stringify(parent.parent.swarmserver.stats[i]) + '\r\n';
6129 + } else {
6130 + r += i + ': ' + parent.parent.swarmserver.stats[i] + '\r\n';
6131 + }
6132 + }
6133 + }
6134 + break;
6135 + }
6136 +
6137 + function serverUserCommandRelays(cmdargs) {
6138 + var r = '';
6139 + for (var i in parent.wsrelays) {
6140 + r += 'id: ' + i + ', ' + ((parent.wsrelays[i].state == 2) ? 'connected' : 'pending');
6141 + if (parent.wsrelays[i].peer1 != null) {
6142 + r += ', ' + cleanRemoteAddr(parent.wsrelays[i].peer1.req.clientIp);
6143 + if (parent.wsrelays[i].peer1.user) { r += ' (User:' + parent.wsrelays[i].peer1.user.name + ')' }
6144 + }
6145 + if (parent.wsrelays[i].peer2 != null) {
6146 + r += ' to ' + cleanRemoteAddr(parent.wsrelays[i].peer2.req.clientIp);
6147 + if (parent.wsrelays[i].peer2.user) { r += ' (User:' + parent.wsrelays[i].peer2.user.name + ')' }
6148 + }
6149 + r += '\r\n';
6150 + }
6151 + if (r == '') { r = 'No relays.'; }
6152 + break;
6153 + }
6154 +
6155 + function serverUserCommandAutoBackup(cmdargs) {
6156 + var r = '';
6157 + var backupResult = parent.db.performBackup(function (msg) {
6158 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: msg, tag: command.tag })); } catch (ex) { }
6159 + });
6160 + if (backupResult == 0) { r = 'Starting auto-backup...'; } else { r = 'Backup alreay in progress.'; }
6161 + break;
6162 + }
6163 +
6164 + function serverUserCommandBackupConfig(cmdargs) {
6165 + var r = '';
6166 + r = parent.db.getBackupConfig();
6167 + break;
6168 + }
6169 +
6170 + function serverUserCommandFirebase(cmdargs) {
6171 + var r = '';
6172 + if (parent.parent.firebase == null) {
6173 + r = "Firebase push messaging not supported";
6174 + } else {
6175 + r = JSON.stringify(parent.parent.firebase.stats, null, 2);
6176 + }
6177 + break;
6178 + }
6179 +
6180 +
6181 function csvClean(s) { return '\"' + s.split('\"').join('').split(',').join('').split('\r').join('').split('\n').join('') + '\"'; }
6182
6183 // Return detailed information about an array of nodeid's