Refactor meshuser - serverconsome cmd handlers

Noah Zalev committed Jul 7, 2021 at 20:44 UTC 2addeb78a9644c135f74bf31c2d9ef8eddebc81d
1 file changed +691 -545
meshuser.js
+691 -545
@@ -544,6 +544,690 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
544 });
545 } catch (e) { console.log(e); }
546
547 +
548 + var consoleCommands = {};
549 + consoleCommands['help'] = helpConsoleCommand;
550 + consoleCommands['certexpire'] = certexpireConsoleCommand;
551 + consoleCommands['webpush'] = webpushConsoleCommand;
552 + consoleCommands['amtmanager'] = amtmanagerConsoleCommand;
553 + consoleCommands['certhashes'] = certhashesConsoleCommand;
554 + consoleCommands['amtacm'] = amtacmConsoleCommand;
555 + consoleCommands['heapdump'] = heapdumpConsoleCommand;
556 + consoleCommands['heapdump2'] = heapdump2ConsoleCommand;
557 + consoleCommands['sms'] = smsConsoleCommand;
558 + consoleCommands['email'] = emailConsoleCommand;
559 + consoleCommands['le'] = leConsoleCommand;
560 + consoleCommands['lecheck'] = lecheckConsoleCommand;
561 + consoleCommands['leevents'] = leeventsConsoleCommand;
562 + consoleCommands['badlogins'] = badloginsConsoleCommand;
563 + consoleCommands['dispatchtable'] = dispatchtableConsoleCommand;
564 + consoleCommands['dupagents'] = dupagentsConsoleCommand;
565 + consoleCommands['agentstats'] = agentstatsConsoleCommand;
566 + consoleCommands['agentissues'] = agentissuesConsoleCommand;
567 + consoleCommands['webstats'] = webstatsConsoleCommand;
568 + consoleCommands['trafficstats'] = trafficstatsConsoleCommand;
569 + consoleCommands['trafficdelta'] = trafficdeltaConsoleCommand;
570 + consoleCommands['watchdog'] = watchdogConsoleCommand;
571 + consoleCommands['acceleratorsstats'] = acceleratorsstatsConsoleCommand;
572 + consoleCommands['mpsstats'] = mpsstatsConsoleCommand;
573 + consoleCommands['mps'] = mpsConsoleCommand;
574 + consoleCommands['dbstats'] = dbstatsConsoleCommand;
575 + consoleCommands['dbcounters'] = dbcountersConsoleCommand;
576 + consoleCommands['serverupdate'] = serverupdateConsoleCommand;
577 + consoleCommands['print'] = printConsoleCommand;
578 + consoleCommands['amtpasswords'] = amtpasswordsConsoleCommand;
579 + consoleCommands['updatecheck'] = updatecheckConsoleCommand;
580 + consoleCommands['maintenance'] = maintenanceConsoleCommand;
581 + consoleCommands['info'] = infoConsoleCommand;
582 + consoleCommands['nodeconfig'] = nodeconfigConsoleCommand;
583 + consoleCommands['versions'] = versionsConsoleCommand;
584 + consoleCommands['args'] = argsConsoleCommand;
585 + consoleCommands['usersessions'] = usersessionsConsoleCommand;
586 + consoleCommands['closeusersessions'] = closeusersessionsConsoleCommand;
587 + consoleCommands['resetserver'] = resetserverConsoleCommand;
588 + consoleCommands['tasklimiter'] = tasklimiterConsoleCommand;
589 + consoleCommands['setmaxtasks'] = setmaxtasksConsoleCommand;
590 + consoleCommands['cores'] = coresConsoleCommand;
591 + consoleCommands['showpaths'] = showpathsConsoleCommand;
592 + consoleCommands['migrationagents'] = migrationagentsConsoleCommand;
593 + consoleCommands['swarmstats'] = swarmstatsConsoleCommand;
594 + consoleCommands['relays'] = relaysConsoleCommand;
595 + consoleCommands['autobackup'] = autobackupConsoleCommand;
596 + consoleCommands['backupconfig'] = backupconfigConsoleCommand;
597 + consoleCommands['firebase'] = firebaseConsoleCommand;
598 +
599 +
600 + function helpConsoleCommand(cmdargs) {
601 + var r = '', 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';
602 + if (parent.parent.config.settings.heapdump === true) { availcommands += ',heapdump'; }
603 + availcommands = availcommands.split(',').sort();
604 + while (availcommands.length > 0) { if (f.length > 80) { fin += (f + ',\r\n'); f = ''; } f += (((f != '') ? ', ' : ' ') + availcommands.shift()); }
605 + if (f != '') { fin += f; }
606 + if (cmdargs['_'].length == 0) {
607 + r = 'Available commands: \r\n' + fin + '\r\nType help <command> for details.';
608 + } else {
609 + var cmd2 = cmdargs['_'][0].toLowerCase();
610 + switch (cmd2) {
611 + 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; }
612 + case 'versions': { r = "versions: Returns all internal versions for NodeJS running this server."; break; }
613 + case 'resetserver': { r = "resetserver: Causes the server to reset, this is sometimes useful is the config.json file was changed."; break; }
614 + case 'usersessions': { r = "usersessions: Returns a list of active sessions grouped by user."; break; }
615 + case 'closeusersessions': { r = "closeusersessions: Disconnects all sessions for a specified user."; break; }
616 + 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; }
617 + case 'serverupdate': { r = "serverupdate: Updates server to latest version. Optional version argument to install specific version. Example: serverupdate 0.8.49"; break; }
618 + default: { r = 'No help information about this command.'; break; }
619 + }
620 + }
621 + return r;
622 + }
623 +
624 + function certexpireConsoleCommand(command, cmdargs) {
625 + var r = '';
626 + const now = Date.now();
627 + for (var i in parent.webCertificateExpire) {
628 + const domainName = (i == '') ? '[Default]' : i;
629 + r += domainName + ', expires in ' + Math.floor((parent.webCertificateExpire[i] - now) / 86400000) + ' day(s)\r\n';
630 + }
631 + return r;
632 + }
633 +
634 + function webpushConsoleCommand(command, cmdargs) {
635 + var r = '';
636 + if (parent.parent.webpush == null) {
637 + r = "Web push not supported.";
638 + } else {
639 + if (cmdargs['_'].length != 1) {
640 + r = "Usage: WebPush \"Message\"";
641 + } else {
642 + 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" } }
643 + parent.parent.webpush.sendNotification(pushSubscription, cmdargs['_'][0]).then(
644 + function (value) { try { ws.send(JSON.stringify({ action: 'OK', value: r, tag: command.tag })); } catch (ex) { } },
645 + function (error) { try { ws.send(JSON.stringify({ action: 'Error', value: r, tag: command.tag })); } catch (ex) { } }
646 + );
647 + }
648 + }
649 + return r;
650 + }
651 +
652 + function amtmanagerConsoleCommand(command, cmdargs) {
653 + var r = '';
654 + if (parent.parent.amtManager == null) {
655 + r = 'Intel AMT Manager not active.';
656 + } else {
657 + r = parent.parent.amtManager.getStatusString();
658 + }
659 + return r;
660 + }
661 +
662 + function certhashesConsoleCommand(command, cmdargs) {
663 + var r = '';
664 + r += 'AgentCertHash: ' + parent.agentCertificateHashHex;
665 + for (var i in parent.webCertificateHashs) { r += '\r\nwebCertificateHash (' + i + '): ' + common.rstr2hex(parent.webCertificateHashs[i]); }
666 + for (var i in parent.webCertificateFullHashs) { r += '\r\nwebCertificateFullHash (' + i + '): ' + common.rstr2hex(parent.webCertificateFullHashs[i]); }
667 + r += '\r\ndefaultWebCertificateHash: ' + common.rstr2hex(parent.defaultWebCertificateHash);
668 + r += '\r\ndefaultWebCertificateFullHash: ' + common.rstr2hex(parent.defaultWebCertificateFullHash);
669 + return r;
670 + }
671 +
672 + function amtacmConsoleCommand(command, cmdargs) {
673 + var r = '';
674 + if ((domain.amtacmactivation == null) || (domain.amtacmactivation.acmmatch == null) || (domain.amtacmactivation.acmmatch.length == 0)) {
675 + r = 'No Intel AMT activation certificates.';
676 + } else {
677 + if (domain.amtacmactivation.log != null) { r += '--- Activation Log ---\r\nFile : ' + domain.amtacmactivation.log + '\r\n'; }
678 + for (var i in domain.amtacmactivation.acmmatch) {
679 + var acmcert = domain.amtacmactivation.acmmatch[i];
680 + r += '--- Activation Certificate ' + (parseInt(i) + 1) + ' ---\r\nName : ' + acmcert.cn + '\r\nSHA1 : ' + acmcert.sha1 + '\r\nSHA256: ' + acmcert.sha256 + '\r\n';
681 + }
682 + }
683 + return r;
684 + }
685 +
686 + function heapdumpConsoleCommand(command, cmdargs) {
687 + var r = '';
688 + // Heapdump support, see example at:
689 + // https://www.arbazsiddiqui.me/a-practical-guide-to-memory-leaks-in-nodejs/
690 + if (parent.parent.config.settings.heapdump === true) {
691 + var dumpFileName = parent.path.join(parent.parent.datapath, `heapDump-${Date.now()}.heapsnapshot`);
692 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: "Generating dump file at: " + dumpFileName, tag: command.tag })); } catch (ex) { }
693 + require('heapdump').writeSnapshot(dumpFileName, (err, filename) => {
694 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: "Done.", tag: command.tag })); } catch (ex) { }
695 + });
696 + } else {
697 + r = "Heapdump not supported, add \"heapdump\":true to settings section of config.json.";
698 + }
699 + return r;
700 + }
701 +
702 + function heapdump2ConsoleCommand(command, cmdargs) {
703 + var r = '';
704 + var heapdump = null;
705 + try { heapdump = require('heapdump'); } catch (ex) { }
706 + if (heapdump == null) {
707 + r = 'Heapdump module not installed, run "npm install heapdump".';
708 + } else {
709 + heapdump.writeSnapshot(function (err, filename) {
710 + if (err != null) {
711 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: 'Unable to write heapdump: ' + err })); } catch (ex) { }
712 + } else {
713 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: 'Wrote heapdump at ' + filename })); } catch (ex) { }
714 + }
715 + });
716 + }
717 + return r;
718 + }
719 +
720 + function smsConsoleCommand(command, cmdargs) {
721 + var r = '';
722 + if (parent.parent.smsserver == null) {
723 + r = "No SMS gateway in use.";
724 + } else {
725 + if (cmdargs['_'].length != 2) {
726 + r = "Usage: SMS \"PhoneNumber\" \"Message\".";
727 + } else {
728 + parent.parent.smsserver.sendSMS(cmdargs['_'][0], cmdargs['_'][1], function (status, msg) {
729 + if (typeof msg == 'string') {
730 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: status ? ('Success: ' + msg) : ('Failed: ' + msg), tag: command.tag })); } catch (ex) { }
731 + } else {
732 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: status ? 'Success' : 'Failed', tag: command.tag })); } catch (ex) { }
733 + }
734 + });
735 + }
736 + }
737 + return r;
738 + }
739 +
740 + function emailConsoleCommand(command, cmdargs) {
741 + var r = '';
742 + if (domain.mailserver == null) {
743 + r = "No email service enabled.";
744 + } else {
745 + if (cmdargs['_'].length != 3) {
746 + r = "Usage: email \"user@sample.com\" \"Subject\" \"Message\".";
747 + } else {
748 + domain.mailserver.sendMail(cmdargs['_'][0], cmdargs['_'][1], cmdargs['_'][2]);
749 + r = "Done.";
750 + }
751 + }
752 + return r;
753 + }
754 +
755 + function leConsoleCommand(command, cmdargs) {
756 + var r = '';
757 + if (parent.parent.letsencrypt == null) {
758 + r = "Let's Encrypt not in use.";
759 + } else {
760 + r = JSON.stringify(parent.parent.letsencrypt.getStats(), null, 4);
761 + }
762 + return r;
763 + }
764 +
765 + function lecheckConsoleCommand(command, cmdargs) {
766 + var r = '';
767 + if (parent.parent.letsencrypt == null) {
768 + r = "Let's Encrypt not in use.";
769 + } else {
770 + r = ["CertOK", "Request:NoCert", "Request:Expire", "Request:MissingNames"][parent.parent.letsencrypt.checkRkenewCertificate()];
771 + }
772 + return r;
773 + }
774 +
775 + function leeventsConsoleCommand(command, cmdargs) {
776 + var r = '';
777 + if (parent.parent.letsencrypt == null) {
778 + r = "Let's Encrypt not in use.";
779 + } else {
780 + r = parent.parent.letsencrypt.events.join('\r\n');
781 + }
782 + return r;
783 + }
784 +
785 + function badloginsConsoleCommand(command, cmdargs) {
786 + var r = '';
787 + if (parent.parent.config.settings.maxinvalidlogin == false) {
788 + r = 'Bad login filter is disabled.';
789 + } else {
790 + if (cmdargs['_'] == 'reset') {
791 + // Reset bad login table
792 + parent.badLoginTable = {};
793 + parent.badLoginTableLastClean = 0;
794 + r = 'Done.'
795 + } else if (cmdargs['_'] == '') {
796 + // Show current bad login table
797 + if (typeof parent.parent.config.settings.maxinvalidlogin.coolofftime == 'number') {
798 + 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";
799 + } else {
800 + r = "Max is " + parent.parent.config.settings.maxinvalidlogin.count + " bad login(s) in " + parent.parent.config.settings.maxinvalidlogin.time + " minute(s).\r\n";
801 + }
802 + var badLoginCount = 0;
803 + parent.cleanBadLoginTable();
804 + for (var i in parent.badLoginTable) {
805 + badLoginCount++;
806 + if (typeof parent.badLoginTable[i] == 'number') {
807 + r += "Cooloff for " + Math.floor((parent.badLoginTable[i] - Date.now()) / 60000) + " minute(s)\r\n";
808 + } else {
809 + if (parent.badLoginTable[i].length > 1) {
810 + r += (i + ' - ' + parent.badLoginTable[i].length + " records\r\n");
811 + } else {
812 + r += (i + ' - ' + parent.badLoginTable[i].length + " record\r\n");
813 + }
814 + }
815 + }
816 + if (badLoginCount == 0) { r += 'No bad logins.'; }
817 + } else {
818 + r = 'Usage: badlogin [reset]';
819 + }
820 + }
821 + return r;
822 + }
823 +
824 + function dispatchtableConsoleCommand(command, cmdargs) {
825 + var r = '';
826 + for (var i in parent.parent.eventsDispatch) {
827 + r += (i + ', ' + parent.parent.eventsDispatch[i].length + '\r\n');
828 + }
829 + return r;
830 + }
831 +
832 + function dupagentsConsoleCommand(command, cmdargs) {
833 + var r = '';
834 + for (var i in parent.duplicateAgentsLog) {
835 + r += JSON.stringify(parent.duplicateAgentsLog[i]) + '\r\n';
836 + }
837 + if (r == '') { r = 'No duplicate agents in log.'; }
838 + return r;
839 + }
840 +
841 + function agentstatsConsoleCommand(command, cmdargs) {
842 + var r = '';
843 + var stats = parent.getAgentStats();
844 + for (var i in stats) {
845 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
846 + }
847 + return r;
848 + }
849 +
850 + function agentissuesConsoleCommand(command, cmdargs) {
851 + var r = '';
852 + var stats = parent.getAgentIssues();
853 + if (stats.length == 0) {
854 + r = "No agent issues.";
855 + } else {
856 + for (var i in stats) { r += stats[i].join(', ') + '\r\n'; }
857 + }
858 + return r;
859 + }
860 +
861 + function webstatsConsoleCommand(command, cmdargs) {
862 + var r = '';
863 + var stats = parent.getStats();
864 + for (var i in stats) {
865 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
866 + }
867 + return r;
868 + }
869 +
870 + function trafficstatsConsoleCommand(command, cmdargs) {
871 + var r = '';
872 + var stats = parent.getTrafficStats();
873 + for (var i in stats) {
874 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
875 + }
876 + return r;
877 + }
878 +
879 + function trafficdeltaConsoleCommand(command, cmdargs) {
880 + var r = '';
881 + const stats = parent.getTrafficDelta(obj.trafficStats);
882 + obj.trafficStats = stats.current;
883 + for (var i in stats.delta) {
884 + if (typeof stats.delta[i] == 'object') { r += (i + ': ' + JSON.stringify(stats.delta[i]) + '\r\n'); } else { r += (i + ': ' + stats.delta[i] + '\r\n'); }
885 + }
886 + return r;
887 + }
888 +
889 + function watchdogConsoleCommand(command, cmdargs) {
890 + var r = '';
891 + if (parent.parent.watchdog == null) {
892 + r = 'Server watchdog not active.';
893 + } else {
894 + r = 'Server watchdog active.\r\n';
895 + if (parent.parent.watchdogmaxtime != null) { r += 'Largest timeout was ' + parent.parent.watchdogmax + 'ms on ' + parent.parent.watchdogmaxtime + '\r\n'; }
896 + for (var i in parent.parent.watchdogtable) { r += parent.parent.watchdogtable[i] + '\r\n'; }
897 + }
898 + return r;
899 + }
900 +
901 + function acceleratorsstatsConsoleCommand(command, cmdargs) {
902 + var r = '';
903 + var stats = parent.parent.certificateOperations.getAcceleratorStats();
904 + for (var i in stats) {
905 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
906 + }
907 + return r;
908 + }
909 +
910 + function mpsstatsConsoleCommand(command, cmdargs) {
911 + var r = '';
912 + if (parent.parent.mpsserver == null) {
913 + r = 'MPS not enabled.';
914 + } else {
915 + var stats = parent.parent.mpsserver.getStats();
916 + for (var i in stats) {
917 + if (typeof stats[i] == 'object') { r += (i + ': ' + JSON.stringify(stats[i]) + '\r\n'); } else { r += (i + ': ' + stats[i] + '\r\n'); }
918 + }
919 + }
920 + return r;
921 + }
922 +
923 + function mpsConsoleCommand(command, cmdargs) {
924 + var r = '';
925 + if (parent.parent.mpsserver == null) {
926 + r = 'MPS not enabled.';
927 + } else {
928 + const connectionTypes = ['CIRA', 'Relay', 'LMS'];
929 + for (var nodeid in parent.parent.mpsserver.ciraConnections) {
930 + r += nodeid;
931 + var connections = parent.parent.mpsserver.ciraConnections[nodeid];
932 + for (var i in connections) { r += ', ' + connectionTypes[connections[i].tag.connType]; }
933 + r += '\r\n';
934 + }
935 + if (r == '') { r = 'MPS has not connections.'; }
936 + }
937 + return r;
938 + }
939 +
940 + function dbstatsConsoleCommand(command, cmdargs) {
941 + parent.parent.db.getStats(function (stats) {
942 + var r2 = '';
943 + for (var i in stats) { r2 += (i + ': ' + stats[i] + '\r\n'); }
944 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: r2, tag: command.tag })); } catch (ex) { }
945 + });
946 + }
947 +
948 + function dbcountersConsoleCommand(command, cmdargs) {
949 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: JSON.stringify(parent.parent.db.dbCounters, null, 2), tag: command.tag })); } catch (ex) { }
950 + }
951 +
952 + function serverupdateConsoleCommand(command, cmdargs) {
953 + var r = '';
954 + r = 'Performing server update...';
955 + var version = null;
956 +
957 + if (cmdargs['_'].length > 0) {
958 + version = cmdargs['_'][0];
959 +
960 + // This call is SLOW. We only want to validate version if we have to
961 + if (version != 'stable' && version != 'latest') {
962 + parent.parent.getServerVersions((data) => {
963 + var versions = JSON.parse(data);
964 +
965 + if (versions.includes(version)) {
966 + if (parent.parent.performServerUpdate(version) == false) {
967 + try {
968 + ws.send(JSON.stringify({ action: 'serverconsole',
969 + value: 'Server self-update not possible.'}));
970 + } catch (ex) { }
971 + }
972 + } else {
973 + try {
974 + ws.send(JSON.stringify({ action: 'serverconsole',
975 + value: 'Invalid version. Aborting update'}));
976 + } catch (ex) { }
977 + }
978 + });
979 + } else {
980 + if (parent.parent.performServerUpdate(version) == false) {
981 + r = 'Server self-update not possible.';
982 + }
983 + }
984 + } else {
985 + if (parent.parent.performServerUpdate(version) == false) {
986 + r = 'Server self-update not possible.';
987 + }
988 + }
989 + return r;
990 + }
991 +
992 + function printConsoleCommand(command, cmdargs) {
993 + console.log(cmdargs['_'][0]);
994 + }
995 +
996 + function amtpasswordsConsoleCommand(command, cmdargs) {
997 + var r = '';
998 + if (parent.parent.amtPasswords == null) {
999 + r = "No Intel AMT password table."
1000 + } else {
1001 + for (var i in parent.parent.amtPasswords) { r += (i + ' - ' + parent.parent.amtPasswords[i].join(', ') + '\r\n'); }
1002 + }
1003 + return r;
1004 + }
1005 +
1006 + function updatecheckConsoleCommand(command, cmdargs) {
1007 + var r = '';
1008 + parent.parent.getServerTags(function (tags, error) {
1009 + var r2 = '';
1010 + if (error != null) { r2 += 'Exception: ' + error + '\r\n'; }
1011 + else { for (var i in tags) { r2 += i + ': ' + tags[i] + '\r\n'; } }
1012 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: r2, tag: command.tag })); } catch (ex) { }
1013 + });
1014 + r = "Checking server update...";
1015 + return r;
1016 + }
1017 +
1018 + function maintenanceConsoleCommand(command, cmdargs) {
1019 + var r = '';
1020 + var arg = null, changed = false;
1021 + if ((cmdargs['_'] != null) && (cmdargs['_'][0] != null)) { arg = cmdargs['_'][0].toLowerCase(); }
1022 + if (arg == 'enabled') { parent.parent.config.settings.maintenancemode = 1; changed = true; }
1023 + else if (arg == 'disabled') { delete parent.parent.config.settings.maintenancemode; changed = true; }
1024 + r = 'Maintenance mode: ' + ((parent.parent.config.settings.maintenancemode == null) ? 'Disabled' : 'Enabled');
1025 + if (changed == false) { r += '\r\nTo change type: maintenance [enabled|disabled]'; }
1026 + return r;
1027 + }
1028 +
1029 + function infoConsoleCommand(command, cmdargs) {
1030 + var r = '';
1031 + var info = process.memoryUsage();
1032 + info.dbType = ['None', 'NeDB', 'MongoJS', 'MongoDB'][parent.db.databaseType];
1033 + try { if (parent.parent.multiServer != null) { info.serverId = parent.parent.multiServer.serverid; } } catch (ex) { }
1034 + if (parent.db.databaseType == 3) { info.dbChangeStream = parent.db.changeStream; }
1035 + if (parent.parent.pluginHandler != null) { info.plugins = []; for (var i in parent.parent.pluginHandler.plugins) { info.plugins.push(i); } }
1036 + try { info.nodeVersion = process.version; } catch (ex) { }
1037 + try { info.meshVersion = parent.parent.currentVer; } catch (ex) { }
1038 + try { info.platform = process.platform; } catch (ex) { }
1039 + try { info.arch = process.arch; } catch (ex) { }
1040 + try { info.pid = process.pid; } catch (ex) { }
1041 + try { info.uptime = process.uptime(); } catch (ex) { }
1042 + try { info.cpuUsage = process.cpuUsage(); } catch (ex) { }
1043 + try { info.warnings = parent.parent.getServerWarnings(); } catch (ex) { }
1044 + try { info.database = ["Unknown", "NeDB", "MongoJS", "MongoDB", "MariaDB", "MySQL"][parent.parent.db.databaseType]; } catch (ex) { }
1045 + try { info.productionMode = ((process.env.NODE_ENV != null) && (process.env.NODE_ENV == 'production')); } catch (ex) { }
1046 + try { info.allDevGroupManagers = parent.parent.config.settings.managealldevicegroups; } catch (ex) { }
1047 + r = JSON.stringify(info, null, 4);
1048 + return r;
1049 + }
1050 +
1051 + function nodeconfigConsoleCommand(command, cmdargs) {
1052 + return JSON.stringify(process.config, null, 4);
1053 + }
1054 +
1055 + function versionsConsoleCommand(command, cmdargs) {
1056 + return JSON.stringify(process.versions, null, 4);
1057 + }
1058 +
1059 + function argsConsoleCommand(command, cmdargs) {
1060 + return 'args: ' + JSON.stringify(cmdargs);
1061 + }
1062 +
1063 + function usersessionsConsoleCommand(command, cmdargs) {
1064 + var r = '';
1065 + var userSessionCount = 0;
1066 + var filter = null;
1067 + var arg = cmdargs['_'][0];
1068 + if (typeof arg == 'string') { if (arg.indexOf('/') >= 0) { filter = arg; } else { filter = ('user/' + domain.id + '/' + arg); } }
1069 + for (var i in parent.wssessions) {
1070 + if ((filter == null) || (filter == i)) {
1071 + userSessionCount++;
1072 + r += (i + ', ' + parent.wssessions[i].length + ' session' + ((parent.wssessions[i].length > 1) ? 's' : '') + '.\r\n');
1073 + for (var j in parent.wssessions[i]) {
1074 + r += ' ' + parent.wssessions[i][j].clientIp + ' --> ' + parent.wssessions[i][j].sessionId + '\r\n';
1075 + }
1076 + }
1077 + }
1078 + if (userSessionCount == 0) { r = 'None.'; }
1079 + return r;
1080 + }
1081 +
1082 + function closeusersessionsConsoleCommand(command, cmdargs) {
1083 + var r = '';
1084 + var userSessionCount = 0;
1085 + var filter = null;
1086 + var arg = cmdargs['_'][0];
1087 + if (typeof arg == 'string') { if (arg.indexOf('/') >= 0) { filter = arg; } else { filter = ('user/' + domain.id + '/' + arg); } }
1088 + if (filter == null) {
1089 + r += "Usage: closeusersessions <username>";
1090 + } else {
1091 + r += "Closing user sessions for: " + filter + '\r\n';
1092 + for (var i in parent.wssessions) {
1093 + if (filter == i) {
1094 + userSessionCount++;
1095 + for (var j in parent.wssessions[i]) {
1096 + parent.wssessions[i][j].send(JSON.stringify({ action: 'stopped', msg: "Administrator forced disconnection" }));
1097 + parent.wssessions[i][j].close();
1098 + }
1099 + }
1100 + }
1101 + if (userSessionCount < 2) { r += 'Disconnected ' + userSessionCount + ' session.'; } else { r += 'Disconnected ' + userSessionCount + ' sessions.'; };
1102 + }
1103 + return r;
1104 + }
1105 +
1106 + function resetserverConsoleCommand(command, cmdargs) {
1107 + console.log("Server restart...");
1108 + process.exit(0);
1109 + }
1110 +
1111 + function tasklimiterConsoleCommand(command, cmdargs) {
1112 + var r = '';
1113 + if (parent.parent.taskLimiter != null) {
1114 + //var obj = { maxTasks: maxTasks, maxTaskTime: (maxTaskTime * 1000), nextTaskId: 0, currentCount: 0, current: {}, pending: [[], [], []], timer: null };
1115 + const tl = parent.parent.taskLimiter;
1116 + r += 'MaxTasks: ' + tl.maxTasks + ', NextTaskId: ' + tl.nextTaskId + '\r\n';
1117 + r += 'MaxTaskTime: ' + (tl.maxTaskTime / 1000) + ' seconds, Timer: ' + (tl.timer != null) + '\r\n';
1118 + var c = [];
1119 + for (var i in tl.current) { c.push(i); }
1120 + r += 'Current (' + tl.currentCount + '): [' + c.join(', ') + ']\r\n';
1121 + r += 'Pending (High/Med/Low): ' + tl.pending[0].length + ', ' + tl.pending[1].length + ', ' + tl.pending[2].length + '\r\n';
1122 + }
1123 + return r;
1124 + }
1125 +
1126 + function setmaxtasksConsoleCommand(command, cmdargs) {
1127 + var r = '';
1128 + if ((cmdargs["_"].length != 1) || (parseInt(cmdargs["_"][0]) < 1) || (parseInt(cmdargs["_"][0]) > 1000)) {
1129 + r = 'Usage: setmaxtasks [1 to 1000]';
1130 + } else {
1131 + parent.parent.taskLimiter.maxTasks = parseInt(cmdargs["_"][0]);
1132 + r = 'MaxTasks set to ' + parent.parent.taskLimiter.maxTasks + '.';
1133 + }
1134 + return r;
1135 + }
1136 +
1137 + function coresConsoleCommand(command, cmdargs) {
1138 + var r = '';
1139 + if (parent.parent.defaultMeshCores != null) {
1140 + for (var i in parent.parent.defaultMeshCores) {
1141 + r += i + ': ' + parent.parent.defaultMeshCores[i].length + ' bytes\r\n';
1142 + }
1143 + }
1144 + return r;
1145 + }
1146 +
1147 + function showpathsConsoleCommand(command, cmdargs) {
1148 + var r = '';
1149 + r = 'Parent: ' + parent.parent.parentpath + '\r\n';
1150 + r += 'Data: ' + parent.parent.datapath + '\r\n';
1151 + r += 'Files: ' + parent.parent.filespath + '\r\n';
1152 + r += 'Backup: ' + parent.parent.backuppath + '\r\n';
1153 + r += 'Record: ' + parent.parent.recordpath + '\r\n';
1154 + r += 'WebPublic: ' + parent.parent.webPublicPath + '\r\n';
1155 + r += 'WebViews: ' + parent.parent.webViewsPath + '\r\n';
1156 + if (parent.parent.webViewsOverridePath) { r += 'XWebPublic: ' + parent.parent.webViewsOverridePath + '\r\n'; }
1157 + if (parent.parent.webViewsOverridePath) { r += 'XWebViews: ' + parent.parent.webPublicOverridePath + '\r\n'; }
1158 + return r;
1159 + }
1160 +
1161 + function migrationagentsConsoleCommand(command, cmdargs) {
1162 + var r = '';
1163 + if (parent.parent.swarmserver == null) {
1164 + r = 'Swarm server not running.';
1165 + } else {
1166 + for (var i in parent.parent.swarmserver.migrationAgents) {
1167 + var arch = parent.parent.swarmserver.migrationAgents[i];
1168 + 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 />'; }
1169 + }
1170 + }
1171 + return r;
1172 + }
1173 +
1174 + function swarmstatsConsoleCommand(command, cmdargs) {
1175 + var r = '';
1176 + if (parent.parent.swarmserver == null) {
1177 + r = 'Swarm server not running.';
1178 + } else {
1179 + for (var i in parent.parent.swarmserver.stats) {
1180 + if (typeof parent.parent.swarmserver.stats[i] == 'object') {
1181 + r += i + ': ' + JSON.stringify(parent.parent.swarmserver.stats[i]) + '\r\n';
1182 + } else {
1183 + r += i + ': ' + parent.parent.swarmserver.stats[i] + '\r\n';
1184 + }
1185 + }
1186 + }
1187 + return r;
1188 + }
1189 +
1190 + function relaysConsoleCommand(command, cmdargs) {
1191 + var r = '';
1192 + for (var i in parent.wsrelays) {
1193 + r += 'id: ' + i + ', ' + ((parent.wsrelays[i].state == 2) ? 'connected' : 'pending');
1194 + if (parent.wsrelays[i].peer1 != null) {
1195 + r += ', ' + cleanRemoteAddr(parent.wsrelays[i].peer1.req.clientIp);
1196 + if (parent.wsrelays[i].peer1.user) { r += ' (User:' + parent.wsrelays[i].peer1.user.name + ')' }
1197 + }
1198 + if (parent.wsrelays[i].peer2 != null) {
1199 + r += ' to ' + cleanRemoteAddr(parent.wsrelays[i].peer2.req.clientIp);
1200 + if (parent.wsrelays[i].peer2.user) { r += ' (User:' + parent.wsrelays[i].peer2.user.name + ')' }
1201 + }
1202 + r += '\r\n';
1203 + }
1204 + if (r == '') { r = 'No relays.'; }
1205 + return r;
1206 + }
1207 +
1208 + function autobackupConsoleCommand(command, cmdargs) {
1209 + var r = '';
1210 + var backupResult = parent.db.performBackup(function (msg) {
1211 + try { ws.send(JSON.stringify({ action: 'serverconsole', value: msg, tag: command.tag })); } catch (ex) { }
1212 + });
1213 + if (backupResult == 0) { r = 'Starting auto-backup...'; } else { r = 'Backup alreay in progress.'; }
1214 + return r;
1215 + }
1216 +
1217 + function backupconfigConsoleCommand(command, cmdargs) {
1218 + return parent.db.getBackupConfig();
1219 + }
1220 +
1221 + function firebaseConsoleCommand(command, cmdargs) {
1222 + var r = '';
1223 + if (parent.parent.firebase == null) {
1224 + r = "Firebase push messaging not supported";
1225 + } else {
1226 + r = JSON.stringify(parent.parent.firebase.stats, null, 2);
1227 + }
1228 + return r;
1229 + }
1230 +
1231 // Process incoming web socket data from the browser
1232 function processWebSocketData(msg) {
1233 var command, i = 0, mesh = null, meshid = null, nodeid = null, meshlinks = null, change = 0;
@@ -911,554 +1595,16 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
1595 const cmd = cmdargs[0].toLowerCase();
1596 cmdargs = parseArgs(cmdargs);
1597
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
1598 + try {
1599 + r = consoleCommands[cmd](command, cmdargs);
1600 + } catch (e) {
1601 + if (consoleCommands[cmd] == null)
1602 r = 'Unknown command \"' + cmd + '\", type \"help\" for list of available commands.';
1457 - break;
1458 - }
1603 + else
1604 + console.log(e);
1605 }
1606
1461 - if (r != '') { try { ws.send(JSON.stringify({ action: 'serverconsole', value: r, tag: command.tag })); } catch (ex) { } }
1607 + if (r != null && r != '') { try { ws.send(JSON.stringify({ action: 'serverconsole', value: r, tag: command.tag })); } catch (ex) { } }
1608 break;
1609 }
1610 case 'msg':