| 1 | /* |
| 2 | Copyright 2022 Intel Corporation |
| 3 | @author Bryan Roe |
| 4 | |
| 5 | Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | you may not use this file except in compliance with the License. |
| 7 | You may obtain a copy of the License at |
| 8 | |
| 9 | http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | |
| 11 | Unless required by applicable law or agreed to in writing, software |
| 12 | distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | See the License for the specific language governing permissions and |
| 15 | limitations under the License. |
| 16 | |
| 17 | */ |
| 18 | |
| 19 | function trimObject(j) |
| 20 | { |
| 21 | var i; |
| 22 | for(i in j) |
| 23 | { |
| 24 | if (j[i] == null || (typeof(j[i])=='string' && j[i]=='') || i.startsWith('__')) { delete j[i];} |
| 25 | } |
| 26 | if (j['SerialNumber'] < 0) { var tmp = Buffer.alloc(4); tmp.writeInt32LE(j['SerialNumber']); j['SerialNumber'] = tmp.readUInt32LE(); } |
| 27 | return (j); |
| 28 | } |
| 29 | |
| 30 | |
| 31 | function getVolumes() |
| 32 | { |
| 33 | var v = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_Volume'); |
| 34 | var i; |
| 35 | |
| 36 | var ret = {}; |
| 37 | |
| 38 | for (i in v) |
| 39 | { |
| 40 | ret[v[i].DeviceID] = trimObject(v[i]); |
| 41 | } |
| 42 | try { |
| 43 | v = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume'); |
| 44 | for (i in v) |
| 45 | { |
| 46 | var tmp = trimObject(v[i]); |
| 47 | for (var k in tmp) |
| 48 | { |
| 49 | ret[tmp.DeviceID][k] = tmp[k]; |
| 50 | } |
| 51 | } |
| 52 | } catch (ex) { } |
| 53 | return (ret); |
| 54 | } |
| 55 | |
| 56 | function windows_volumes() |
| 57 | { |
| 58 | var promise = require('promise'); |
| 59 | var p1 = new promise(function (res, rej) { this._res = res; this._rej = rej; }); |
| 60 | var ret = {}; |
| 61 | var values = require('win-wmi').query('ROOT\\CIMV2', 'SELECT * FROM Win32_LogicalDisk', ['DeviceID', 'VolumeName', 'FileSystem', 'Size', 'FreeSpace', 'DriveType']); |
| 62 | if(values[0]){ |
| 63 | for (var i = 0; i < values.length; ++i) { |
| 64 | if (!values[i]['DeviceID']) { continue; } //always check for null to be sure |
| 65 | var drive = values[i]['DeviceID'].slice(0,-1); |
| 66 | ret[drive] = { |
| 67 | name: (values[i]['VolumeName'] ? values[i]['VolumeName'] : ""), |
| 68 | type: (values[i]['FileSystem'] ? values[i]['FileSystem'] : "Unknown"), |
| 69 | size: (values[i]['Size'] ? values[i]['Size'] : 0), |
| 70 | sizeremaining: (values[i]['FreeSpace'] ? values[i]['FreeSpace'] : 0), |
| 71 | removable: (values[i]['DriveType'] == 2), |
| 72 | cdrom: (values[i]['DriveType'] == 5) |
| 73 | }; |
| 74 | } |
| 75 | } |
| 76 | try { |
| 77 | values = require('win-wmi').query('ROOT\\CIMV2\\Security\\MicrosoftVolumeEncryption', 'SELECT * FROM Win32_EncryptableVolume', ['DriveLetter','ConversionStatus','ProtectionStatus']); |
| 78 | if(values[0]){ |
| 79 | // RegExps for the specific patterns in the manage-bde output, case-insensitive multiline |
| 80 | var reID = new RegExp("{[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}}", "mi"); |
| 81 | var rePass = new RegExp("[0-9]{6}-[0-9]{6}-[0-9]{6}-[0-9]{6}-[0-9]{6}-[0-9]{6}-[0-9]{6}-[0-9]{6}", "mi"); |
| 82 | var id, rp; |
| 83 | for (var i = 0; i < values.length; ++i) { |
| 84 | if (!values[i]['DriveLetter']) { continue; } //There can be volumes withouth a DriveLetter(=null), which errors the slice. Skip for now, fix later |
| 85 | var drive = values[i]['DriveLetter'].slice(0,-1); |
| 86 | var statuses = { |
| 87 | 0: 'FullyDecrypted', |
| 88 | 1: 'FullyEncrypted', |
| 89 | 2: 'EncryptionInProgress', |
| 90 | 3: 'DecryptionInProgress', |
| 91 | 4: 'EncryptionPaused', |
| 92 | 5: 'DecryptionPaused' |
| 93 | }; |
| 94 | ret[drive].volumeStatus = statuses.hasOwnProperty(values[i].ConversionStatus) ? statuses[values[i].ConversionStatus] : 'FullyDecrypted'; |
| 95 | ret[drive].protectionStatus = (values[i].ProtectionStatus == 0 ? 'Off' : (values[i].ProtectionStatus == 1 ? 'On' : 'Unknown')); |
| 96 | try { |
| 97 | var keychild = require('child_process').execFile(process.env['windir'] + '\\system32\\cmd.exe', ['/c', 'manage-bde -protectors -get ' + drive + ': -Type recoverypassword'], {}); |
| 98 | keychild.stdout.str = ''; keychild.stdout.on('data', function (c) { this.str += c.toString(); }); |
| 99 | keychild.waitExit(); |
| 100 | // find position of pattern, or null if not found |
| 101 | id = keychild.stdout.str.match(reID); |
| 102 | rp = keychild.stdout.str.match(rePass); |
| 103 | // recoveryPW can be empty if volume is locked |
| 104 | if (id) { ret[drive].identifier = id[0]; } |
| 105 | if (rp) { ret[drive].recoveryPassword = rp[0]; } |
| 106 | } catch(ex) { } // just carry on as we cant get bitlocker key |
| 107 | } |
| 108 | } |
| 109 | p1._res(ret); |
| 110 | } catch (ex) { p1._res(ret); } // just return volumes as cant get encryption/bitlocker |
| 111 | return (p1); |
| 112 | } |
| 113 | |
| 114 | module.exports = { |
| 115 | getVolumes: function () { try { return (getVolumes()); } catch (x) { return ({}); } }, |
| 116 | volumes_promise: windows_volumes |
| 117 | }; |