EverydayTech Platform - Developer Reference
Complete Source Code Documentation - All Applications
Loading...
Searching...
No Matches
amt-ider.js
Go to the documentation of this file.
1/*
2Copyright 2020-2021 Intel Corporation
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15
16@description MeshCentral Server IDER handler
17@author Ylian Saint-Hilaire
18@version v0.3.0
19*/
20
21/*jslint node: true */
22/*jshint node: true */
23/*jshint strict:false */
24/*jshint -W097 */
25/*jshint esversion: 6 */
26"use strict";
27
28// Construct a MeshAgent object, called upon connection
29module.exports.CreateAmtIderSession = function (parent, db, ws, req, args, domain, user) {
30 const fs = require('fs');
31 const path = require('path');
32 const common = parent.common;
33 const amtMeshRedirModule = require('./amt-redir-mesh.js');
34 const amtMeshIderModule = require('./amt-ider-module.js');
35
36 //console.log('New Server IDER session from ' + user.name);
37
38 var obj = {};
39 obj.user = user;
40 obj.domain = domain;
41 obj.ider = null;
42
43 // Disconnect this user
44 obj.close = function (arg) {
45 if ((arg == 1) || (arg == null)) { try { ws.close(); parent.parent.debug(1, 'Soft disconnect'); } catch (e) { console.log(e); } } // Soft close, close the websocket
46 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
47 };
48
49 try {
50
51 // Check if the user is logged in
52 if (user == null) { try { ws.close(); } catch (e) { } return; }
53
54 // When data is received from the web socket
55 ws.on('message', processWebSocketData);
56
57 // If error, do nothing
58 ws.on('error', function (err) { console.log(err); obj.close(0); });
59
60 // If the web socket is closed
61 ws.on('close', function (req) {
62 // Close the IDER session
63 if (obj.ider) { obj.ider.Stop(); delete obj.ider; }
64 });
65
66 // We are all set, start receiving data
67 ws._socket.resume();
68
69 } catch (e) { console.log(e); }
70
71 // Process incoming web socket data from the browser
72 function processWebSocketData(msg) {
73 var command, i = 0, mesh = null, meshid = null, nodeid = null, meshlinks = null, change = 0;
74 try { command = JSON.parse(msg.toString('utf8')); } catch (e) { return; }
75 if (common.validateString(command.action, 3, 32) == false) return; // Action must be a string between 3 and 32 chars
76
77 switch (command.action) {
78 case 'ping': { try { ws.send(JSON.stringify({ action: 'pong' })); } catch (ex) { } break; }
79 case 'start': {
80 // Get the list of disk images
81 var domainx = 'domain' + ((domain.id == '') ? '' : ('-' + domain.id));
82 var useridx = user._id.split('/')[2];
83 var userPath = parent.parent.path.join(parent.parent.filespath, domainx, 'user-' + useridx);
84
85 // Look for a list of disk images for the user to select.
86 if (fs.existsSync(userPath)) {
87 // Do something
88 readFsRec(userPath, function (err, results) {
89 var floppyImages = [], cdromImages = [];
90 for (var i in results) {
91 if (results[i].toLowerCase().endsWith('.img')) { floppyImages.push(results[i].substring(userPath.length + 1)); }
92 else if (results[i].toLowerCase().endsWith('.iso')) { cdromImages.push(results[i].substring(userPath.length + 1)); }
93 }
94 var xx, sel = true, html = "<div style='margin:10px 5px 10px 5px'>Select disk images & start type.</div>";
95
96 // Floppy image selection
97 xx = "<select style=width:240px id=xxFloppyImagesSelect><option value=''>None</option>";
98 for (var i in floppyImages) { xx += "<option value='" + encodeURIComponent(floppyImages[i]) + "'" + (sel?" selected":"") + ">" + floppyImages[i] + "</option>"; sel = false; }
99 xx += "</select>";
100 html += "<div style=margin:5px>" + addHtmlValue("Floppy Image", xx) + "</div>";
101
102 // CDROM image selection
103 sel = true;
104 xx = "<select style=width:240px id=xxCdromImagesSelect><option value=''>None</option>";
105 for (var i in cdromImages) { xx += "<option value='" + encodeURIComponent(cdromImages[i]) + "'" + (sel ? " selected" : "") + ">" + cdromImages[i] + "</option>"; sel = false; }
106 xx += "</select>";
107 html += "<div style=margin:5px>" + addHtmlValue("CDROM Image", xx) + "</div>";
108
109 // Start type
110 xx = "<select style=width:240px id=xxIderStartType><option value=0>On next boot<option value=1>Graceful<option value=2>Immediate</select>";
111 html += "<div style=margin:5px>" + addHtmlValue("Session Start", xx) + "</div>";
112
113 var js = "function iderServerCall() { return { ider: 1, floppyPath: Q('xxFloppyImagesSelect').value, cdromPath: Q('xxCdromImagesSelect').value, iderStart: Q('xxIderStartType').value }; }";
114
115 try { ws.send(JSON.stringify({ action: 'dialog', args: { html: html, js: js }, buttons: 3 })); } catch (ex) { }
116 });
117 } else {
118 // No user folder
119 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) { }
120 }
121
122 break;
123 }
124 case 'dialogResponse': {
125 if (command.args.ider == 1) { // Start IDER Session
126 // Decode and validate file paths
127 if ((command.args.floppyPath != null) && (typeof command.args.floppyPath != 'string')) { command.args.floppyPath = null; } else { command.args.floppyPath = decodeURIComponent(command.args.floppyPath); }
128 if ((command.args.cdromPath != null) && (typeof command.args.cdromPath != 'string')) { command.args.cdromPath = null; } else { command.args.cdromPath = decodeURIComponent(command.args.cdromPath); }
129 // TODO: Double check that "." or ".." are not used.
130 if ((command.args.floppyPath != null) && (command.args.floppyPath.indexOf('..') >= 0)) { delete command.args.floppyPath; }
131 if ((command.args.cdromPath != null) && (command.args.cdromPath.indexOf('..') >= 0)) { delete command.args.cdromPath; }
132
133 // Get the disk image paths
134 var domainx = 'domain' + ((domain.id == '') ? '' : ('-' + domain.id));
135 var useridx = user._id.split('/')[2];
136 var floppyPath = null, cdromPath = null;
137 if (command.args.floppyPath) { floppyPath = parent.parent.path.join(parent.parent.filespath, domainx, 'user-' + useridx, command.args.floppyPath); }
138 if (command.args.cdromPath) { cdromPath = parent.parent.path.join(parent.parent.filespath, domainx, 'user-' + useridx, command.args.cdromPath); }
139
140 // Setup the IDER session
141 obj.ider = amtMeshRedirModule.CreateAmtRedirect(amtMeshIderModule.CreateAmtRemoteIder(parent, parent.parent), domain, user, parent, parent.parent);
142 obj.ider.onStateChanged = onIderStateChange;
143 obj.ider.m.iderStart = command.args.iderStart;
144 obj.ider.m.sectorStats = iderSectorStats;
145 obj.ider.tlsv1only = req.query.tlsv1only;
146
147 // Setup disk images
148 var iderError = obj.ider.m.diskSetup(floppyPath, cdromPath);
149
150 // Error with the disk images, unable to start IDER
151 if (iderError != 0) { try { ws.send(JSON.stringify({ action: 'error', code: iderError })); } catch (ex) { } break; }
152
153 // Start the IDER session
154 obj.ider.Start(req.query.host, req.query.port, req.query.tls);
155 }
156
157 break;
158 }
159 default: {
160 // Unknown user action
161 console.log('Unknown IDER action from user ' + user.name + ': ' + command.action + '.');
162 break;
163 }
164 }
165 }
166
167 function onIderStateChange(sender, state) {
168 try { ws.send(JSON.stringify({ action: 'state', state: state })); } catch (ex) { }
169 switch (state) {
170 case 0:
171 // Close the websocket connection and clean up.
172 obj.ider.onStateChanged = null;
173 obj.ider.m.sectorStats = null;
174 obj.ider = null;
175 obj.close();
176 break;
177 }
178 }
179
180 function iderSectorStats(mode, dev, total, start, len) {
181 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) { }
182 }
183
184 // Recursivly read all of the files in a fonder
185 function readFsRec(dir, func) {
186 var results = [];
187 fs.readdir(dir, function (err, list) {
188 if (err) return func(err);
189 var pending = list.length;
190 if (!pending) return func(null, results);
191 list.forEach(function (file) {
192 file = path.resolve(dir, file);
193 fs.stat(file, function (err, stat) {
194 if (stat && stat.isDirectory()) {
195 readFsRec(file, function (err, res) { results = results.concat(res); if (!--pending) func(null, results); });
196 } else {
197 results.push(file); if (!--pending) func(null, results);
198 }
199 });
200 });
201 });
202 };
203
204 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>'; }
205
206 return obj;
207};