mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			207 lines
		
	
	
		
			No EOL
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			207 lines
		
	
	
		
			No EOL
		
	
	
		
			10 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*
 | 
						|
Copyright 2020-2021 Intel Corporation
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
 | 
						|
@description MeshCentral Server IDER handler
 | 
						|
@author Ylian Saint-Hilaire
 | 
						|
@version v0.3.0
 | 
						|
*/
 | 
						|
 | 
						|
/*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) {
 | 
						|
    const fs = require('fs');
 | 
						|
    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
 | 
						|
            if (obj.ider) { obj.ider.Stop(); delete obj.ider; }
 | 
						|
        });
 | 
						|
 | 
						|
        // 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; }
 | 
						|
            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)); }
 | 
						|
                        }
 | 
						|
                        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) { }
 | 
						|
                }
 | 
						|
 | 
						|
                break;
 | 
						|
            }
 | 
						|
            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);
 | 
						|
 | 
						|
                    // Error with the disk images, unable to start IDER
 | 
						|
                    if (iderError != 0) { try { ws.send(JSON.stringify({ action: 'error', code: iderError })); } catch (ex) { } break; }
 | 
						|
 | 
						|
                    // Start the IDER session
 | 
						|
                    obj.ider.Start(req.query.host, req.query.port, req.query.tls);
 | 
						|
                }
 | 
						|
 | 
						|
                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) { }
 | 
						|
    }
 | 
						|
 | 
						|
    // 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>'; }
 | 
						|
 | 
						|
    return obj;
 | 
						|
}; |