2019-06-28 21:31:18 -04:00
#!/usr/bin/env node
2020-04-16 01:27:03 -04:00
// Make sure we have the dependency modules
try { require ( 'minimist' ) ; } catch ( ex ) { console . log ( 'Missing module "minimist", type "npm install minimist" to install it.' ) ; return ; }
try { require ( 'ws' ) ; } catch ( ex ) { console . log ( 'Missing module "ws", type "npm install ws" to install it.' ) ; return ; }
2019-06-28 21:31:18 -04:00
var settings = { } ;
2020-04-16 01:27:03 -04:00
const crypto = require ( 'crypto' ) ;
2019-06-28 21:31:18 -04:00
const args = require ( 'minimist' ) ( process . argv . slice ( 2 ) ) ;
2020-07-16 17:08:06 -04:00
const possibleCommands = [ 'listusers' , 'listusersessions' , 'listdevicegroups' , 'listdevices' , 'listusersofdevicegroup' , 'serverinfo' , 'userinfo' , 'adduser' , 'removeuser' , 'adddevicegroup' , 'removedevicegroup' , 'broadcast' , 'showevents' , 'addusertodevicegroup' , 'removeuserfromdevicegroup' , 'addusertodevice' , 'removeuserfromdevice' , 'sendinviteemail' , 'generateinvitelink' , 'config' , 'movetodevicegroup' , 'deviceinfo' , 'addusergroup' , 'listusergroups' , 'removeusergroup' , 'runcommand' , 'shell' , 'upload' , 'download' ] ;
2020-04-16 01:27:03 -04:00
if ( args . proxy != null ) { try { require ( 'https-proxy-agent' ) ; } catch ( ex ) { console . log ( 'Missing module "https-proxy-agent", type "npm install https-proxy-agent" to install it.' ) ; return ; } }
2019-06-28 21:31:18 -04:00
2019-06-30 14:34:27 -04:00
if ( args [ '_' ] . length == 0 ) {
console . log ( "MeshCtrl performs command line actions on a MeshCentral server." ) ;
console . log ( "Information at: https://meshcommander.com/meshcentral" ) ;
2019-06-28 21:31:18 -04:00
console . log ( "No action specified, use MeshCtrl like this:\r\n\r\n meshctrl [action] [arguments]\r\n" ) ;
console . log ( "Supported actions:" ) ;
2019-07-05 16:28:41 -04:00
console . log ( " Help [action] - Get help on an action." ) ;
console . log ( " ServerInfo - Show server information." ) ;
console . log ( " UserInfo - Show user information." ) ;
console . log ( " ListUsers - List user accounts." ) ;
2020-07-17 03:57:50 -04:00
console . log ( " ListUserSessions - List online users." ) ;
2020-05-27 20:23:38 -04:00
console . log ( " ListUserGroups - List user groups." ) ;
2019-07-05 16:28:41 -04:00
console . log ( " ListDevices - List devices." ) ;
console . log ( " ListDeviceGroups - List device groups." ) ;
console . log ( " ListUsersOfDeviceGroup - List the users in a device group." ) ;
2020-05-02 16:49:56 -04:00
console . log ( " DeviceInfo - Show information about a device." ) ;
2019-11-22 19:17:29 -05:00
console . log ( " Config - Perform operation on config.json file." ) ;
2019-07-05 16:28:41 -04:00
console . log ( " AddUser - Create a new user account." ) ;
console . log ( " RemoveUser - Delete a user account." ) ;
2020-05-27 20:23:38 -04:00
console . log ( " AddUserGroup - Create a new user group." ) ;
console . log ( " RemoveUserGroup - Delete a user group." ) ;
2019-07-05 16:28:41 -04:00
console . log ( " AddDeviceGroup - Create a new device group." ) ;
console . log ( " RemoveDeviceGroup - Delete a device group." ) ;
2020-04-16 11:46:53 -04:00
console . log ( " MoveToDeviceGroup - Move a device to a different device group." ) ;
2019-07-05 16:28:41 -04:00
console . log ( " AddUserToDeviceGroup - Add a user to a device group." ) ;
console . log ( " RemoveUserFromDeviceGroup - Remove a user from a device group." ) ;
2020-04-01 16:15:14 -04:00
console . log ( " AddUserToDevice - Add a user to a device." ) ;
console . log ( " RemoveUserFromDevice - Remove a user from a device." ) ;
2019-07-05 16:28:41 -04:00
console . log ( " SendInviteEmail - Send an agent install invitation email." ) ;
2019-09-23 14:45:10 -04:00
console . log ( " GenerateInviteLink - Create an invitation link." ) ;
2019-07-05 16:28:41 -04:00
console . log ( " Broadcast - Display a message to all online users." ) ;
2020-03-20 18:47:22 -04:00
console . log ( " ShowEvents - Display real-time server events in JSON format." ) ;
2020-07-13 15:25:14 -04:00
console . log ( " RunCommand - Run a shell command on a remote device." ) ;
2020-07-13 18:06:45 -04:00
console . log ( " Shell - Access command shell of a remote device." ) ;
2020-07-16 17:08:06 -04:00
console . log ( " Upload - Upload a file to a remote device." ) ;
console . log ( " Download - Download a file from a remote device." ) ;
2019-06-29 15:18:20 -04:00
console . log ( "\r\nSupported login arguments:" ) ;
2019-07-05 16:28:41 -04:00
console . log ( " --url [wss://server] - Server url, wss://localhost:443 is default." ) ;
console . log ( " --loginuser [username] - Login username, admin is default." ) ;
console . log ( " --loginpass [password] - Login password." ) ;
console . log ( " --token [number] - 2nd factor authentication token." ) ;
console . log ( " --loginkey [hex] - Server login key in hex." ) ;
console . log ( " --loginkeyfile [file] - File containing server login key in hex." ) ;
2020-05-27 20:23:38 -04:00
console . log ( " --logindomain [domainid] - Domain id, default is empty, only used with loginkey." ) ;
2020-04-16 01:27:03 -04:00
console . log ( " --proxy [http://proxy:1] - Specify an HTTP proxy." ) ;
2019-06-28 21:31:18 -04:00
return ;
} else {
settings . cmd = args [ '_' ] [ 0 ] . toLowerCase ( ) ;
2019-06-29 15:18:20 -04:00
if ( ( possibleCommands . indexOf ( settings . cmd ) == - 1 ) && ( settings . cmd != 'help' ) ) { console . log ( "Invalid command. Possible commands are: " + possibleCommands . join ( ', ' ) + '.' ) ; return ; }
2019-06-28 21:31:18 -04:00
//console.log(settings.cmd);
var ok = false ;
switch ( settings . cmd ) {
2019-11-22 19:17:29 -05:00
case 'config' : { performConfigOperations ( args ) ; return ; }
2019-06-28 21:31:18 -04:00
case 'serverinfo' : { ok = true ; break ; }
case 'userinfo' : { ok = true ; break ; }
case 'listusers' : { ok = true ; break ; }
2020-05-14 16:20:45 -04:00
case 'listusersessions' : { ok = true ; break ; }
2020-05-27 20:23:38 -04:00
case 'listusergroups' : { ok = true ; break ; }
2019-06-30 15:30:03 -04:00
case 'listdevicegroups' : { ok = true ; break ; }
2019-07-05 16:28:41 -04:00
case 'listdevices' : { ok = true ; break ; }
case 'listusersofdevicegroup' : {
2020-07-17 16:52:45 -04:00
if ( args . id == null ) { console . log ( "Missing group id, use --id '[groupid]'" ) ; }
2019-07-05 16:28:41 -04:00
else { ok = true ; }
break ;
}
2020-05-02 16:49:56 -04:00
case 'deviceinfo' : {
2020-07-17 16:52:45 -04:00
if ( args . id == null ) { console . log ( "Missing device id, use --id '[deviceid]'" ) ; }
2020-05-02 16:49:56 -04:00
else { ok = true ; }
break ;
}
2019-07-01 17:44:26 -04:00
case 'addusertodevicegroup' : {
2020-07-17 16:52:45 -04:00
if ( ( args . id == null ) && ( args . group == null ) ) { console . log ( "Device group identifier missing, use --id '[groupid]' or --group [groupname]" ) ; }
2020-04-08 14:26:35 -04:00
else if ( args . userid == null ) { console . log ( "Add user to group missing useid, use --userid [userid]" ) ; }
2019-07-01 17:44:26 -04:00
else { ok = true ; }
break ;
}
case 'removeuserfromdevicegroup' : {
2020-07-17 16:52:45 -04:00
if ( ( args . id == null ) && ( args . group == null ) ) { console . log ( "Device group identifier missing, use --id '[groupid]' or --group [groupname]" ) ; }
2020-04-08 14:26:35 -04:00
else if ( args . userid == null ) { console . log ( "Remove user from group missing useid, use --userid [userid]" ) ; }
2019-07-01 17:44:26 -04:00
else { ok = true ; }
break ;
}
2020-04-01 16:15:14 -04:00
case 'addusertodevice' : {
2020-07-17 16:52:45 -04:00
if ( args . userid == null ) { console . log ( "Add user to device missing userid, use --userid [userid]" ) ; }
else if ( args . id == null ) { console . log ( "Add user to device missing device id, use --id '[deviceid]'" ) ; }
2020-04-01 16:15:14 -04:00
else { ok = true ; }
break ;
}
case 'removeuserfromdevice' : {
2020-07-17 16:52:45 -04:00
if ( args . userid == null ) { console . log ( "Remove user from device missing userid, use --userid [userid]" ) ; }
else if ( args . id == null ) { console . log ( "Remove user from device missing device id, use --id '[deviceid]'" ) ; }
2020-04-01 16:15:14 -04:00
else { ok = true ; }
break ;
}
2019-06-30 14:34:27 -04:00
case 'adddevicegroup' : {
if ( args . name == null ) { console . log ( "Message group name, use --name [name]" ) ; }
else { ok = true ; }
break ;
}
case 'removedevicegroup' : {
2020-07-17 16:52:45 -04:00
if ( ( args . id == null ) && ( args . group == null ) ) { console . log ( "Device group identifier missing, use --id '[groupid]' or --group [groupname]" ) ; }
2019-06-30 14:34:27 -04:00
else { ok = true ; }
break ;
}
2020-04-16 11:46:53 -04:00
case 'movetodevicegroup' : {
2020-07-17 16:52:45 -04:00
if ( ( args . id == null ) && ( args . group == null ) ) { console . log ( "Device group identifier missing, use --id '[groupid]' or --group [groupname]" ) ; }
else if ( args . devid == null ) { console . log ( "Device identifier missing, use --devid '[deviceid]'" ) ; }
2020-04-16 11:46:53 -04:00
else { ok = true ; }
break ;
}
2019-06-30 14:34:27 -04:00
case 'broadcast' : {
if ( args . msg == null ) { console . log ( "Message missing, use --msg [message]" ) ; }
else { ok = true ; }
break ;
}
2020-03-20 18:47:22 -04:00
case 'showevents' : {
ok = true ;
break ;
}
2019-06-29 15:18:20 -04:00
case 'adduser' : {
if ( args . user == null ) { console . log ( "New account name missing, use --user [name]" ) ; }
2019-06-30 14:34:27 -04:00
else if ( ( args . pass == null ) && ( args . randompass == null ) ) { console . log ( "New account password missing, use --pass [password] or --randompass" ) ; }
2019-06-29 15:18:20 -04:00
else { ok = true ; }
break ;
}
case 'removeuser' : {
if ( args . userid == null ) { console . log ( "Remove account userid missing, use --userid [id]" ) ; }
else { ok = true ; }
break ;
}
2020-05-27 20:23:38 -04:00
case 'addusergroup' : {
if ( args . name == null ) { console . log ( "New user group name missing, use --name [name]" ) ; }
else { ok = true ; }
break ;
}
case 'removeusergroup' : {
2020-07-17 16:52:45 -04:00
if ( args . groupid == null ) { console . log ( "Remove user group id missing, use --groupid '[id]'" ) ; }
2020-05-27 20:23:38 -04:00
else { ok = true ; }
break ;
}
2019-07-05 16:28:41 -04:00
case 'sendinviteemail' : {
2020-07-17 16:52:45 -04:00
if ( ( args . id == null ) && ( args . group == null ) ) { console . log ( "Device group identifier missing, use --id '[groupid]' or --group [groupname]" ) ; }
2019-07-05 16:28:41 -04:00
else if ( args . email == null ) { console . log ( "Device email is missing, use --email [email]" ) ; }
2020-04-07 19:13:02 -04:00
else { ok = true ; }
2019-07-05 16:28:41 -04:00
break ;
}
2019-09-23 14:45:10 -04:00
case 'generateinvitelink' : {
2020-07-17 16:52:45 -04:00
if ( ( args . id == null ) && ( args . group == null ) ) { console . log ( "Device group identifier missing, use --id '[groupid]' or --group [groupname]" ) ; }
2019-09-23 14:45:10 -04:00
else if ( args . hours == null ) { console . log ( "Invitation validity period missing, use --hours [hours]" ) ; }
else { ok = true ; }
break ;
}
2020-07-13 15:25:14 -04:00
case 'runcommand' : {
2020-07-17 16:52:45 -04:00
if ( args . id == null ) { console . log ( "Missing device id, use --id '[deviceid]'" ) ; }
2020-07-13 15:25:14 -04:00
else if ( args . run == null ) { console . log ( "Missing run, use --run \"command\"" ) ; }
else { ok = true ; }
break ;
}
2020-07-13 18:06:45 -04:00
case 'shell' : {
2020-07-17 16:52:45 -04:00
if ( args . id == null ) { console . log ( "Missing device id, use --id '[deviceid]'" ) ; }
2020-07-13 18:06:45 -04:00
else { ok = true ; }
break ;
}
2020-07-16 17:08:06 -04:00
case 'upload' : {
2020-07-17 16:52:45 -04:00
if ( args . id == null ) { console . log ( "Missing device id, use --id '[deviceid]'" ) ; }
2020-07-16 17:08:06 -04:00
else if ( args . file == null ) { console . log ( "Local file missing, use --file [file] specify the file to upload" ) ; }
else if ( args . target == null ) { console . log ( "Remote target path missing, use --target [path] to specify the remote location" ) ; }
else if ( require ( 'fs' ) . existsSync ( args . file ) == false ) { console . log ( "Local file does not exists, check --file" ) ; }
else { ok = true ; }
break ;
}
case 'download' : {
2020-07-17 16:52:45 -04:00
if ( args . id == null ) { console . log ( "Missing device id, use --id '[deviceid]'" ) ; }
2020-07-16 17:08:06 -04:00
else if ( args . file == null ) { console . log ( "Remote file missing, use --file [file] specify the remote file to download" ) ; }
else if ( args . target == null ) { console . log ( "Target path missing, use --target [path] to specify the local download location" ) ; }
else { ok = true ; }
break ;
}
2019-06-29 15:18:20 -04:00
case 'help' : {
if ( args [ '_' ] . length < 2 ) {
console . log ( "Get help on an action. Type:\r\n\r\n help [action]\r\n\r\nPossible actions are: " + possibleCommands . join ( ', ' ) + '.' ) ;
} else {
switch ( args [ '_' ] [ 1 ] . toLowerCase ( ) ) {
2019-11-22 19:17:29 -05:00
case 'config' : {
2019-12-20 20:29:38 -05:00
displayConfigHelp ( ) ;
2019-11-22 19:17:29 -05:00
break ;
}
2019-07-05 16:28:41 -04:00
case 'sendinviteemail' : {
console . log ( "Send invitation email with instructions on how to install the mesh agent for a specific device group. Example usage:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl SendInviteEmail --id 'groupid' --message \"msg\" --email user@sample.com" ) ;
2020-04-07 19:13:02 -04:00
console . log ( " MeshCtrl SendInviteEmail --group \"My Computers\" --name \"Jack\" --email user@sample.com" ) ;
2019-07-05 16:28:41 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[groupid]' - Device group identifier (or --group)." ) ;
2020-04-07 19:13:02 -04:00
console . log ( " --group [groupname] - Device group name (or --id)." ) ;
2019-07-05 16:28:41 -04:00
console . log ( " --email [email] - Email address." ) ;
2020-04-07 19:13:02 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --name (name) - Name of recipient to be included in the email." ) ;
console . log ( " --message (msg) - Message to be included in the email." ) ;
2019-07-05 16:28:41 -04:00
break ;
}
2019-09-23 14:45:10 -04:00
case 'generateinvitelink' : {
console . log ( "Generate a agent invitation URL for a given group. Example usage:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl GenerateInviteLink --id 'groupid' --hours 24" ) ;
2020-04-07 19:13:02 -04:00
console . log ( " MeshCtrl GenerateInviteLink --group \"My Computers\" --hours 0" ) ;
2019-09-23 14:45:10 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[groupid]' - Device group identifier (or --group)." ) ;
2020-04-07 19:13:02 -04:00
console . log ( " --group [groupname] - Device group name (or --id)." ) ;
2019-09-23 14:45:10 -04:00
console . log ( " --hours [hours] - Validity period in hours or 0 for infinit." ) ;
break ;
}
2019-06-29 15:18:20 -04:00
case 'serverinfo' : {
console . log ( "Get information on the MeshCentral server, Example usages:\r\n" ) ;
console . log ( " MeshCtrl ServerInfo --loginuser myaccountname --loginpass mypassword" ) ;
console . log ( " MeshCtrl ServerInfo --loginuser myaccountname --loginkeyfile key.txt" ) ;
console . log ( "\r\nOptional arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --json - Show result as JSON." ) ;
2019-06-29 15:18:20 -04:00
break ;
}
case 'userinfo' : {
console . log ( "Get account information for the login account, Example usages:\r\n" ) ;
console . log ( " MeshCtrl UserInfo --loginuser myaccountname --loginpass mypassword" ) ;
console . log ( " MeshCtrl UserInfo --loginuser myaccountname --loginkeyfile key.txt" ) ;
console . log ( "\r\nOptional arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --json - Show result as JSON." ) ;
2019-06-29 15:18:20 -04:00
break ;
}
case 'listusers' : {
console . log ( "List the account on the MeshCentral server, Example usages:\r\n" ) ;
console . log ( " MeshCtrl ListUsers" ) ;
console . log ( " MeshCtrl ListUsers --json" ) ;
console . log ( " MeshCtrl ListUsers --nameexists \"bob\"" ) ;
2019-12-12 14:44:03 -05:00
console . log ( " MeshCtrl ListUsers --filter 2fa" ) ;
2019-06-29 15:18:20 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --idexists [id] - Return 1 if id exists, 0 if not." ) ;
console . log ( " --nameexists [name] - Return id if name exists." ) ;
2019-12-12 14:44:03 -05:00
console . log ( " --filter [filter1,...] - Filter user names: 2FA, NO2FA." ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --json - Show result as JSON." ) ;
2019-06-29 15:18:20 -04:00
break ;
}
2020-05-14 16:20:45 -04:00
case 'listusersessions' : {
console . log ( "List active user sessions on the MeshCentral server, Example usages:\r\n" ) ;
console . log ( " MeshCtrl ListUserSessions" ) ;
console . log ( " MeshCtrl ListUserSessions --json" ) ;
break ;
}
2020-05-27 20:23:38 -04:00
case 'listusergroups' : {
console . log ( "List user groups on the MeshCentral server, Example usages:\r\n" ) ;
console . log ( " MeshCtrl ListUserGroups" ) ;
console . log ( " MeshCtrl ListUserGroups --json" ) ;
break ;
}
2019-06-30 14:34:27 -04:00
case 'listdevicegroups' : {
2019-06-29 15:18:20 -04:00
console . log ( "List the device groups for this account, Example usages:\r\n" ) ;
2019-06-30 14:34:27 -04:00
console . log ( " MeshCtrl ListDeviceGroups " ) ;
console . log ( " MeshCtrl ListDeviceGroups --json" ) ;
2019-06-29 15:18:20 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --idexists [id] - Return 1 if id exists, 0 if not." ) ;
console . log ( " --nameexists [name] - Return id if name exists." ) ;
console . log ( " --emailexists [email] - Return id if email exists." ) ;
2020-07-15 18:12:01 -04:00
console . log ( " --hex - Display meshid in hex format." ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --json - Show result as JSON." ) ;
2019-06-29 15:18:20 -04:00
break ;
}
2019-07-05 16:28:41 -04:00
case 'listdevices' : {
console . log ( "List devices, Example usages:\r\n" ) ;
console . log ( " MeshCtrl ListDevices" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl ListDevices -id '[groupid]' --json" ) ;
2019-07-05 16:28:41 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[groupid]' - Filter by group identifier (or --group)." ) ;
console . log ( " --group [groupname] - Filter by group name (or --id)." ) ;
2019-07-05 16:28:41 -04:00
console . log ( " --count - Only return the device count." ) ;
console . log ( " --json - Show result as JSON." ) ;
break ;
}
case 'listusersofdevicegroup' : {
console . log ( "List users that have permissions for a given device group, Example usage:\r\n" ) ;
console . log ( " MeshCtrl ListUserOfDeviceGroup " ) ;
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[groupid]' - Device group identifier." ) ;
2019-07-05 16:28:41 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --json - Show result as JSON." ) ;
break ;
}
2019-06-29 15:18:20 -04:00
case 'adduser' : {
console . log ( "Add a new user account, Example usages:\r\n" ) ;
console . log ( " MeshCtrl AddUser --user newaccountname --pass newpassword" ) ;
console . log ( "\r\nRequired arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --user [name] - New account name." ) ;
console . log ( " --pass [password] - New account password." ) ;
console . log ( " --randompass - Create account with a random password." ) ;
2019-06-29 15:18:20 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --email [email] - New account email address." ) ;
console . log ( " --emailverified - New account email is verified." ) ;
console . log ( " --resetpass - Request password reset on next login." ) ;
console . log ( " --siteadmin - Create the account as full site administrator." ) ;
console . log ( " --manageusers - Allow this account to manage server users." ) ;
console . log ( " --fileaccess - Allow this account to store server files." ) ;
console . log ( " --serverupdate - Allow this account to update the server." ) ;
console . log ( " --locked - This account will be locked." ) ;
console . log ( " --nonewgroups - Account will not be allowed to create device groups." ) ;
console . log ( " --notools - Account not see MeshCMD download links." ) ;
2020-05-27 20:23:38 -04:00
console . log ( " --domain [domain] - Account domain, only for cross-domain admins." ) ;
2019-06-29 15:18:20 -04:00
break ;
}
case 'removeuser' : {
console . log ( "Delete a user account, Example usages:\r\n" ) ;
console . log ( " MeshCtrl RemoveUser --userid accountid" ) ;
console . log ( "\r\nRequired arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --userid [id] - Account identifier." ) ;
2019-06-29 15:18:20 -04:00
break ;
}
2019-06-30 14:34:27 -04:00
case 'adddevicegroup' : {
console . log ( "Add a device group, Example usages:\r\n" ) ;
console . log ( " MeshCtrl AddDeviceGroup --name newgroupname" ) ;
console . log ( " MeshCtrl AddDeviceGroup --name newgroupname --desc description --amtonly" ) ;
console . log ( "\r\nRequired arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --name [name] - Name of the new group." ) ;
2019-06-30 14:34:27 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
2019-07-01 19:46:05 -04:00
console . log ( " --desc [description] - New group description." ) ;
console . log ( " --amtonly - New group is agent-less, Intel AMT only." ) ;
2019-06-30 14:34:27 -04:00
break ;
}
case 'removedevicegroup' : {
console . log ( "Remove a device group, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl RemoveDeviceGroup --id 'groupid'" ) ;
2019-06-30 14:34:27 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[groupid]' - Device group identifier (or --group)." ) ;
2020-04-08 14:26:35 -04:00
console . log ( " --group [groupname] - Device group name (or --id)." ) ;
2019-06-30 14:34:27 -04:00
break ;
}
2020-04-16 11:46:53 -04:00
case 'movetodevicegroup' : {
console . log ( "Move a device to a new device group, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl MoveToDeviceGroup --devid 'deviceid' --id 'groupid'" ) ;
2020-04-16 11:46:53 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[groupid]' - Device group identifier (or --group)." ) ;
2020-04-16 11:46:53 -04:00
console . log ( " --group [groupname] - Device group name (or --id)." ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --devid '[deviceid]' - Device identifier." ) ;
2020-04-16 11:46:53 -04:00
break ;
}
2019-07-01 17:44:26 -04:00
case 'addusertodevicegroup' : {
console . log ( "Add a user to a device group, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl AddUserToDeviceGroup --id 'groupid' --userid userid --fullrights" ) ;
2020-04-08 14:26:35 -04:00
console . log ( " MeshCtrl AddUserToDeviceGroup --group groupname --userid userid --editgroup --manageusers" ) ;
2019-07-01 17:44:26 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[groupid]' - Device group identifier (or --group)." ) ;
2020-04-08 14:26:35 -04:00
console . log ( " --group [groupname] - Device group name (or --id)." ) ;
2019-07-01 17:44:26 -04:00
console . log ( " --userid [userid] - The user identifier." ) ;
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --fullrights - Allow full rights over this device group." ) ;
console . log ( " --editgroup - Allow the user to edit group information." ) ;
console . log ( " --manageusers - Allow the user to add/remove users." ) ;
console . log ( " --managedevices - Allow the user to edit device information." ) ;
console . log ( " --remotecontrol - Allow device remote control operations." ) ;
console . log ( " --agentconsole - Allow agent console operations." ) ;
console . log ( " --serverfiles - Allow access to group server files." ) ;
console . log ( " --wakedevices - Allow device wake operation." ) ;
console . log ( " --notes - Allow editing of device notes." ) ;
console . log ( " --desktopviewonly - Restrict user to view-only remote desktop." ) ;
console . log ( " --limiteddesktop - Limit remote desktop keys." ) ;
console . log ( " --noterminal - Hide the terminal tab from this user." ) ;
console . log ( " --nofiles - Hide the files tab from this user." ) ;
console . log ( " --noamt - Hide the Intel AMT tab from this user." ) ;
2020-04-01 16:15:14 -04:00
console . log ( " --limitedevents - User can only see his own events." ) ;
console . log ( " --chatnotify - Allow chat and notification options." ) ;
console . log ( " --uninstall - Allow remote uninstall of the agent." ) ;
if ( args . limiteddesktop ) { meshrights |= 4096 ; }
if ( args . limitedevents ) { meshrights |= 8192 ; }
if ( args . chatnotify ) { meshrights |= 16384 ; }
if ( args . uninstall ) { meshrights |= 32768 ; }
2019-07-01 17:44:26 -04:00
break ;
}
case 'removeuserfromdevicegroup' : {
console . log ( "Remove a user from a device group, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl RemoveuserFromDeviceGroup --id 'groupid' --userid userid" ) ;
2019-07-01 17:44:26 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[groupid]' - Device group identifier (or --group)." ) ;
2020-04-08 14:26:35 -04:00
console . log ( " --group [groupname] - Device group name (or --id)." ) ;
2019-07-01 17:44:26 -04:00
console . log ( " --userid [userid] - The user identifier." ) ;
break ;
}
2020-04-01 16:15:14 -04:00
case 'addusertodevice' : {
console . log ( "Add a user to a device, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl AddUserToDevice --id 'deviceid' --userid userid --fullrights" ) ;
console . log ( " MeshCtrl AddUserToDevice --id 'deviceid' --userid userid --remotecontrol" ) ;
2020-04-01 16:15:14 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[deviceid]' - The device identifier." ) ;
2020-04-01 16:15:14 -04:00
console . log ( " --userid [userid] - The user identifier." ) ;
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --fullrights - Allow full rights over this device." ) ;
console . log ( " --remotecontrol - Allow device remote control operations." ) ;
console . log ( " --agentconsole - Allow agent console operations." ) ;
console . log ( " --serverfiles - Allow access to group server files." ) ;
console . log ( " --wakedevices - Allow device wake operation." ) ;
console . log ( " --notes - Allow editing of device notes." ) ;
console . log ( " --desktopviewonly - Restrict user to view-only remote desktop." ) ;
console . log ( " --limiteddesktop - Limit remote desktop keys." ) ;
console . log ( " --noterminal - Hide the terminal tab from this user." ) ;
console . log ( " --nofiles - Hide the files tab from this user." ) ;
console . log ( " --noamt - Hide the Intel AMT tab from this user." ) ;
console . log ( " --limitedevents - User can only see his own events." ) ;
console . log ( " --chatnotify - Allow chat and notification options." ) ;
console . log ( " --uninstall - Allow remote uninstall of the agent." ) ;
break ;
}
case 'removeuserfromdevice' : {
console . log ( "Remove a user from a device, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl RemoveuserFromDeviceGroup --id 'deviceid' --userid userid" ) ;
2020-04-01 16:15:14 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[deviceid]' - The device identifier." ) ;
2020-04-01 16:15:14 -04:00
console . log ( " --userid [userid] - The user identifier." ) ;
break ;
}
2019-06-30 14:34:27 -04:00
case 'broadcast' : {
console . log ( "Display a message to all logged in users, Example usages:\r\n" ) ;
console . log ( " MeshCtrl Broadcast --msg \"This is a test\"" ) ;
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-04-01 16:15:14 -04:00
console . log ( " --msg [message] - Message to display." ) ;
2019-06-30 14:34:27 -04:00
break ;
}
2020-05-02 16:49:56 -04:00
case 'deviceinfo' : {
console . log ( "Display information about a device, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl DeviceInfo --id 'deviceid'" ) ;
console . log ( " MeshCtrl DeviceInfo --id 'deviceid' --json" ) ;
2020-05-02 16:49:56 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[deviceid]' - The device identifier." ) ;
2020-05-02 16:49:56 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --raw - Output raw data in JSON format." ) ;
console . log ( " --json - Give results in JSON format." ) ;
break ;
}
2020-07-13 15:25:14 -04:00
case 'runcommand' : {
console . log ( "Run a shell command on a remote device, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl RunCommand --id 'deviceid' --run \"command\"" ) ;
console . log ( " MeshCtrl RunCommand --id 'deviceid' --run \"command\" --powershell" ) ;
2020-07-13 15:25:14 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[deviceid]' - The device identifier." ) ;
2020-07-13 15:25:14 -04:00
console . log ( " --run \"[command]\" - Shell command to execute on the remote device." ) ;
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --powershell - Run in Windows PowerShell." ) ;
break ;
}
2020-07-13 18:06:45 -04:00
case 'shell' : {
console . log ( "Access a command shell on a remote device, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl Shell --id 'deviceid'" ) ;
console . log ( " MeshCtrl Shell --id 'deviceid' --powershell" ) ;
2020-07-13 18:06:45 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[deviceid]' - The device identifier." ) ;
2020-07-13 18:06:45 -04:00
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --powershell - Run a Windows PowerShell." ) ;
break ;
}
2020-07-16 17:08:06 -04:00
case 'upload' : {
console . log ( "Upload a local file to a remote device, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl Upload --id 'deviceid' --file sample.txt --target c:\\" ) ;
console . log ( " MeshCtrl Upload --id 'deviceid' --file sample.txt --target /tmp" ) ;
2020-07-16 17:08:06 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[deviceid]' - The device identifier." ) ;
2020-07-16 17:08:06 -04:00
console . log ( " --file [localfile] - The local file to upload." ) ;
console . log ( " --target [remotepath] - The remote path to upload the file to." ) ;
break ;
}
case 'download' : {
console . log ( "Download a file from a remote device, Example usages:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " MeshCtrl Download --id 'deviceid' --file C:\\sample.txt --target c:\\temp" ) ;
console . log ( " MeshCtrl Download --id 'deviceid' --file /tmp/sample.txt --target /tmp" ) ;
2020-07-16 17:08:06 -04:00
console . log ( "\r\nRequired arguments:\r\n" ) ;
2020-07-17 16:52:45 -04:00
console . log ( " --id '[deviceid]' - The device identifier." ) ;
2020-07-16 17:08:06 -04:00
console . log ( " --file [remotefile] - The remote file to download." ) ;
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --target [localpath] - The local path to download the file to." ) ;
break ;
}
2019-06-29 15:18:20 -04:00
default : {
console . log ( "Get help on an action. Type:\r\n\r\n help [action]\r\n\r\nPossible actions are: " + possibleCommands . join ( ', ' ) + '.' ) ;
}
}
}
break ;
}
2019-06-28 21:31:18 -04:00
}
2019-06-29 15:18:20 -04:00
if ( ok ) { serverConnect ( ) ; }
2019-06-28 21:31:18 -04:00
}
2019-12-20 20:29:38 -05:00
function displayConfigHelp ( ) {
console . log ( "Perform operations on the config.json file. Example usage:\r\n" ) ;
console . log ( " MeshCtrl config --show" ) ;
console . log ( "\r\nOptional arguments:\r\n" ) ;
console . log ( " --show - Display the config.json file." ) ;
console . log ( " --listdomains - Display non-default domains." ) ;
console . log ( " --adddomain [domain] - Add a domain." ) ;
console . log ( " --removedomain [domain] - Remove a domain." ) ;
console . log ( " --settodomain [domain] - Set values to the domain." ) ;
console . log ( " --removefromdomain [domain] - Remove values from the domain." ) ;
console . log ( "\r\nWith adddomain, removedomain, settodomain and removefromdomain you can add the key and value pair. For example:\r\n" ) ;
console . log ( " --adddomain \"MyDomain\" --title \"My Server Name\" --newAccounts false" ) ;
console . log ( " --settodomain \"MyDomain\" --title \"My Server Name\"" ) ;
console . log ( " --removefromdomain \"MyDomain\" --title" ) ;
}
2019-11-22 19:17:29 -05:00
function performConfigOperations ( args ) {
2020-05-15 15:09:31 -04:00
var domainValues = [ 'title' , 'title2' , 'titlepicture' , 'trustedcert' , 'welcomepicture' , 'welcometext' , 'userquota' , 'meshquota' , 'newaccounts' , 'usernameisemail' , 'newaccountemaildomains' , 'newaccountspass' , 'newaccountsrights' , 'geolocation' , 'lockagentdownload' , 'userconsentflags' , 'Usersessionidletimeout' , 'auth' , 'ldapoptions' , 'ldapusername' , 'ldapuserbinarykey' , 'ldapuseremail' , 'footer' , 'certurl' , 'loginKey' , 'userallowedip' , 'agentallowedip' , 'agentnoproxy' , 'agentconfig' , 'orphanagentuser' , 'httpheaders' , 'yubikey' , 'passwordrequirements' , 'limits' , 'amtacmactivation' , 'redirects' , 'sessionrecording' , 'hide' , 'loginkey' ] ;
2019-12-21 18:05:58 -05:00
var domainObjectValues = [ 'ldapoptions' , 'httpheaders' , 'yubikey' , 'passwordrequirements' , 'limits' , 'amtacmactivation' , 'redirects' , 'sessionrecording' ] ;
var domainArrayValues = [ 'newaccountemaildomains' , 'newaccountsrights' , 'loginkey' , 'agentconfig' ] ;
2019-11-22 19:17:29 -05:00
var configChange = false ;
var fs = require ( 'fs' ) ;
var path = require ( 'path' ) ;
2020-06-12 15:39:51 -04:00
var configFile = 'config.json' ;
2019-12-20 20:29:38 -05:00
var didSomething = 0 ;
2019-12-12 14:44:03 -05:00
if ( fs . existsSync ( configFile ) == false ) { configFile = path . join ( 'meshcentral-data' , 'config.json' ) ; }
2020-06-12 15:39:51 -04:00
if ( fs . existsSync ( configFile ) == false ) { configFile = path . join ( _ _dirname , 'config.json' ) ; }
2019-11-22 19:17:29 -05:00
if ( fs . existsSync ( configFile ) == false ) { configFile = path . join ( _ _dirname , 'meshcentral-data' , 'config.json' ) ; }
if ( fs . existsSync ( configFile ) == false ) { configFile = path . join ( _ _dirname , '..' , 'meshcentral-data' , 'config.json' ) ; }
2020-06-23 15:35:23 -04:00
if ( fs . existsSync ( configFile ) == false ) { configFile = path . join ( _ _dirname , '..' , '..' , 'meshcentral-data' , 'config.json' ) ; }
2019-11-22 19:17:29 -05:00
if ( fs . existsSync ( configFile ) == false ) { console . log ( "Unable to find config.json." ) ; return ; }
var config = null ;
2020-06-23 15:35:23 -04:00
try { config = fs . readFileSync ( configFile ) . toString ( 'utf8' ) ; } catch ( ex ) { console . log ( "Error: Unable to read config.json" ) ; return ; }
try { config = require ( configFile ) ; } catch ( e ) { console . log ( 'ERROR: Unable to parse ' + configFilePath + '.' ) ; return null ; }
2019-11-22 19:17:29 -05:00
if ( args . adddomain != null ) {
2019-12-20 20:29:38 -05:00
didSomething ++ ;
2019-11-22 19:17:29 -05:00
if ( config . domains == null ) { config . domains = { } ; }
if ( config . domains [ args . adddomain ] != null ) { console . log ( "Error: Domain \"" + args . adddomain + "\" already exists" ) ; }
else {
configChange = true ;
config . domains [ args . adddomain ] = { } ;
for ( var i in args ) {
if ( domainValues . indexOf ( i . toLowerCase ( ) ) >= 0 ) {
if ( args [ i ] == 'true' ) { args [ i ] = true ; } else if ( args [ i ] == 'false' ) { args [ i ] = false ; } else if ( parseInt ( args [ i ] ) == args [ i ] ) { args [ i ] = parseInt ( args [ i ] ) ; }
config . domains [ args . adddomain ] [ i ] = args [ i ] ;
configChange = true ;
}
}
}
}
if ( args . removedomain != null ) {
2019-12-20 20:29:38 -05:00
didSomething ++ ;
2019-11-22 19:17:29 -05:00
if ( config . domains == null ) { config . domains = { } ; }
if ( config . domains [ args . removedomain ] == null ) { console . log ( "Error: Domain \"" + args . removedomain + "\" does not exist" ) ; }
else { delete config . domains [ args . removedomain ] ; configChange = true ; }
}
if ( args . settodomain != null ) {
2019-12-20 20:29:38 -05:00
didSomething ++ ;
2019-11-22 19:17:29 -05:00
if ( config . domains == null ) { config . domains = { } ; }
2019-12-21 18:05:58 -05:00
if ( args . settodomain == true ) { args . settodomain = '' ; }
2019-11-22 19:17:29 -05:00
if ( config . domains [ args . settodomain ] == null ) { console . log ( "Error: Domain \"" + args . settodomain + "\" does not exist" ) ; }
else {
for ( var i in args ) {
2019-12-21 18:05:58 -05:00
if ( ( i == '_' ) || ( i == 'settodomain' ) ) continue ;
2019-11-22 19:17:29 -05:00
if ( domainValues . indexOf ( i . toLowerCase ( ) ) >= 0 ) {
2019-12-21 18:05:58 -05:00
var isObj = ( domainObjectValues . indexOf ( i . toLowerCase ( ) ) >= 0 ) ;
var isArr = ( domainArrayValues . indexOf ( i . toLowerCase ( ) ) >= 0 ) ;
if ( ( isObj == false ) && ( isArr == false ) ) {
// Simple value set
if ( args [ i ] == '' ) { delete config . domains [ args . settodomain ] [ i ] ; configChange = true ; } else {
if ( args [ i ] == 'true' ) { args [ i ] = true ; } else if ( args [ i ] == 'false' ) { args [ i ] = false ; } else if ( parseInt ( args [ i ] ) == args [ i ] ) { args [ i ] = parseInt ( args [ i ] ) ; }
config . domains [ args . settodomain ] [ i ] = args [ i ] ;
configChange = true ;
}
} else if ( isObj || isArr ) {
// Set an object/array value
if ( args [ i ] == '' ) { delete config . domains [ args . settodomain ] [ i ] ; configChange = true ; } else {
var x = null ;
try { x = JSON . parse ( args [ i ] ) ; } catch ( ex ) { }
if ( ( x == null ) || ( typeof x != 'object' ) ) { console . log ( "Unable to parse JSON for " + i + "." ) ; } else {
if ( isArr && Array . isArray ( x ) == false ) {
console . log ( "Value " + i + " must be an array." ) ;
} else if ( ! isArr && Array . isArray ( x ) == true ) {
console . log ( "Value " + i + " must be an object." ) ;
} else {
config . domains [ args . settodomain ] [ i ] = x ;
configChange = true ;
}
}
}
2019-11-22 19:17:29 -05:00
}
2019-12-21 18:05:58 -05:00
} else {
console . log ( 'Invalid configuration value: ' + i ) ;
2019-11-22 19:17:29 -05:00
}
}
}
}
if ( args . removefromdomain != null ) {
2019-12-20 20:29:38 -05:00
didSomething ++ ;
2019-11-22 19:17:29 -05:00
if ( config . domains == null ) { config . domains = { } ; }
if ( config . domains [ args . removefromdomain ] == null ) { console . log ( "Error: Domain \"" + args . removefromdomain + "\" does not exist" ) ; }
else { for ( var i in args ) { if ( domainValues . indexOf ( i . toLowerCase ( ) ) >= 0 ) { delete config . domains [ args . removefromdomain ] [ i ] ; configChange = true ; } } }
}
if ( configChange ) {
try { fs . writeFileSync ( configFile , JSON . stringify ( config , null , 2 ) ) ; } catch ( ex ) { console . log ( "Error: Unable to read config.json" ) ; return ; }
}
2019-12-20 20:29:38 -05:00
if ( args . show == 1 ) {
console . log ( JSON . stringify ( config , null , 2 ) ) ; return ;
} else if ( args . listdomains == 1 ) {
if ( config . domains == null ) {
console . log ( 'No domains found.' ) ; return ;
} else {
// Show the list of active domains, skip the default one.
for ( var i in config . domains ) { if ( ( i != '' ) && ( i [ 0 ] != '_' ) ) { console . log ( i ) ; } } return ;
}
} else {
if ( didSomething == 0 ) {
displayConfigHelp ( ) ;
} else {
2019-12-21 18:05:58 -05:00
console . log ( "Done." ) ;
2019-12-20 20:29:38 -05:00
}
}
2019-11-22 19:17:29 -05:00
}
2019-06-30 14:34:27 -04:00
function onVerifyServer ( clientName , certs ) { return null ; }
2019-06-28 21:31:18 -04:00
function serverConnect ( ) {
const WebSocket = require ( 'ws' ) ;
2019-06-29 15:18:20 -04:00
var url = 'wss://localhost/control.ashx' ;
if ( args . url ) {
url = args . url ;
if ( url . length < 5 ) { console . log ( "Invalid url." ) ; process . exit ( ) ; return ; }
if ( ( url . startsWith ( 'wss://' ) == false ) && ( url . startsWith ( 'ws://' ) == false ) ) { console . log ( "Invalid url." ) ; process . exit ( ) ; return ; }
if ( url . endsWith ( '/' ) == false ) { url += '/' ; }
url += 'control.ashx' ;
}
2019-06-30 14:34:27 -04:00
// TODO: checkServerIdentity does not work???
2019-06-29 15:18:20 -04:00
var options = { rejectUnauthorized : false , checkServerIdentity : onVerifyServer }
2020-04-16 01:27:03 -04:00
// Setup the HTTP proxy if needed
if ( args . proxy != null ) {
const HttpsProxyAgent = require ( 'https-proxy-agent' ) ;
options . agent = new HttpsProxyAgent ( require ( 'url' ) . parse ( args . proxy ) ) ;
}
2019-06-29 15:18:20 -04:00
// Password authentication
if ( args . loginpass != null ) {
var username = 'admin' ;
2019-09-20 18:20:59 -04:00
if ( args . loginuser != null ) { username = args . loginuser ; }
2019-06-29 15:18:20 -04:00
var token = '' ;
if ( args . token != null ) { token = ',' + Buffer . from ( '' + args . token ) . toString ( 'base64' ) ; }
options . headers = { 'x-meshauth' : Buffer . from ( username ) . toString ( 'base64' ) + ',' + Buffer . from ( args . loginpass ) . toString ( 'base64' ) + token }
}
// Cookie authentication
var ckey = null ;
if ( args . loginkey != null ) {
// User key passed in a argument hex
if ( args . loginkey . length != 160 ) { console . log ( "Invalid login key." ) ; process . exit ( ) ; return ; }
ckey = Buffer . from ( args . loginkey , 'hex' ) ;
if ( ckey != 80 ) { console . log ( "Invalid login key." ) ; process . exit ( ) ; return ; }
} else if ( args . loginkeyfile != null ) {
// Load key from hex file
var fs = require ( 'fs' ) ;
try {
var keydata = fs . readFileSync ( args . loginkeyfile , 'utf8' ) . split ( ' ' ) . join ( '' ) . split ( '\r' ) . join ( '' ) . split ( '\n' ) . join ( '' ) ;
ckey = Buffer . from ( keydata , 'hex' ) ;
if ( ckey . length != 80 ) { console . log ( "Invalid login key file." ) ; process . exit ( ) ; return ; }
2020-05-27 04:17:03 -04:00
} catch ( ex ) { console . log ( ex . message ) ; process . exit ( ) ; return ; }
2019-06-29 15:18:20 -04:00
}
if ( ckey != null ) {
var domainid = '' , username = 'admin' ;
2020-05-27 20:23:38 -04:00
if ( args . logindomain != null ) { domainid = args . logindomain ; }
2019-06-29 15:18:20 -04:00
if ( args . loginuser != null ) { username = args . loginuser ; }
url += '?auth=' + encodeCookie ( { userid : 'user/' + domainid + '/' + username , domainid : domainid } , ckey ) ;
2020-04-20 16:31:01 -04:00
} else {
2020-05-27 20:23:38 -04:00
if ( args . logindomain != null ) { console . log ( "--logindomain can only be used along with --loginkey." ) ; process . exit ( ) ; return ; }
2019-06-29 15:18:20 -04:00
}
const ws = new WebSocket ( url , options ) ;
2020-04-20 16:31:01 -04:00
//console.log('Connecting to ' + url);
2019-06-28 21:31:18 -04:00
ws . on ( 'open' , function open ( ) {
2019-06-29 15:18:20 -04:00
//console.log('Connected.');
2019-06-28 21:31:18 -04:00
switch ( settings . cmd ) {
case 'serverinfo' : { break ; }
case 'userinfo' : { break ; }
2020-06-12 16:04:23 -04:00
case 'listusers' : { ws . send ( JSON . stringify ( { action : 'users' , responseid : 'meshctrl' } ) ) ; break ; }
case 'listusersessions' : { ws . send ( JSON . stringify ( { action : 'wssessioncount' , responseid : 'meshctrl' } ) ) ; }
case 'listusergroups' : { ws . send ( JSON . stringify ( { action : 'usergroups' , responseid : 'meshctrl' } ) ) ; }
case 'listdevicegroups' : { ws . send ( JSON . stringify ( { action : 'meshes' , responseid : 'meshctrl' } ) ) ; break ; }
case 'listusersofdevicegroup' : { ws . send ( JSON . stringify ( { action : 'meshes' , responseid : 'meshctrl' } ) ) ; break ; }
2019-07-05 16:28:41 -04:00
case 'listdevices' : {
2020-04-16 16:18:45 -04:00
if ( args . group ) {
2020-05-14 16:20:45 -04:00
ws . send ( JSON . stringify ( { action : 'nodes' , meshname : args . group , responseid : 'meshctrl' } ) ) ;
2020-04-16 16:18:45 -04:00
} else if ( args . id ) {
2020-05-14 16:20:45 -04:00
ws . send ( JSON . stringify ( { action : 'nodes' , meshid : args . id , responseid : 'meshctrl' } ) ) ;
2019-07-05 16:28:41 -04:00
} else {
ws . send ( JSON . stringify ( { action : 'meshes' } ) ) ;
2020-05-14 16:20:45 -04:00
ws . send ( JSON . stringify ( { action : 'nodes' , responseid : 'meshctrl' } ) ) ;
2019-07-05 16:28:41 -04:00
}
2020-05-14 16:20:45 -04:00
break ;
2019-07-05 16:28:41 -04:00
}
2019-06-29 15:18:20 -04:00
case 'adduser' : {
2019-06-30 14:34:27 -04:00
var siteadmin = 0 ;
if ( args . siteadmin ) { siteadmin = 0xFFFFFFFF ; }
if ( args . manageusers ) { siteadmin |= 2 ; }
if ( args . fileaccess ) { siteadmin |= 8 ; }
if ( args . serverupdate ) { siteadmin |= 16 ; }
if ( args . locked ) { siteadmin |= 32 ; }
if ( args . nonewgroups ) { siteadmin |= 64 ; }
if ( args . notools ) { siteadmin |= 128 ; }
if ( args . randompass ) { args . pass = getRandomAmtPassword ( ) ; }
var op = { action : 'adduser' , username : args . user , pass : args . pass , responseid : 'meshctrl' } ;
2019-07-01 19:46:05 -04:00
if ( args . email ) { op . email = args . email ; if ( args . emailverified ) { op . emailVerified = true ; } }
2019-06-29 15:18:20 -04:00
if ( args . resetpass ) { op . resetNextLogin = true ; }
2019-06-30 14:34:27 -04:00
if ( siteadmin != 0 ) { op . siteadmin = siteadmin ; }
2020-05-27 20:23:38 -04:00
if ( args . domain ) { op . domain = args . domain ; }
2019-06-29 15:18:20 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
case 'removeuser' : {
2020-05-27 20:23:38 -04:00
var userid = args . userid ;
if ( ( args . domain != null ) && ( userid . indexOf ( '/' ) < 0 ) ) { userid = 'user/' + args . domain + '/' + userid ; }
ws . send ( JSON . stringify ( { action : 'deleteuser' , userid : userid , responseid : 'meshctrl' } ) ) ;
break ;
}
case 'addusergroup' : {
var op = { action : 'createusergroup' , name : args . name , desc : args . desc , responseid : 'meshctrl' } ;
if ( args . domain ) { op . domain = args . domain ; }
2019-06-30 14:34:27 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
2020-05-27 20:23:38 -04:00
case 'removeusergroup' : {
var ugrpid = args . groupid ;
if ( ( args . domain != null ) && ( userid . indexOf ( '/' ) < 0 ) ) { ugrpid = 'ugrp/' + args . domain + '/' + ugrpid ; }
ws . send ( JSON . stringify ( { action : 'deleteusergroup' , ugrpid : ugrpid , responseid : 'meshctrl' } ) ) ;
break ;
}
2019-06-30 14:34:27 -04:00
case 'adddevicegroup' : {
var op = { action : 'createmesh' , meshname : args . name , meshtype : 2 , responseid : 'meshctrl' } ;
if ( args . desc ) { op . desc = args . desc ; }
if ( args . amtonly ) { op . meshtype = 1 ; }
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
case 'removedevicegroup' : {
2020-04-08 14:26:35 -04:00
var op = { action : 'deletemesh' , responseid : 'meshctrl' } ;
if ( args . id ) { op . meshid = args . id ; } else if ( args . group ) { op . meshname = args . group ; }
2019-06-30 14:34:27 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
2020-04-16 11:46:53 -04:00
case 'movetodevicegroup' : {
var op = { action : 'changeDeviceMesh' , responseid : 'meshctrl' , nodeids : [ args . devid ] } ;
if ( args . id ) { op . meshid = args . id ; } else if ( args . group ) { op . meshname = args . group ; }
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
2019-07-01 17:44:26 -04:00
case 'addusertodevicegroup' : {
var meshrights = 0 ;
if ( args . fullrights ) { meshrights = 0xFFFFFFFF ; }
if ( args . editgroup ) { meshrights |= 1 ; }
if ( args . manageusers ) { meshrights |= 2 ; }
if ( args . managedevices ) { meshrights |= 4 ; }
if ( args . remotecontrol ) { meshrights |= 8 ; }
if ( args . agentconsole ) { meshrights |= 16 ; }
if ( args . serverfiles ) { meshrights |= 32 ; }
if ( args . wakedevices ) { meshrights |= 64 ; }
if ( args . notes ) { meshrights |= 128 ; }
if ( args . desktopviewonly ) { meshrights |= 256 ; }
if ( args . noterminal ) { meshrights |= 512 ; }
if ( args . nofiles ) { meshrights |= 1024 ; }
if ( args . noamt ) { meshrights |= 2048 ; }
if ( args . limiteddesktop ) { meshrights |= 4096 ; }
2020-04-01 16:15:14 -04:00
if ( args . limitedevents ) { meshrights |= 8192 ; }
if ( args . chatnotify ) { meshrights |= 16384 ; }
if ( args . uninstall ) { meshrights |= 32768 ; }
2020-04-08 14:26:35 -04:00
var op = { action : 'addmeshuser' , usernames : [ args . userid ] , meshadmin : meshrights , responseid : 'meshctrl' } ;
if ( args . id ) { op . meshid = args . id ; } else if ( args . group ) { op . meshname = args . group ; }
2019-07-01 17:44:26 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
case 'removeuserfromdevicegroup' : {
2020-04-08 14:26:35 -04:00
var op = { action : 'removemeshuser' , userid : args . userid , responseid : 'meshctrl' } ;
if ( args . id ) { op . meshid = args . id ; } else if ( args . group ) { op . meshname = args . group ; }
2019-07-01 17:44:26 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
2020-04-01 16:15:14 -04:00
case 'addusertodevice' : {
var meshrights = 0 ;
if ( args . fullrights ) { meshrights = ( 8 + 16 + 32 + 64 + 128 + 16384 + 32768 ) ; }
if ( args . remotecontrol ) { meshrights |= 8 ; }
if ( args . agentconsole ) { meshrights |= 16 ; }
if ( args . serverfiles ) { meshrights |= 32 ; }
if ( args . wakedevices ) { meshrights |= 64 ; }
if ( args . notes ) { meshrights |= 128 ; }
if ( args . desktopviewonly ) { meshrights |= 256 ; }
if ( args . noterminal ) { meshrights |= 512 ; }
if ( args . nofiles ) { meshrights |= 1024 ; }
if ( args . noamt ) { meshrights |= 2048 ; }
if ( args . limiteddesktop ) { meshrights |= 4096 ; }
if ( args . limitedevents ) { meshrights |= 8192 ; }
if ( args . chatnotify ) { meshrights |= 16384 ; }
if ( args . uninstall ) { meshrights |= 32768 ; }
var op = { action : 'adddeviceuser' , nodeid : args . id , usernames : [ args . userid ] , rights : meshrights , responseid : 'meshctrl' } ;
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
case 'removeuserfromdevice' : {
2020-05-14 15:10:25 -04:00
var op = { action : 'adddeviceuser' , nodeid : args . id , usernames : [ args . userid ] , rights : 0 , remove : true , responseid : 'meshctrl' } ;
2020-04-01 16:15:14 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
2019-07-05 16:28:41 -04:00
case 'sendinviteemail' : {
2020-04-07 19:13:02 -04:00
var op = { action : 'inviteAgent' , email : args . email , name : '' , os : '0' , responseid : 'meshctrl' }
if ( args . id ) { op . meshid = args . id ; } else if ( args . group ) { op . meshname = args . group ; }
if ( args . name ) { op . name = args . name ; }
if ( args . message ) { op . msg = args . message ; }
2019-07-05 16:28:41 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
2019-09-23 14:45:10 -04:00
case 'generateinvitelink' : {
2020-04-07 19:13:02 -04:00
var op = { action : 'createInviteLink' , expire : args . hours , flags : 0 , responseid : 'meshctrl' }
if ( args . id ) { op . meshid = args . id ; } else if ( args . group ) { op . meshname = args . group ; }
2019-09-23 14:45:10 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
2019-06-30 14:34:27 -04:00
case 'broadcast' : {
var op = { action : 'userbroadcast' , msg : args . msg , responseid : 'meshctrl' } ;
2019-06-29 15:18:20 -04:00
ws . send ( JSON . stringify ( op ) ) ;
break ;
}
2020-03-20 18:47:22 -04:00
case 'showevents' : {
console . log ( 'Connected. Press ctrl-c to end.' ) ;
break ;
}
2020-05-02 16:49:56 -04:00
case 'deviceinfo' : {
settings . deviceinfocount = 3 ;
ws . send ( JSON . stringify ( { action : 'getnetworkinfo' , nodeid : args . id , nodeinfo : true , responseid : 'meshctrl' } ) ) ;
ws . send ( JSON . stringify ( { action : 'lastconnect' , nodeid : args . id , nodeinfo : true , responseid : 'meshctrl' } ) ) ;
ws . send ( JSON . stringify ( { action : 'getsysinfo' , nodeid : args . id , nodeinfo : true , responseid : 'meshctrl' } ) ) ;
break ;
}
2020-07-13 15:25:14 -04:00
case 'runcommand' : {
ws . send ( JSON . stringify ( { action : 'runcommands' , nodeids : [ args . id ] , type : ( ( args . powershell ) ? 2 : 0 ) , cmds : args . run , responseid : 'meshctrl' } ) ) ;
break ;
}
2020-07-16 17:08:06 -04:00
case 'shell' :
case 'upload' :
case 'download' : {
2020-07-13 18:06:45 -04:00
ws . send ( "{\"action\":\"authcookie\"}" ) ;
break ;
}
2019-06-28 21:31:18 -04:00
}
} ) ;
2020-04-16 01:27:03 -04:00
ws . on ( 'close' , function ( ) { process . exit ( ) ; } ) ;
ws . on ( 'error' , function ( err ) {
if ( err . code == 'ENOTFOUND' ) { console . log ( 'Unable to resolve ' + url ) ; }
else if ( err . code == 'ECONNREFUSED' ) { console . log ( 'Unable to connect to ' + url ) ; }
else { console . log ( err ) ; }
process . exit ( ) ;
} ) ;
2019-06-28 21:31:18 -04:00
ws . on ( 'message' , function incoming ( rawdata ) {
var data = null ;
try { data = JSON . parse ( rawdata ) ; } catch ( ex ) { }
if ( data == null ) { console . log ( 'Unable to parse data: ' + rawdata ) ; }
2020-03-20 18:47:22 -04:00
if ( settings . cmd == 'showevents' ) {
console . log ( data ) ;
return ;
}
2019-06-28 21:31:18 -04:00
switch ( data . action ) {
case 'serverinfo' : { // SERVERINFO
2020-07-13 18:06:45 -04:00
settings . currentDomain = data . serverinfo . domain ;
2019-06-28 21:31:18 -04:00
if ( settings . cmd == 'serverinfo' ) {
if ( args . json ) {
console . log ( JSON . stringify ( data . serverinfo , ' ' , 2 ) ) ;
} else {
for ( var i in data . serverinfo ) { console . log ( i + ':' , data . serverinfo [ i ] ) ; }
}
process . exit ( ) ;
}
break ;
}
2020-07-16 17:08:06 -04:00
case 'authcookie' : { // SHELL, UPLOAD, DOWNLOAD
if ( ( settings . cmd == 'shell' ) || ( settings . cmd == 'upload' ) || ( settings . cmd == 'download' ) ) {
var protocol = 1 ; // Terminal
if ( ( settings . cmd == 'upload' ) || ( settings . cmd == 'download' ) ) { protocol = 5 ; } // Files
2020-07-13 18:06:45 -04:00
if ( ( args . id . split ( '/' ) != 3 ) && ( settings . currentDomain != null ) ) { args . id = 'node/' + settings . currentDomain + '/' + args . id ; }
var id = getRandomHex ( 6 ) ;
2020-07-16 17:08:06 -04:00
ws . send ( JSON . stringify ( { action : 'msg' , nodeid : args . id , type : 'tunnel' , usage : 1 , value : '*/meshrelay.ashx?p=' + protocol + '&nodeid=' + args . id + '&id=' + id + '&rauth=' + data . rcookie , responseid : 'meshctrl' } ) ) ;
connectTunnel ( url . replace ( '/control.ashx' , '/meshrelay.ashx?browser=1&p=' + protocol + '&nodeid=' + args . id + '&id=' + id + '&auth=' + data . cookie ) ) ;
2020-07-13 18:06:45 -04:00
}
break ;
}
2019-06-28 21:31:18 -04:00
case 'userinfo' : { // USERINFO
if ( settings . cmd == 'userinfo' ) {
if ( args . json ) {
console . log ( JSON . stringify ( data . userinfo , ' ' , 2 ) ) ;
} else {
for ( var i in data . userinfo ) { console . log ( i + ':' , data . userinfo [ i ] ) ; }
}
process . exit ( ) ;
}
break ;
}
2020-05-02 16:49:56 -04:00
case 'getsysinfo' : { // DEVICEINFO
if ( settings . cmd == 'deviceinfo' ) {
if ( data . result ) {
console . log ( data . result ) ;
process . exit ( ) ;
} else {
settings . sysinfo = data ;
if ( -- settings . deviceinfocount == 0 ) { displayDeviceInfo ( settings . sysinfo , settings . lastconnect , settings . networking ) ; process . exit ( ) ; }
}
}
break ;
}
case 'lastconnect' : {
if ( settings . cmd == 'deviceinfo' ) {
settings . lastconnect = ( data . result ) ? null : data ;
if ( -- settings . deviceinfocount == 0 ) { displayDeviceInfo ( settings . sysinfo , settings . lastconnect , settings . networking ) ; process . exit ( ) ; }
}
break ;
}
case 'getnetworkinfo' : {
if ( settings . cmd == 'deviceinfo' ) {
settings . networking = ( data . result ) ? null : data ;
if ( -- settings . deviceinfocount == 0 ) { displayDeviceInfo ( settings . sysinfo , settings . lastconnect , settings . networking ) ; process . exit ( ) ; }
}
break ;
}
2020-07-13 18:06:45 -04:00
case 'msg' : // SHELL
2019-06-30 14:34:27 -04:00
case 'adduser' : // ADDUSER
case 'deleteuser' : // REMOVEUSER
case 'createmesh' : // ADDDEVICEGROUP
case 'deletemesh' : // REMOVEDEVICEGROUP
2020-04-16 11:46:53 -04:00
case 'changeDeviceMesh' :
2019-07-01 17:44:26 -04:00
case 'addmeshuser' : //
case 'removemeshuser' : //
2019-09-23 14:45:10 -04:00
case 'inviteAgent' : //
2020-04-01 16:15:14 -04:00
case 'adddeviceuser' : //
2020-05-27 20:23:38 -04:00
case 'createusergroup' : //
case 'deleteusergroup' : //
2020-07-13 15:25:14 -04:00
case 'runcommands' :
2019-06-30 14:34:27 -04:00
case 'userbroadcast' : { // BROADCAST
if ( data . responseid == 'meshctrl' ) {
if ( data . meshid ) { console . log ( data . result , data . meshid ) ; }
else if ( data . userid ) { console . log ( data . result , data . userid ) ; }
else console . log ( data . result ) ;
process . exit ( ) ;
}
break ;
}
2019-09-23 14:45:10 -04:00
case 'createInviteLink' :
if ( data . responseid == 'meshctrl' ) {
if ( data . url ) { console . log ( data . url ) ; }
else console . log ( data . result ) ;
process . exit ( ) ;
}
break ;
2020-05-14 16:20:45 -04:00
case 'wssessioncount' : { // LIST USER SESSIONS
if ( args . json ) {
console . log ( JSON . stringify ( data . wssessions , ' ' , 2 ) ) ;
} else {
for ( var i in data . wssessions ) { console . log ( i + ', ' + ( ( data . wssessions [ i ] > 1 ) ? ( data . wssessions [ i ] + ' sessions.' ) : ( "1 session." ) ) ) ; }
}
process . exit ( ) ;
break ;
}
2020-05-27 20:23:38 -04:00
case 'usergroups' : { // LIST USER GROUPS
if ( args . json ) {
console . log ( JSON . stringify ( data . ugroups , ' ' , 2 ) ) ;
} else {
for ( var i in data . ugroups ) {
var x = i + ', ' + data . ugroups [ i ] . name ;
if ( data . ugroups [ i ] . desc && ( data . ugroups [ i ] . desc != '' ) ) { x += ', ' + data . ugroups [ i ] . desc ; }
console . log ( x ) ;
}
}
process . exit ( ) ;
break ;
}
2019-06-28 21:31:18 -04:00
case 'users' : { // LISTUSERS
2020-06-12 16:04:23 -04:00
if ( data . result ) { console . log ( data . result ) ; process . exit ( ) ; return ; }
2019-12-12 14:44:03 -05:00
if ( args . filter ) {
// Filter the list of users
var filters = args . filter . toLowerCase ( ) . split ( ',' ) ;
var filteredusers = [ ] ;
for ( var i in data . users ) {
var ok = false ;
if ( ( filters . indexOf ( '2fa' ) >= 0 ) && ( ( data . users [ i ] . otphkeys != null ) || ( data . users [ i ] . otpkeys != null ) || ( data . users [ i ] . otpsecret != null ) ) ) { ok = true ; }
if ( ( filters . indexOf ( 'no2fa' ) >= 0 ) && ( ( data . users [ i ] . otphkeys == null ) && ( data . users [ i ] . otpkeys == null ) && ( data . users [ i ] . otpsecret == null ) ) ) { ok = true ; }
if ( ok == true ) { filteredusers . push ( data . users [ i ] ) ; }
}
data . users = filteredusers ;
}
2019-06-28 21:31:18 -04:00
if ( args . json ) {
console . log ( JSON . stringify ( data . users , ' ' , 2 ) ) ;
} else {
2019-06-29 15:18:20 -04:00
if ( args . idexists ) { for ( var i in data . users ) { const u = data . users [ i ] ; if ( ( u . _id == args . idexists ) || ( u . _id . split ( '/' ) [ 2 ] == args . idexists ) ) { console . log ( '1' ) ; process . exit ( ) ; return ; } } console . log ( '0' ) ; process . exit ( ) ; return ; }
if ( args . nameexists ) { for ( var i in data . users ) { const u = data . users [ i ] ; if ( u . name == args . nameexists ) { console . log ( u . _id ) ; process . exit ( ) ; return ; } } process . exit ( ) ; return ; }
console . log ( 'id, name, email\r\n---------------' ) ;
2019-06-28 21:31:18 -04:00
for ( var i in data . users ) {
const u = data . users [ i ] ;
var t = "\"" + u . _id . split ( '/' ) [ 2 ] + "\", \"" + u . name + "\"" ;
if ( u . email != null ) { t += ", \"" + u . email + "\"" ; }
console . log ( t ) ;
}
}
process . exit ( ) ;
break ;
}
2019-07-05 16:28:41 -04:00
case 'nodes' : {
if ( ( settings . cmd == 'listdevices' ) && ( data . responseid == 'meshctrl' ) ) {
if ( ( data . result != null ) && ( data . result != 'ok' ) ) {
console . log ( data . result ) ;
} else {
if ( args . count ) {
// Return how many devices are in this group
var nodes = [ ] ;
for ( var i in data . nodes ) { var devicesInMesh = data . nodes [ i ] ; for ( var j in devicesInMesh ) { nodes . push ( devicesInMesh [ j ] ) ; } }
console . log ( nodes . length ) ;
} else if ( args . json ) {
// Return all devices in JSON format
var nodes = [ ] ;
for ( var i in data . nodes ) { var devicesInMesh = data . nodes [ i ] ; for ( var j in devicesInMesh ) { nodes . push ( devicesInMesh [ j ] ) ; } }
console . log ( JSON . stringify ( nodes , ' ' , 2 ) ) ;
} else {
// Display the list of nodes in text format
2020-04-20 16:31:01 -04:00
var nodecount = 0 ;
2019-07-05 16:28:41 -04:00
for ( var i in data . nodes ) {
var devicesInMesh = data . nodes [ i ] ;
if ( settings . xmeshes ) { console . log ( '\r\nDevice group: \"' + settings . xmeshes [ i ] . name + '\"' ) ; }
console . log ( 'id, name, icon, conn, pwr, ip\r\n-----------------------------' ) ;
for ( var j in devicesInMesh ) {
var n = devicesInMesh [ j ] ;
2020-04-20 16:31:01 -04:00
nodecount ++ ;
2019-07-05 16:28:41 -04:00
console . log ( n . _id . split ( '/' ) [ 2 ] + ', \"' + n . name + '\", ' + ( n . icon ? n . icon : 0 ) + ', ' + ( n . conn ? n . conn : 0 ) + ', ' + ( n . pwr ? n . pwr : 0 ) ) ;
}
}
2020-04-20 16:31:01 -04:00
if ( nodecount == 0 ) { console . log ( 'None' ) ; }
2019-07-05 16:28:41 -04:00
}
}
process . exit ( ) ;
}
break ;
}
2019-06-30 14:34:27 -04:00
case 'meshes' : { // LISTDEVICEGROUPS
2019-07-05 16:28:41 -04:00
if ( settings . cmd == 'listdevices' ) {
// Store the list of device groups for later use
settings . xmeshes = { }
for ( var i in data . meshes ) { settings . xmeshes [ data . meshes [ i ] . _id ] = data . meshes [ i ] ; }
} else if ( settings . cmd == 'listdevicegroups' ) {
if ( args . json ) {
console . log ( JSON . stringify ( data . meshes , ' ' , 2 ) ) ;
} else {
if ( args . idexists ) { for ( var i in data . meshes ) { const u = data . meshes [ i ] ; if ( ( u . _id == args . idexists ) || ( u . _id . split ( '/' ) [ 2 ] == args . idexists ) ) { console . log ( '1' ) ; process . exit ( ) ; return ; } } console . log ( '0' ) ; process . exit ( ) ; return ; }
if ( args . nameexists ) { for ( var i in data . meshes ) { const u = data . meshes [ i ] ; if ( u . name == args . nameexists ) { console . log ( u . _id ) ; process . exit ( ) ; return ; } } process . exit ( ) ; return ; }
2019-06-29 15:18:20 -04:00
2019-07-05 16:28:41 -04:00
console . log ( 'id, name\r\n---------------' ) ;
for ( var i in data . meshes ) {
const m = data . meshes [ i ] ;
2020-07-15 18:12:01 -04:00
var mid = m . _id . split ( '/' ) [ 2 ] ;
2020-07-16 17:08:06 -04:00
if ( args . hex ) { mid = '0x' + Buffer . from ( mid . replace ( /\@/g , '+' ) . replace ( /\$/g , '/' ) , 'base64' ) . toString ( 'hex' ) . toUpperCase ( ) ; }
2020-07-15 18:12:01 -04:00
var t = "\"" + mid + "\", \"" + m . name + "\"" ;
2019-07-05 16:28:41 -04:00
console . log ( t ) ;
}
}
process . exit ( ) ;
} else if ( settings . cmd == 'listusersofdevicegroup' ) {
2019-06-28 21:31:18 -04:00
for ( var i in data . meshes ) {
const m = data . meshes [ i ] ;
2019-07-05 16:28:41 -04:00
var mid = m . _id . split ( '/' ) [ 2 ] ;
if ( mid == args . id ) {
if ( args . json ) {
console . log ( JSON . stringify ( m . links , ' ' , 2 ) ) ;
} else {
console . log ( 'userid, rights\r\n---------------' ) ;
for ( var l in m . links ) {
var rights = m . links [ l ] . rights ;
var rightsstr = [ ] ;
if ( rights == 4294967295 ) { rightsstr = [ 'FullAdministrator' ] ; } else {
if ( rights & 1 ) { rightsstr . push ( 'EditMesh' ) ; }
if ( rights & 2 ) { rightsstr . push ( 'ManageUsers' ) ; }
if ( rights & 4 ) { rightsstr . push ( 'ManageComputers' ) ; }
if ( rights & 8 ) { rightsstr . push ( 'RemoteControl' ) ; }
if ( rights & 16 ) { rightsstr . push ( 'AgentConsole' ) ; }
if ( rights & 32 ) { rightsstr . push ( 'ServerFiles' ) ; }
if ( rights & 64 ) { rightsstr . push ( 'WakeDevice' ) ; }
if ( rights & 128 ) { rightsstr . push ( 'SetNotes' ) ; }
if ( rights & 256 ) { rightsstr . push ( 'RemoteViewOnly' ) ; }
if ( rights & 512 ) { rightsstr . push ( 'NoTerminal' ) ; }
if ( rights & 1024 ) { rightsstr . push ( 'NoFiles' ) ; }
if ( rights & 2048 ) { rightsstr . push ( 'NoAMT' ) ; }
if ( rights & 4096 ) { rightsstr . push ( 'DesktopLimitedInput' ) ; }
}
console . log ( l . split ( '/' ) [ 2 ] + ', ' + rightsstr . join ( ', ' ) ) ;
}
}
process . exit ( ) ;
return ;
}
2019-06-28 21:31:18 -04:00
}
2019-07-05 16:28:41 -04:00
console . log ( 'Group id not found' ) ;
process . exit ( ) ;
2019-06-28 21:31:18 -04:00
}
break ;
}
2019-06-29 15:18:20 -04:00
case 'close' : {
if ( data . cause == 'noauth' ) {
if ( data . msg == 'tokenrequired' ) {
console . log ( 'Authentication token required, use --token [number].' ) ;
} else {
2020-05-27 04:17:03 -04:00
if ( ( args . loginkeyfile != null ) || ( args . loginkey != null ) ) {
console . log ( 'Invalid login, check the login key and that this computer has the correct time.' ) ;
} else {
console . log ( 'Invalid login.' ) ;
}
2019-06-29 15:18:20 -04:00
}
}
process . exit ( ) ;
break ;
}
2019-06-30 14:34:27 -04:00
default : { break ; }
2019-06-28 21:31:18 -04:00
}
//console.log('Data', data);
//setTimeout(function timeout() { ws.send(Date.now()); }, 500);
} ) ;
2019-06-29 15:18:20 -04:00
}
2020-07-16 17:08:06 -04:00
// Connect tunnel to a remote agent
function connectTunnel ( url ) {
2020-07-13 18:06:45 -04:00
// Setup WebSocket options
var options = { rejectUnauthorized : false , checkServerIdentity : onVerifyServer }
// Setup the HTTP proxy if needed
if ( args . proxy != null ) { const HttpsProxyAgent = require ( 'https-proxy-agent' ) ; options . agent = new HttpsProxyAgent ( require ( 'url' ) . parse ( args . proxy ) ) ; }
// Connect the WebSocket
console . log ( 'Connecting...' ) ;
const WebSocket = require ( 'ws' ) ;
settings . tunnelwsstate = 0 ;
settings . tunnelws = new WebSocket ( url , options ) ;
settings . tunnelws . on ( 'open' , function ( ) { console . log ( 'Waiting for Agent...' ) ; } ) ; // Wait for agent connection
settings . tunnelws . on ( 'close' , function ( ) { console . log ( 'Connection Closed.' ) ; process . exit ( ) ; } ) ;
settings . tunnelws . on ( 'error' , function ( err ) { console . log ( err ) ; process . exit ( ) ; } ) ;
2020-07-16 17:08:06 -04:00
if ( settings . cmd == 'shell' ) {
// This code does all of the work for a shell command
settings . tunnelws . on ( 'message' , function ( rawdata ) {
var data = rawdata . toString ( ) ;
if ( settings . tunnelwsstate == 1 ) {
process . stdout . write ( data ) ;
} else if ( settings . tunnelwsstate == 0 ) {
if ( data == 'c' ) { console . log ( 'Connected.' ) ; } else if ( data == 'cr' ) { console . log ( 'Connected, session is being recorded.' ) ; } else return ;
2020-07-13 18:06:45 -04:00
// Send terminal size
var termSize = null ;
if ( typeof process . stdout . getWindowSize == 'function' ) { termSize = process . stdout . getWindowSize ( ) ; }
if ( termSize != null ) { settings . tunnelws . send ( JSON . stringify ( { ctrlChannel : '102938' , type : 'options' , cols : termSize [ 0 ] , rows : termSize [ 1 ] } ) ) ; }
settings . tunnelwsstate = 1 ;
2020-07-16 17:08:06 -04:00
settings . tunnelws . send ( '1' ) ; // Terminal
process . stdin . setEncoding ( 'utf8' ) ;
process . stdin . setRawMode ( true ) ;
process . stdout . setEncoding ( 'utf8' ) ;
process . stdin . unpipe ( process . stdout ) ;
process . stdout . unpipe ( process . stdin ) ;
process . stdin . on ( 'data' , function ( data ) { settings . tunnelws . send ( Buffer . from ( data ) ) ; } ) ;
//process.stdin.on('readable', function () { var chunk; while ((chunk = process.stdin.read()) !== null) { settings.tunnelws.send(Buffer.from(chunk)); } });
process . stdin . on ( 'end' , function ( ) { process . exit ( ) ; } ) ;
process . stdout . on ( 'resize' , function ( ) {
var termSize = null ;
if ( typeof process . stdout . getWindowSize == 'function' ) { termSize = process . stdout . getWindowSize ( ) ; }
if ( termSize != null ) { settings . tunnelws . send ( JSON . stringify ( { ctrlChannel : '102938' , type : 'termsize' , cols : termSize [ 0 ] , rows : termSize [ 1 ] } ) ) ; }
} ) ;
2020-07-13 18:06:45 -04:00
}
2020-07-16 17:08:06 -04:00
} ) ;
} else if ( settings . cmd == 'upload' ) {
// This code does all of the work for a file upload
// node meshctrl upload --id oL4Y6Eg0qjnpHFrp1AxfxnBPenbDGnDSkC@HSOnAheIyd51pKhqSCUgJZakzwfKl --file readme.md --target c:\
settings . tunnelws . on ( 'message' , function ( rawdata ) {
if ( settings . tunnelwsstate == 1 ) {
var cmd = null ;
try { cmd = JSON . parse ( rawdata . toString ( ) ) ; } catch ( ex ) { return ; }
if ( cmd . reqid == 'up' ) {
if ( ( cmd . action == 'uploadack' ) || ( cmd . action == 'uploadstart' ) ) {
var buf = Buffer . alloc ( 4096 ) ;
var len = require ( 'fs' ) . readSync ( settings . uploadFile , buf , 0 , 4096 , settings . uploadPtr ) ;
settings . uploadPtr += len ;
if ( len > 0 ) {
settings . tunnelws . send ( buf . slice ( 0 , len ) ) ;
} else {
console . log ( 'Upload done, ' + settings . uploadPtr + ' bytes sent.' ) ;
if ( settings . uploadFile != null ) { require ( 'fs' ) . closeSync ( settings . uploadFile ) ; }
process . exit ( ) ;
}
} else if ( cmd . action == 'uploaderror' ) {
if ( settings . uploadFile != null ) { require ( 'fs' ) . closeSync ( settings . uploadFile ) ; }
console . log ( 'Upload error.' ) ;
process . exit ( ) ;
}
}
} else if ( settings . tunnelwsstate == 0 ) {
var data = rawdata . toString ( ) ;
if ( data == 'c' ) { console . log ( 'Connected.' ) ; } else if ( data == 'cr' ) { console . log ( 'Connected, session is being recorded.' ) ; } else return ;
settings . tunnelwsstate = 1 ;
settings . tunnelws . send ( '5' ) ; // Files
settings . uploadSize = require ( 'fs' ) . statSync ( args . file ) . size ;
settings . uploadFile = require ( 'fs' ) . openSync ( args . file , 'r' ) ;
settings . uploadPtr = 0 ;
settings . tunnelws . send ( JSON . stringify ( { action : 'upload' , reqid : 'up' , path : require ( 'path' ) . dirname ( args . target ) , name : require ( 'path' ) . basename ( args . file ) , size : settings . uploadSize } ) ) ;
}
} ) ;
} else if ( settings . cmd == 'download' ) {
// This code does all of the work for a file download
// node meshctrl download --id oL4Y6Eg0qjnpHFrp1AxfxnBPenbDGnDSkC@HSOnAheIyd51pKhqSCUgJZakzwfKl --file c:\temp\MC-8Languages.png --target c:\temp\bob.png
settings . tunnelws . on ( 'message' , function ( rawdata ) {
if ( settings . tunnelwsstate == 1 ) {
if ( ( rawdata . length > 0 ) && ( rawdata [ 0 ] != '{' ) ) {
// This is binary data, this test is ok because 4 first bytes is a control value.
if ( ( rawdata . length > 4 ) && ( settings . downloadFile != null ) ) { settings . downloadSize += ( rawdata . length - 4 ) ; require ( 'fs' ) . writeSync ( settings . downloadFile , rawdata , 4 , rawdata . length - 4 ) ; }
if ( ( rawdata [ 3 ] & 1 ) != 0 ) { // Check end flag
// File is done, close everything.
if ( settings . downloadFile != null ) { require ( 'fs' ) . closeSync ( settings . downloadFile ) ; }
console . log ( 'Download completed, ' + settings . downloadSize + ' bytes written.' ) ;
process . exit ( ) ;
} else {
settings . tunnelws . send ( JSON . stringify ( { action : 'download' , sub : 'ack' , id : args . file } ) ) ; // Send the ACK
}
} else {
// This is text data
var cmd = null ;
try { cmd = JSON . parse ( rawdata . toString ( ) ) ; } catch ( ex ) { return ; }
if ( cmd . action == 'download' ) {
if ( cmd . id != args . file ) return ;
if ( cmd . sub == 'start' ) {
settings . downloadFile = require ( 'fs' ) . openSync ( args . target , 'w' ) ;
settings . downloadSize = 0 ;
settings . tunnelws . send ( JSON . stringify ( { action : 'download' , sub : 'startack' , id : args . file } ) ) ;
console . log ( 'Download started...' ) ;
} else if ( cmd . sub == 'cancel' ) {
if ( settings . downloadFile != null ) { require ( 'fs' ) . closeSync ( settings . downloadFile ) ; }
console . log ( 'Download canceled.' ) ;
process . exit ( ) ;
}
}
}
} else if ( settings . tunnelwsstate == 0 ) {
var data = rawdata . toString ( ) ;
if ( data == 'c' ) { console . log ( 'Connected.' ) ; } else if ( data == 'cr' ) { console . log ( 'Connected, session is being recorded.' ) ; } else return ;
settings . tunnelwsstate = 1 ;
settings . tunnelws . send ( '5' ) ; // Files
settings . tunnelws . send ( JSON . stringify ( { action : 'download' , sub : 'start' , id : args . file , path : args . file } ) ) ;
}
} ) ;
}
2020-07-13 18:06:45 -04:00
}
2019-06-29 15:18:20 -04:00
// Encode an object as a cookie using a key using AES-GCM. (key must be 32 bytes or more)
function encodeCookie ( o , key ) {
try {
if ( key == null ) { return null ; }
o . time = Math . floor ( Date . now ( ) / 1000 ) ; // Add the cookie creation time
const iv = Buffer . from ( crypto . randomBytes ( 12 ) , 'binary' ) , cipher = crypto . createCipheriv ( 'aes-256-gcm' , key . slice ( 0 , 32 ) , iv ) ;
const crypted = Buffer . concat ( [ cipher . update ( JSON . stringify ( o ) , 'utf8' ) , cipher . final ( ) ] ) ;
return Buffer . concat ( [ iv , cipher . getAuthTag ( ) , crypted ] ) . toString ( 'base64' ) . replace ( /\+/g , '@' ) . replace ( /\//g , '$' ) ;
} catch ( e ) { return null ; }
}
2019-06-30 14:34:27 -04:00
// Generate a random Intel AMT password
function checkAmtPassword ( p ) { return ( p . length > 7 ) && ( /\d/ . test ( p ) ) && ( /[a-z]/ . test ( p ) ) && ( /[A-Z]/ . test ( p ) ) && ( /\W/ . test ( p ) ) ; }
function getRandomAmtPassword ( ) { var p ; do { p = Buffer . from ( crypto . randomBytes ( 9 ) , 'binary' ) . toString ( 'base64' ) . split ( '/' ) . join ( '@' ) ; } while ( checkAmtPassword ( p ) == false ) ; return p ; }
2020-07-13 18:06:45 -04:00
function getRandomHex ( count ) { return Buffer . from ( crypto . randomBytes ( count ) , 'binary' ) . toString ( 'hex' ) ; }
2020-05-02 16:49:56 -04:00
function format ( format ) { var args = Array . prototype . slice . call ( arguments , 1 ) ; return format . replace ( /{(\d+)}/g , function ( match , number ) { return typeof args [ number ] != 'undefined' ? args [ number ] : match ; } ) ; } ;
function displayDeviceInfo ( sysinfo , lastconnect , network ) {
var node = sysinfo . node ;
var hardware = sysinfo . hardware ;
var info = { } ;
if ( network != null ) { sysinfo . netif = network . netif ; }
if ( lastconnect != null ) { node . lastconnect = lastconnect . time ; node . lastaddr = lastconnect . addr ; }
if ( args . raw ) { console . log ( JSON . stringify ( sysinfo , ' ' , 2 ) ) ; return ; }
// Operating System
if ( ( hardware . windows && hardware . windows . osinfo ) || node . osdesc ) {
var output = { } , outputCount = 0 ;
if ( node . rname ) { output [ "Name" ] = node . rname ; outputCount ++ ; }
if ( node . osdesc ) { output [ "Version" ] = node . osdesc ; outputCount ++ ; }
if ( hardware . windows && hardware . windows . osinfo ) { var m = hardware . windows . osinfo ; if ( m . OSArchitecture ) { output [ "Architecture" ] = m . OSArchitecture ; outputCount ++ ; } }
if ( outputCount > 0 ) { info [ "Operating System" ] = output ; }
}
// MeshAgent
if ( node . agent ) {
var output = { } , outputCount = 0 ;
var agentsStr = [ "Unknown" , "Windows 32bit console" , "Windows 64bit console" , "Windows 32bit service" , "Windows 64bit service" , "Linux 32bit" , "Linux 64bit" , "MIPS" , "XENx86" , "Android ARM" , "Linux ARM" , "MacOS 32bit" , "Android x86" , "PogoPlug ARM" , "Android APK" , "Linux Poky x86-32bit" , "MacOS 64bit" , "ChromeOS" , "Linux Poky x86-64bit" , "Linux NoKVM x86-32bit" , "Linux NoKVM x86-64bit" , "Windows MinCore console" , "Windows MinCore service" , "NodeJS" , "ARM-Linaro" , "ARMv6l / ARMv7l" , "ARMv8 64bit" , "ARMv6l / ARMv7l / NoKVM" , "Unknown" , "Unknown" , "FreeBSD x86-64" ] ;
if ( ( node . agent != null ) && ( node . agent . id != null ) && ( node . agent . ver != null ) ) {
var str = '' ;
if ( node . agent . id <= agentsStr . length ) { str = agentsStr [ node . agent . id ] ; } else { str = agentsStr [ 0 ] ; }
if ( node . agent . ver != 0 ) { str += ' v' + node . agent . ver ; }
output [ "Mesh Agent" ] = str ; outputCount ++ ;
}
if ( ( node . conn & 1 ) != 0 ) {
output [ "Last agent connection" ] = "Connected now" ; outputCount ++ ;
} else {
if ( node . lastconnect ) { output [ "Last agent connection" ] = new Date ( node . lastconnect ) . toLocaleString ( ) ; outputCount ++ ; }
}
if ( node . lastaddr ) {
var splitip = node . lastaddr . split ( ':' ) ;
if ( splitip . length > 2 ) {
output [ "Last agent address" ] = node . lastaddr ; outputCount ++ ; // IPv6
} else {
output [ "Last agent address" ] = splitip [ 0 ] ; outputCount ++ ; // IPv4
}
}
if ( outputCount > 0 ) { info [ "Mesh Agent" ] = output ; }
}
// Networking
if ( network . netif != null ) {
var output = { } , outputCount = 0 , minfo = { } ;
for ( var i in network . netif ) {
var m = network . netif [ i ] , moutput = { } , moutputCount = 0 ;
if ( m . desc ) { moutput [ "Description" ] = m . desc ; moutputCount ++ ; }
if ( m . mac ) {
if ( m . gatewaymac ) {
moutput [ "MAC Layer" ] = format ( "MAC: {0}, Gateway: {1}" , m . mac , m . gatewaymac ) ; moutputCount ++ ;
} else {
moutput [ "MAC Layer" ] = format ( "MAC: {0}" , m . mac ) ; moutputCount ++ ;
}
}
if ( m . v4addr && ( m . v4addr != '0.0.0.0' ) ) {
if ( m . v4gateway && m . v4mask ) {
moutput [ "IPv4 Layer" ] = format ( "IP: {0}, Mask: {1}, Gateway: {2}" , m . v4addr , m . v4mask , m . v4gateway ) ; moutputCount ++ ;
} else {
moutput [ "IPv4 Layer" ] = format ( "IP: {0}" , m . v4addr ) ; moutputCount ++ ;
}
}
if ( moutputCount > 0 ) { minfo [ m . name + ( m . dnssuffix ? ( ', ' + m . dnssuffix ) : '' ) ] = moutput ; info [ "Networking" ] = minfo ; }
}
}
// Intel AMT
if ( node . intelamt != null ) {
var output = { } , outputCount = 0 ;
output [ "Version" ] = ( node . intelamt . ver ) ? ( 'v' + node . intelamt . ver ) : ( '<i>' + "Unknown" + '</i>' ) ; outputCount ++ ;
var provisioningStates = { 0 : "Not Activated (Pre)" , 1 : "Not Activated (In)" , 2 : "Activated" } ;
var provisioningMode = '' ;
if ( ( node . intelamt . state == 2 ) && node . intelamt . flags ) { if ( node . intelamt . flags & 2 ) { provisioningMode = ( ', ' + "Client Control Mode (CCM)" ) ; } else if ( node . intelamt . flags & 4 ) { provisioningMode = ( ', ' + "Admin Control Mode (ACM)" ) ; } }
output [ "Provisioning State" ] = ( ( node . intelamt . state ) ? ( provisioningStates [ node . intelamt . state ] ) : ( '<i>' + "Unknown" + '</i>' ) ) + provisioningMode ; outputCount ++ ;
output [ "Security" ] = ( node . intelamt . tls == 1 ) ? "Secured using TLS" : "TLS is not setup" ; outputCount ++ ;
output [ "Admin Credentials" ] = ( node . intelamt . user == null || node . intelamt . user == '' ) ? "Not Known" : "Known" ; outputCount ++ ;
if ( outputCount > 0 ) { info [ "Intel Active Management Technology (Intel AMT)" ] = output ; }
}
if ( hardware . identifiers ) {
var output = { } , outputCount = 0 , ident = hardware . identifiers ;
// BIOS
if ( ident . bios _vendor ) { output [ "Vendor" ] = ident . bios _vendor ; outputCount ++ ; }
if ( ident . bios _version ) { output [ "Version" ] = ident . bios _version ; outputCount ++ ; }
if ( outputCount > 0 ) { info [ "BIOS" ] = output ; }
output = { } , outputCount = 0 ;
// Motherboard
if ( ident . board _vendor ) { output [ "Vendor" ] = ident . board _vendor ; outputCount ++ ; }
if ( ident . board _name ) { output [ "Name" ] = ident . board _name ; outputCount ++ ; }
if ( ident . board _serial && ( ident . board _serial != '' ) ) { output [ "Serial" ] = ident . board _serial ; outputCount ++ ; }
if ( ident . board _version ) { output [ "Version" ] = ident . board _version ; }
if ( ident . product _uuid ) { output [ "Identifier" ] = ident . product _uuid ; }
if ( ident . cpu _name ) { output [ "CPU" ] = ident . cpu _name ; }
if ( ident . gpu _name ) { for ( var i in ident . gpu _name ) { output [ "GPU" + ( parseInt ( i ) + 1 ) ] = ident . gpu _name [ i ] ; } }
if ( outputCount > 0 ) { info [ "Motherboard" ] = output ; }
}
// Memory
if ( hardware . windows ) {
if ( hardware . windows . memory ) {
var output = { } , outputCount = 0 , minfo = { } ;
hardware . windows . memory . sort ( function ( a , b ) { if ( a . BankLabel > b . BankLabel ) return 1 ; if ( a . BankLabel < b . BankLabel ) return - 1 ; return 0 ; } ) ;
for ( var i in hardware . windows . memory ) {
var m = hardware . windows . memory [ i ] , moutput = { } , moutputCount = 0 ;
if ( m . Capacity ) { moutput [ "Capacity/Speed" ] = ( m . Capacity / 1024 / 1024 ) + " Mb, " + m . Speed + " Mhz" ; moutputCount ++ ; }
if ( m . PartNumber ) { moutput [ "Part Number" ] = ( ( m . Manufacturer && m . Manufacturer != 'Undefined' ) ? ( m . Manufacturer + ', ' ) : '' ) + m . PartNumber ; moutputCount ++ ; }
if ( moutputCount > 0 ) { minfo [ m . BankLabel ] = moutput ; info [ "Memory" ] = minfo ; }
}
}
}
// Storage
if ( hardware . identifiers && ident . storage _devices ) {
var output = { } , outputCount = 0 , minfo = { } ;
// Sort Storage
ident . storage _devices . sort ( function ( a , b ) { if ( a . Caption > b . Caption ) return 1 ; if ( a . Caption < b . Caption ) return - 1 ; return 0 ; } ) ;
for ( var i in ident . storage _devices ) {
var m = ident . storage _devices [ i ] , moutput = { } ;
if ( m . Size ) {
if ( m . Model && ( m . Model != m . Caption ) ) { moutput [ "Model" ] = m . Model ; outputCount ++ ; }
if ( ( typeof m . Size == 'string' ) && ( parseInt ( m . Size ) == m . Size ) ) { m . Size = parseInt ( m . Size ) ; }
if ( typeof m . Size == 'number' ) { moutput [ "Capacity" ] = Math . floor ( m . Size / 1024 / 1024 ) + 'Mb' ; outputCount ++ ; }
if ( typeof m . Size == 'string' ) { moutput [ "Capacity" ] = m . Size ; outputCount ++ ; }
if ( moutputCount > 0 ) { minfo [ m . Caption ] = moutput ; info [ "Storage" ] = minfo ; }
}
}
}
// Display everything
if ( args . json ) {
console . log ( JSON . stringify ( info , ' ' , 2 ) ) ;
} else {
for ( var i in info ) {
console . log ( '--- ' + i + ' ---' ) ;
for ( var j in info [ i ] ) {
if ( typeof info [ i ] [ j ] == 'string' ) {
console . log ( ' ' + j + ': ' + info [ i ] [ j ] ) ;
} else {
console . log ( ' ' + j + ':' ) ;
for ( var k in info [ i ] [ j ] ) {
console . log ( ' ' + k + ': ' + info [ i ] [ j ] [ k ] ) ;
}
}
}
}
}
2020-05-15 03:39:07 -04:00
}