2019-04-24 14:38:28 -04:00
/ * *
* @ description MeshCentral Server IDER handler
* @ author Ylian Saint - Hilaire & Bryan Roe
* @ copyright Intel Corporation 2018 - 2019
* @ license Apache - 2.0
* @ version v0 . 0.1
* /
/*jslint node: true */
/*jshint node: true */
/*jshint strict:false */
/*jshint -W097 */
/*jshint esversion: 6 */
"use strict" ;
// Construct a MeshAgent object, called upon connection
module . exports . CreateAmtIderSession = function ( parent , db , ws , req , args , domain , user ) {
2019-04-24 21:04:45 -04:00
const fs = require ( 'fs' ) ;
2019-04-24 14:38:28 -04:00
const path = require ( 'path' ) ;
const common = parent . common ;
const amtMeshRedirModule = require ( './amt-redir-mesh.js' ) ;
const amtMeshIderModule = require ( './amt-ider-module.js' ) ;
//console.log('New Server IDER session from ' + user.name);
var obj = { } ;
obj . user = user ;
obj . domain = domain ;
obj . ider = null ;
// Disconnect this user
obj . close = function ( arg ) {
if ( ( arg == 1 ) || ( arg == null ) ) { try { ws . close ( ) ; parent . parent . debug ( 1 , 'Soft disconnect' ) ; } catch ( e ) { console . log ( e ) ; } } // Soft close, close the websocket
if ( arg == 2 ) { try { ws . _socket . _parent . end ( ) ; parent . parent . debug ( 1 , 'Hard disconnect' ) ; } catch ( e ) { console . log ( e ) ; } } // Hard close, close the TCP socket
} ;
try {
// Check if the user is logged in
if ( user == null ) { try { ws . close ( ) ; } catch ( e ) { } return ; }
// When data is received from the web socket
ws . on ( 'message' , processWebSocketData ) ;
// If error, do nothing
ws . on ( 'error' , function ( err ) { console . log ( err ) ; obj . close ( 0 ) ; } ) ;
// If the web socket is closed
ws . on ( 'close' , function ( req ) {
// Close the IDER session
2019-04-24 21:04:45 -04:00
if ( obj . ider ) { obj . ider . Stop ( ) ; delete obj . ider ; }
2019-04-24 14:38:28 -04:00
} ) ;
// We are all set, start receiving data
ws . _socket . resume ( ) ;
} catch ( e ) { console . log ( e ) ; }
// Process incoming web socket data from the browser
function processWebSocketData ( msg ) {
var command , i = 0 , mesh = null , meshid = null , nodeid = null , meshlinks = null , change = 0 ;
try { command = JSON . parse ( msg . toString ( 'utf8' ) ) ; } catch ( e ) { return ; }
if ( common . validateString ( command . action , 3 , 32 ) == false ) return ; // Action must be a string between 3 and 32 chars
switch ( command . action ) {
case 'ping' : { try { ws . send ( JSON . stringify ( { action : 'pong' } ) ) ; } catch ( ex ) { } break ; }
2019-04-24 21:04:45 -04:00
case 'start' : {
// Get the list of disk images
var domainx = 'domain' + ( ( domain . id == '' ) ? '' : ( '-' + domain . id ) ) ;
var useridx = user . _id . split ( '/' ) [ 2 ] ;
var userPath = parent . parent . path . join ( parent . parent . filespath , domainx , 'user-' + useridx ) ;
// Look for a list of disk images for the user to select.
if ( fs . existsSync ( userPath ) ) {
// Do something
readFsRec ( userPath , function ( err , results ) {
var floppyImages = [ ] , cdromImages = [ ] ;
for ( var i in results ) {
if ( results [ i ] . toLowerCase ( ) . endsWith ( '.img' ) ) { floppyImages . push ( results [ i ] . substring ( userPath . length + 1 ) ) ; }
else if ( results [ i ] . toLowerCase ( ) . endsWith ( '.iso' ) ) { cdromImages . push ( results [ i ] . substring ( userPath . length + 1 ) ) ; }
}
//console.log(floppyImages, cdromImages);
var xx , sel = true , html = "<div style='margin:10px 5px 10px 5px'>Select disk images & start type.</div>" ;
// Floppy image selection
xx = "<select style=width:240px id=xxFloppyImagesSelect><option value=''>None</option>" ;
for ( var i in floppyImages ) { xx += "<option value='" + encodeURIComponent ( floppyImages [ i ] ) + "'" + ( sel ? " selected" : "" ) + ">" + floppyImages [ i ] + "</option>" ; sel = false ; }
xx += "</select>" ;
html += "<div style=margin:5px>" + addHtmlValue ( "Floppy Image" , xx ) + "</div>" ;
// CDROM image selection
sel = true ;
xx = "<select style=width:240px id=xxCdromImagesSelect><option value=''>None</option>" ;
for ( var i in cdromImages ) { xx += "<option value='" + encodeURIComponent ( cdromImages [ i ] ) + "'" + ( sel ? " selected" : "" ) + ">" + cdromImages [ i ] + "</option>" ; sel = false ; }
xx += "</select>" ;
html += "<div style=margin:5px>" + addHtmlValue ( "CDROM Image" , xx ) + "</div>" ;
// Start type
xx = "<select style=width:240px id=xxIderStartType><option value=0>On next boot<option value=1>Graceful<option value=2>Immediate</select>" ;
html += "<div style=margin:5px>" + addHtmlValue ( "Session Start" , xx ) + "</div>" ;
var js = "function iderServerCall() { return { ider: 1, floppyPath: Q('xxFloppyImagesSelect').value, cdromPath: Q('xxCdromImagesSelect').value, iderStart: Q('xxIderStartType').value }; }" ;
try { ws . send ( JSON . stringify ( { action : 'dialog' , args : { html : html , js : js } , buttons : 3 } ) ) ; } catch ( ex ) { }
} ) ;
} else {
// No user folder
try { ws . send ( JSON . stringify ( { action : 'dialog' , args : { html : 'No disk images found on remote server. Upload .img and .iso files to server "My Files" folder to enable this feature.' } , buttons : 2 } ) ) ; } catch ( ex ) { }
}
2019-04-24 14:38:28 -04:00
break ;
}
2019-04-24 21:04:45 -04:00
case 'dialogResponse' : {
if ( command . args . ider == 1 ) { // Start IDER Session
// Decode and validate file paths
if ( ( command . args . floppyPath != null ) && ( typeof command . args . floppyPath != 'string' ) ) { command . args . floppyPath = null ; } else { command . args . floppyPath = decodeURIComponent ( command . args . floppyPath ) ; }
if ( ( command . args . cdromPath != null ) && ( typeof command . args . cdromPath != 'string' ) ) { command . args . cdromPath = null ; } else { command . args . cdromPath = decodeURIComponent ( command . args . cdromPath ) ; }
// TODO: Double check that "." or ".." are not used.
if ( ( command . args . floppyPath != null ) && ( command . args . floppyPath . indexOf ( ".." ) >= 0 ) ) { delete command . args . floppyPath ; }
if ( ( command . args . cdromPath != null ) && ( command . args . cdromPath . indexOf ( ".." ) >= 0 ) ) { delete command . args . cdromPath ; }
// Get the disk image paths
var domainx = 'domain' + ( ( domain . id == '' ) ? '' : ( '-' + domain . id ) ) ;
var useridx = user . _id . split ( '/' ) [ 2 ] ;
var floppyPath = null , cdromPath = null ;
if ( command . args . floppyPath ) { floppyPath = parent . parent . path . join ( parent . parent . filespath , domainx , 'user-' + useridx , command . args . floppyPath ) ; }
if ( command . args . cdromPath ) { cdromPath = parent . parent . path . join ( parent . parent . filespath , domainx , 'user-' + useridx , command . args . cdromPath ) ; }
// Setup the IDER session
obj . ider = amtMeshRedirModule . CreateAmtRedirect ( amtMeshIderModule . CreateAmtRemoteIder ( parent , parent . parent ) , domain , user , parent , parent . parent ) ;
obj . ider . onStateChanged = onIderStateChange ;
obj . ider . m . iderStart = command . args . iderStart ;
obj . ider . m . sectorStats = iderSectorStats ;
obj . ider . tlsv1only = req . query . tlsv1only ;
// Setup disk images
var iderError = obj . ider . m . diskSetup ( floppyPath , cdromPath ) ;
2019-04-24 14:38:28 -04:00
// Error with the disk images, unable to start IDER
2019-04-24 21:04:45 -04:00
if ( iderError != 0 ) { try { ws . send ( JSON . stringify ( { action : "error" , code : iderError } ) ) ; } catch ( ex ) { } break ; }
2019-04-24 14:38:28 -04:00
2019-04-24 21:04:45 -04:00
// Start the IDER session
obj . ider . Start ( req . query . host , req . query . port , req . query . tls ) ;
}
2019-04-24 14:38:28 -04:00
break ;
}
default : {
// Unknown user action
console . log ( 'Unknown IDER action from user ' + user . name + ': ' + command . action + '.' ) ;
break ;
}
}
}
function onIderStateChange ( sender , state ) {
try { ws . send ( JSON . stringify ( { action : 'state' , state : state } ) ) ; } catch ( ex ) { }
switch ( state ) {
case 0 :
// Close the websocket connection and clean up.
obj . ider . onStateChanged = null ;
obj . ider . m . sectorStats = null ;
obj . ider = null ;
obj . close ( ) ;
break ;
}
}
function iderSectorStats ( mode , dev , total , start , len ) {
try { ws . send ( JSON . stringify ( { action : 'stats' , mode : mode , dev : dev , total : total , start : start , len : len , toAmt : obj . ider . m . bytesToAmt , fromAmt : obj . ider . m . bytesFromAmt } ) ) ; } catch ( ex ) { }
}
2019-04-24 21:04:45 -04:00
// Recursivly read all of the files in a fonder
function readFsRec ( dir , func ) {
var results = [ ] ;
fs . readdir ( dir , function ( err , list ) {
if ( err ) return func ( err ) ;
var pending = list . length ;
if ( ! pending ) return func ( null , results ) ;
list . forEach ( function ( file ) {
file = path . resolve ( dir , file ) ;
fs . stat ( file , function ( err , stat ) {
if ( stat && stat . isDirectory ( ) ) {
readFsRec ( file , function ( err , res ) { results = results . concat ( res ) ; if ( ! -- pending ) func ( null , results ) ; } ) ;
} else {
results . push ( file ) ; if ( ! -- pending ) func ( null , results ) ;
}
} ) ;
} ) ;
} ) ;
} ;
function addHtmlValue ( t , v ) { return '<div style=height:20px><div style=float:right;width:240px;overflow:hidden><b title="' + v + '">' + v + '</b></div><div>' + t + '</div></div>' ; }
2019-04-24 14:38:28 -04:00
return obj ;
} ;