More BitLocker improvements.

Ylian Saint-Hilaire committed Feb 17, 2024 at 17:51 UTC f2bc7d5349871f40ef70f75f7541336a91f1de05
4 files changed +58 -80
agents/meshcore.js
+34 -37
@@ -654,22 +654,6 @@ var meshCoreObj = { action: 'coreinfo', value: (require('MeshAgent').coreHash ?
654 // Get the operating system description string
655 try { require('os').name().then(function (v) { meshCoreObj.osdesc = v; meshCoreObjChanged(); }); } catch (ex) { }
656
657 -// Get Volumes and BitLocker if Windows
658 -try {
659 - if (process.platform == 'win32') {
660 - if (require('computer-identifiers').volumes_promise != null) {
661 - var p = require('computer-identifiers').volumes_promise();
662 - p.then(function (res) {
663 - meshCoreObj.volumes = res;
664 - meshCoreObjChanged();
665 - });
666 - } else if (require('computer-identifiers').volumes != null) {
667 - meshCoreObj.volumes = require('computer-identifiers').volumes();
668 - meshCoreObjChanged();
669 - }
670 - }
671 -} catch(e) { }
672 -
657 // Setup logged in user monitoring (THIS IS BROKEN IN WIN7)
658 try {
659 var userSession = require('user-sessions');
@@ -1959,28 +1943,24 @@ function getSystemInformation(func) {
1943 results.hardware.network = { dns: require('os').dns() };
1944 replaceSpacesWithUnderscoresRec(results);
1945 var hasher = require('SHA384Stream').create();
1962 - // results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1963 - // func(results);
1946
1965 -
1947 // On Windows platforms, get volume information - Needs more testing.
1948 if (process.platform == 'win32')
1949 {
1950 results.pendingReboot = require('win-info').pendingReboot(); // Pending reboot
1970 -
1951 if (require('computer-identifiers').volumes_promise != null)
1952 {
1953 var p = require('computer-identifiers').volumes_promise();
1954 p.then(function (res)
1955 {
1976 - results.hardware.windows.volumes = res;
1956 + results.hardware.windows.volumes = cleanGetBitLockerVolumeInfo(res);
1957 results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1958 func(results);
1959 });
1960 }
1961 else if (require('computer-identifiers').volumes != null)
1962 {
1983 - results.hardware.windows.volumes = require('computer-identifiers').volumes();
1963 + results.hardware.windows.volumes = cleanGetBitLockerVolumeInfo(require('computer-identifiers').volumes());
1964 results.hash = hasher.syncHash(JSON.stringify(results)).toString('hex');
1965 func(results);
1966 }
@@ -3801,7 +3781,7 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
3781 if (require('os').dns != null) { availcommands += ',dnsinfo'; }
3782 try { require('linux-dhcp'); availcommands += ',dhcp'; } catch (ex) { }
3783 if (process.platform == 'win32') {
3804 - availcommands += ',cs,wpfhwacceleration,uac,volumes,rdpport';
3784 + availcommands += ',bitlocker,cs,wpfhwacceleration,uac,volumes,rdpport';
3785 if (bcdOK()) { availcommands += ',safemode'; }
3786 if (require('notifybar-desktop').DefaultPinned != null) { availcommands += ',privacybar'; }
3787 try { require('win-utils'); availcommands += ',taskbar'; } catch (ex) { }
@@ -3962,6 +3942,17 @@ function processConsoleCommand(cmd, args, rights, sessionid) {
3942 case 'volumes':
3943 response = JSON.stringify(require('win-volumes').getVolumes(), null, 1);
3944 break;
3945 + case 'bitlocker':
3946 + if (process.platform == 'win32') {
3947 + if (require('computer-identifiers').volumes_promise != null) {
3948 + var p = require('computer-identifiers').volumes_promise();
3949 + p.then(function (res) { sendConsoleText(JSON.stringify(cleanGetBitLockerVolumeInfo(res), null, 1), this.session); });
3950 + response = "Please wait...";
3951 + } else if (require('computer-identifiers').volumes != null) {
3952 + sendConsoleText(JSON.stringify(cleanGetBitLockerVolumeInfo(require('computer-identifiers').volumes()), null, 1), this.session);
3953 + }
3954 + }
3955 + break;
3956 case 'dhcp': // This command is only supported on Linux, this is because Linux does not give us the DNS suffix for each network adapter independently so we have to ask the DHCP server.
3957 {
3958 try { require('linux-dhcp'); } catch (ex) { response = 'Unknown command "dhcp", type "help" for list of available commands.'; break; }
@@ -5702,6 +5693,7 @@ function sendPeriodicServerUpdate(flags, force) {
5693 });
5694 } catch (ex) { }
5695 }
5696 +
5697 // Get Defender for Windows Server
5698 try {
5699 var d = require('win-info').defender();
@@ -5709,20 +5701,7 @@ function sendPeriodicServerUpdate(flags, force) {
5701 meshCoreObj.defender = res;
5702 meshCoreObjChanged();
5703 });
5712 - } catch (ex){ }
5713 - // Get Volumes and BitLocker if Windows
5714 - try {
5715 - if (require('computer-identifiers').volumes_promise != null){
5716 - var p = require('computer-identifiers').volumes_promise();
5717 - p.then(function (res){
5718 - meshCoreObj.volumes = res;
5719 - meshCoreObjChanged();
5720 - });
5721 - }else if (require('computer-identifiers').volumes != null){
5722 - meshCoreObj.volumes = require('computer-identifiers').volumes();
5723 - meshCoreObjChanged();
5724 - }
5725 - } catch(e) { }
5704 + } catch (ex) { }
5705 }
5706
5707 // Send available data right now
@@ -5736,6 +5715,24 @@ function sendPeriodicServerUpdate(flags, force) {
5715 }
5716 }
5717
5718 +// Sort the names in an object
5719 +function sortObject(obj) { return Object.keys(obj).sort().reduce(function(a, v) { a[v] = obj[v]; return a; }, {}); }
5720 +
5721 +// Fix the incoming data and cut down how much data we use
5722 +function cleanGetBitLockerVolumeInfo(volumes) {
5723 + for (var i in volumes) {
5724 + const v = volumes[i];
5725 + if (typeof v.size == 'string') { v.size = parseInt(v.size); }
5726 + if (v.identifier == '') { delete v.identifier; }
5727 + if (v.name == '') { delete v.name; }
5728 + if (v.removable != true) { delete v.removable; }
5729 + if (v.protectionStatus == 'On') { v.protectionStatus = true; } else { delete v.protectionStatus; }
5730 + if (v.volumeStatus == 'FullyDecrypted') { delete v.volumeStatus; }
5731 + if (v.recoveryPassword == '') { delete v.recoveryPassword; }
5732 + }
5733 + return sortObject(volumes);
5734 +}
5735 +
5736 // Once we are done collecting all the data, send to server if needed
5737 var LastPeriodicServerUpdate = null;
5738 var PeriodicServerUpdateNagleTimer = null;
meshagent.js
+2 -15
@@ -1940,21 +1940,8 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) {
1940 // TODO: Check that the agent has an interface that is the same as the one we got this websocket connection on. Only set if we have a match.
1941 }
1942
1943 - // Volumes and BitLocker
1944 - if (command.volumes != null) {
1945 - for (var i in command.volumes) {
1946 - // Fix the incoming data and cut down how much data we use
1947 - const v = command.volumes[i];
1948 - if (typeof v.size == 'string') { v.size = parseInt(v.size); }
1949 - if (v.recoveryPassword == '') { delete v.recoveryPassword; }
1950 - if (v.identifier == '') { delete v.identifier; }
1951 - if (v.name == '') { delete v.name; }
1952 - if (v.removable != true) { delete v.removable; }
1953 - if (v.protectionStatus == 'On') { v.protectionStatus = true; } else { delete v.protectionStatus; }
1954 - if (v.volumeStatus == "FullyDecrypted") { delete v.volumeStatus; }
1955 - }
1956 - if (JSON.stringify(device.volumes) != JSON.stringify(command.volumes)) { device.volumes = command.volumes; change = 1; }
1957 - }
1943 + // Remove old volumes and BitLocker data, this is part of sysinfo.
1944 + delete device.volumes;
1945
1946 // If there are changes, event the new device
1947 if (change == 1) {
meshuser.js
+6
@@ -6273,6 +6273,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
6273 delete doc.type;
6274 delete doc.domain;
6275 delete doc._id;
6276 +
6277 + // If this is not a device group admin users, don't send any BitLocker recovery passwords
6278 + if ((rights != MESHRIGHT_ADMIN) && (doc.hardware) && (doc.hardware.windows) && (doc.hardware.windows.volumes)) {
6279 + for (var i in doc.hardware.windows.volumes) { delete doc.hardware.windows.volumes[i].recoveryPassword; }
6280 + }
6281 +
6282 if (command.nodeinfo === true) { doc.node = node; doc.rights = rights; }
6283 obj.send(doc);
6284 } else {
views/default.handlebars
+16 -28
@@ -7451,21 +7451,6 @@
7451 x += addDeviceAttribute("Antivirus", y.join('<br />'));
7452 }
7453
7454 - /*
7455 - // Volumes and Bitlocker
7456 - if (node.volumes){
7457 - var bitlocker = [];
7458 - for (var i in node.volumes) {
7459 - if (typeof node.volumes[i].protectionStatus !== 'undefined' && node.volumes[i].protectionStatus == 'On'){
7460 - bitlocker.push('<div style=margin-bottom:2px>' + addKeyLinkConditional(i + ' - <span style=color:green>' + EscapeHtml(node.volumes[i].volumeStatus) + '</span>', 'p10showBitlockerKey(\'' + i + '\')', (userinfo.siteadmin == 0xFFFFFFFF)) + '</div>');
7461 - } else if (typeof node.volumes[i].protectionStatus !== 'undefined') {
7462 - bitlocker.push('<div style=margin-bottom:2px>' + i + ' - <span style=color:red>' + EscapeHtml(node.volumes[i].volumeStatus) + '</span>' + '</div>');
7463 - }
7464 - }
7465 - if (bitlocker.length > 0) { x += addDeviceAttribute("BitLocker", bitlocker.join(' ')); }
7466 - }
7467 - */
7468 -
7454 // Active Users
7455 if (node.users && node.conn && (node.users.length > 0) && (node.conn & 1)) { x += addDeviceAttribute(((node.users.length > 1)?"Active Users":"Active User"), EscapeHtml(node.users.join(', '))); }
7456
@@ -7918,13 +7903,6 @@
7903 }
7904 }
7905
7921 - function p10showBitlockerKey(drive) {
7922 - if (xxdialogMode) return false;
7923 - var x = '<div><p>' + "Identifier" + '</p><p style=user-select:text;font-weight:bold>' + EscapeHtml(currentNode.volumes[drive].identifier ? currentNode.volumes[drive].identifier : "Unknown") + '</p>';
7924 - x += '<p>' + "Recovery Password" + '</p><p style=user-select:text;font-weight:bold>' + EscapeHtml(currentNode.volumes[drive].recoveryPassword ? currentNode.volumes[drive].recoveryPassword : "Unknown") + '</p></div>';
7925 - setDialogMode(2, EscapeHtml(drive) + ': ' + "BitLocker Information", 1, null, x, '');
7926 - }
7927 -
7906 function p20editDeviceNotify() {
7907 if (xxdialogMode) return false;
7908 var devNotify = 0, fx = ((features2 & 0x00004000) && (userinfo.emailVerified))?1:0;
@@ -12123,24 +12101,27 @@
12101 }
12102
12103 // Volumes and Bitlocker
12126 - if (node.volumes) {
12104 + if (hardware.windows && hardware.windows.volumes) {
12105 var x = '';
12128 - for (var i in node.volumes) {
12129 - var m = node.volumes[i];
12106 + for (var i in hardware.windows.volumes) {
12107 + var m = hardware.windows.volumes[i];
12108 x += '<tr><td><div class=style10 style=border-radius:5px;padding:8px>';
12109 x += '<div style=margin-bottom:3px><b>' + i + ':' + (((m.name == null) || (m.name == '')) ? '' : (' - ' + EscapeHtml(m.name))) + '</b></div>';
12110 if (m.size) {
12111 var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
12134 - var i = parseInt(Math.floor(Math.log(Math.abs(m.size)) / Math.log(1024)), 10);
12135 - var fsize = (i === 0 ? `${m.size} ${sizes[i]}` : `${(m.size / (1024 ** i)).toFixed(2)} ${sizes[i]}`);
12112 + var j = parseInt(Math.floor(Math.log(Math.abs(m.size)) / Math.log(1024)), 10);
12113 + var fsize = (j === 0 ? `${m.size} ${sizes[j]}` : `${(m.size / (1024 ** j)).toFixed(2)} ${sizes[j]}`);
12114 x += addDetailItem("Capacity", EscapeHtml(fsize), s);
12115 }
12116 if (m.type) { x += addDetailItem("File System", (m.removable == true ? ("Removable" + ' / ') : '') + EscapeHtml(m.type), s); }
12117 +
12118 if (m.protectionStatus || m.volumeStatus) {
12119 var bitlockerState = [];
12120 if (m.protectionStatus) bitlockerState.push("Enabled");
12121 if (m.volumeStatus) bitlockerState.push(EscapeHtml(m.volumeStatus));
12143 - x += addDetailItem("BitLocker", bitlockerState.join(' - '), s);
12122 + bitlockerState = bitlockerState.join(' - ');
12123 + if (m.recoveryPassword) { bitlockerState += addKeyLink('', 'deviceDetailsShowBitlockerInfo(\"' + encodeURIComponentEx(i) + '\",\"' + encodeURIComponentEx(m.identifier) + '\",\"' + encodeURIComponentEx(m.recoveryPassword) + '\")'); }
12124 + x += addDetailItem("BitLocker", bitlockerState, s);
12125 }
12126 x += '</div>';
12127 }
@@ -12167,6 +12148,13 @@
12148 }
12149 }
12150
12151 + function deviceDetailsShowBitlockerInfo(drive, identifier, password) {
12152 + if (xxdialogMode) return false;
12153 + var x = '<div><p>' + "Identifier" + '</p><p style=user-select:text;font-weight:bold>' + (identifier ? decodeURIComponent(identifier) : "Unknown") + '</p>';
12154 + x += '<p>' + "Recovery Password" + '</p><p style=user-select:text;font-weight:bold>' + (password ? decodeURIComponent(password) : "Unknown") + '</p></div>';
12155 + setDialogMode(2, decodeURIComponent(drive) + ': ' + "BitLocker Information", 1, null, x, '');
12156 + }
12157 +
12158 //
12159 // CONSOLE
12160 //