diff --git a/apprelays.js b/apprelays.js index f6c82f72..f4142d12 100644 --- a/apprelays.js +++ b/apprelays.js @@ -62,10 +62,10 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { var inTraffc = obj.ws._socket.bytesRead, outTraffc = obj.ws._socket.bytesWritten; if (obj.wsClient != null) { inTraffc += obj.wsClient._socket.bytesRead; outTraffc += obj.wsClient._socket.bytesWritten; } const sessionSeconds = Math.round((Date.now() - obj.startTime) / 1000); - const user = parent.users[obj.cookie.userid]; + const user = parent.users[obj.userid]; const username = (user != null) ? user.name : null; - const event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: obj.cookie.userid, username: username, sessionid: obj.sessionid, msgid: 125, msgArgs: [sessionSeconds, obj.sessionid], msg: "Left Web-RDP session \"" + obj.sessionid + "\" after " + sessionSeconds + " second(s).", protocol: PROTOCOL_WEBRDP, bytesin: inTraffc, bytesout: outTraffc }; - parent.parent.DispatchEvent(['*', obj.nodeid, obj.cookie.userid, obj.meshid], obj, event); + const event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: obj.userid, username: username, sessionid: obj.sessionid, msgid: 125, msgArgs: [sessionSeconds, obj.sessionid], msg: "Left Web-RDP session \"" + obj.sessionid + "\" after " + sessionSeconds + " second(s).", protocol: PROTOCOL_WEBRDP, bytesin: inTraffc, bytesout: outTraffc }; + parent.parent.DispatchEvent(['*', obj.nodeid, obj.userid, obj.meshid], obj, event); delete obj.startTime; delete obj.sessionid; } @@ -129,8 +129,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { function startRdp(port) { parent.parent.debug('relay', 'RDP: Starting RDP client on loopback port ' + port); try { - //rdpClient = require('node-rdpjs-2').createClient({ - rdpClient = require('./rdp').createClient({ + const args = { logLevel: 'NONE', // 'ERROR', domain: obj.infos.domain, userName: obj.infos.username, @@ -139,7 +138,8 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { autoLogin: true, screen: obj.infos.screen, locale: obj.infos.locale - }).on('connect', function () { + }; + rdpClient = require('./rdp').createClient(args).on('connect', function () { send(['rdp-connect']); if ((typeof obj.infos.options == 'object') && (obj.infos.options.savepass == true)) { saveRdpCredentials(); } // Save the credentials if needed obj.sessionid = Buffer.from(parent.crypto.randomBytes(9), 'binary').toString('base64'); @@ -147,10 +147,10 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { // Event session start try { - const user = parent.users[obj.cookie.userid]; + const user = parent.users[obj.userid]; const username = (user != null) ? user.name : null; - const event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: obj.cookie.userid, username: username, sessionid: obj.sessionid, msgid: 150, msgArgs: [obj.sessionid], msg: "Started Web-RDP session \"" + obj.sessionid + "\".", protocol: PROTOCOL_WEBRDP }; - parent.parent.DispatchEvent(['*', obj.nodeid, obj.cookie.userid, obj.meshid], obj, event); + const event = { etype: 'relay', action: 'relaylog', domain: domain.id, nodeid: obj.nodeid, userid: obj.userid, username: username, sessionid: obj.sessionid, msgid: 150, msgArgs: [obj.sessionid], msg: "Started Web-RDP session \"" + obj.sessionid + "\".", protocol: PROTOCOL_WEBRDP }; + parent.parent.DispatchEvent(['*', obj.nodeid, obj.userid, obj.meshid], obj, event); } catch (ex) { console.log(ex); } }).on('bitmap', function (bitmap) { try { ws.send(bitmap.data); } catch (ex) { } // Send the bitmap data as binary @@ -201,11 +201,17 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { case 'infos': { obj.infos = msg[1]; - // Decode the authentication cookie - obj.cookie = parent.parent.decodeCookie(obj.infos.ip, parent.parent.loginCookieEncryptionKey); - if ((obj.cookie == null) || (typeof obj.cookie.nodeid != 'string') || (typeof obj.cookie.userid != 'string')) { obj.close(); return; } - obj.nodeid = obj.cookie.nodeid; - obj.userid = obj.cookie.userid; + if (obj.infos.ip.startsWith('node/')) { + // Use the user session + obj.nodeid = obj.infos.ip; + obj.userid = req.session.userid; + } else { + // Decode the authentication cookie + obj.cookie = parent.parent.decodeCookie(obj.infos.ip, parent.parent.loginCookieEncryptionKey); + if ((obj.cookie == null) || (typeof obj.cookie.nodeid != 'string') || (typeof obj.cookie.userid != 'string')) { obj.close(); return; } + obj.nodeid = obj.cookie.nodeid; + obj.userid = obj.cookie.userid; + } // Get node parent.parent.db.Get(obj.nodeid, function (err, nodes) { @@ -222,7 +228,11 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { obj.tcpaddr = node.host; // Re-encode a cookie with a device relay - const cookieContent = { userid: obj.cookie.userid, domainid: obj.cookie.domainid, nodeid: mesh.relayid, tcpaddr: node.host, tcpport: obj.cookie.tcpport }; + const cookieContent = { userid: obj.userid, domainid: domain.id, nodeid: mesh.relayid, tcpaddr: node.host, tcpport: obj.cookie.tcpport }; + obj.infos.ip = parent.parent.encodeCookie(cookieContent, parent.parent.loginCookieEncryptionKey); + } else if (obj.infos.ip.startsWith('node/')) { + // Encode a cookie with a device relay + const cookieContent = { userid: obj.userid, domainid: domain.id, nodeid: obj.nodeid, tcpport: node.rdpport ? node.rdpport : 3389 }; obj.infos.ip = parent.parent.encodeCookie(cookieContent, parent.parent.loginCookieEncryptionKey); } @@ -234,7 +244,7 @@ module.exports.CreateMstscRelay = function (parent, db, ws, req, args, domain) { // Check if we need to load server stored credentials if ((typeof obj.infos.options == 'object') && (obj.infos.options.useServerCreds == true)) { // Check if RDP credentials exist - if ((domain.allowsavingdevicecredentials === false) && (typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) { + if ((domain.allowsavingdevicecredentials !== false) && (typeof node.rdp == 'object') && (typeof node.rdp.d == 'string') && (typeof node.rdp.u == 'string') && (typeof node.rdp.p == 'string')) { obj.infos.domain = node.rdp.d; obj.infos.username = node.rdp.u; obj.infos.password = node.rdp.p; diff --git a/public/mstsc/client.js b/public/mstsc/client.js index 62ff5f8d..317a5114 100644 --- a/public/mstsc/client.js +++ b/public/mstsc/client.js @@ -138,7 +138,13 @@ }); return this; - }, + }, + /** + * disconnect + */ + disconnect: function () { + if (this.socket) { this.socket.close(); } + }, /** * connect * @param ip {string} ip target for rdp diff --git a/public/scripts/agent-desktop-0.0.2.js b/public/scripts/agent-desktop-0.0.2.js index be13bf29..4401b365 100644 --- a/public/scripts/agent-desktop-0.0.2.js +++ b/public/scripts/agent-desktop-0.0.2.js @@ -560,7 +560,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { obj.onResize = function () { if (obj.ScreenWidth == 0 || obj.ScreenHeight == 0) return; - if (obj.Canvas.canvas.width == obj.ScreenWidth && obj.Canvas.canvas.height == obj.ScreenHeight) return; + if ((obj.Canvas.canvas.width == obj.ScreenWidth) && (obj.Canvas.canvas.height == obj.ScreenHeight)) return; if (obj.FirstDraw) { obj.Canvas.canvas.width = obj.ScreenWidth; obj.Canvas.canvas.height = obj.ScreenHeight; diff --git a/public/scripts/agent-rdp-0.0.1.js b/public/scripts/agent-rdp-0.0.1.js new file mode 100644 index 00000000..cda3a53c --- /dev/null +++ b/public/scripts/agent-rdp-0.0.1.js @@ -0,0 +1,159 @@ +/** +* @description RDP Remote Desktop +* @author Ylian Saint-Hilaire +* @version v0.0.1 +*/ + +// Construct a RDP remote desktop object +var CreateRDPDesktop = function (canvasid) { + var obj = {} + obj.m = {}; + obj.State = 0; + obj.canvas = Q(canvasid); + obj.CanvasId = canvasid; + if (typeof canvasid === 'string') obj.CanvasId = Q(canvasid); + obj.Canvas = obj.CanvasId.getContext('2d'); + obj.ScreenWidth = obj.width = 1280; + obj.ScreenHeight = obj.height = 1024; + + function mouseButtonMap(button) { + // Swap mouse buttons if needed + if (obj.m.SwapMouse === true) return [2, 0, 1, 0, 0][button]; + return [1, 0, 2, 0, 0][button]; + }; + + obj.Start = function (nodeid, port, credentials) { + changeState(1); + obj.nodeid = nodeid; + obj.port = port; + obj.credentials = credentials; + var options = { savepass: credentials.savecred, useServerCreds: credentials.servercred }; + obj.render = new Mstsc.Canvas.create(obj.canvas); + obj.socket = new WebSocket('wss://' + window.location.host + '/mstscrelay.ashx'); // TODO: Support domains + obj.socket.binaryType = 'arraybuffer'; + obj.socket.onopen = function () { + changeState(2); // Setup state + obj.socket.send(JSON.stringify(['infos', { + ip: obj.nodeid, + port: obj.port, + screen: { width: obj.width, height: obj.height }, + domain: credentials.domain, + username: credentials.username, + password: credentials.password, + options: options, + locale: Mstsc.locale() + }])); + }; + obj.socket.onmessage = function (evt) { + if (typeof evt.data == 'string') { + // This is a JSON text string, parse it. + var msg = JSON.parse(evt.data); + switch (msg[0]) { + case 'rdp-connect': { + changeState(3); + obj.rotation = 0; + obj.Canvas.setTransform(1, 0, 0, 1, 0, 0); + obj.Canvas.canvas.width = obj.ScreenWidth; + obj.Canvas.canvas.height = obj.ScreenHeight; + obj.Canvas.fillRect(0, 0, obj.ScreenWidth, obj.ScreenHeight); + if (obj.m.onScreenSizeChange != null) { obj.m.onScreenSizeChange(obj, obj.ScreenWidth, obj.ScreenHeight, obj.CanvasId); } + break; + } + case 'rdp-bitmap': { + if (obj.bitmapData == null) break; + var bitmap = msg[1]; + bitmap.data = obj.bitmapData; // Use the binary data that was sent earlier. + delete obj.bitmapData; + obj.render.update(bitmap); + break; + } + case 'rdp-close': { + obj.Stop(); + break; + } + case 'rdp-error': { + var err = msg[1]; + console.log('[mstsc.js] error : ' + err.code + '(' + err.message + ')'); + obj.Stop(); + break; + } + } + } else { + // This is binary bitmap data, store it. + obj.bitmapData = evt.data; + } + }; + obj.socket.onclose = function () { changeState(0); }; + changeState(1); + } + + obj.Stop = function () { + if (obj.socket) { obj.socket.close(); } + } + + function changeState(newstate) { + if (obj.State == newstate) return; + obj.State = newstate; + if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State); + } + + function getPositionOfControl(Control) { + var Position = Array(2); + Position[0] = Position[1] = 0; + while (Control) { Position[0] += Control.offsetLeft; Position[1] += Control.offsetTop; Control = Control.offsetParent; } + return Position; + } + + function getMousePosition(event) { + var ScaleFactorHeight = (obj.Canvas.canvas.height / obj.CanvasId.clientHeight); + var ScaleFactorWidth = (obj.Canvas.canvas.width / obj.CanvasId.clientWidth); + var Offsets = getPositionOfControl(obj.Canvas.canvas); + var X = ((event.pageX - Offsets[0]) * ScaleFactorWidth); + var Y = ((event.pageY - Offsets[1]) * ScaleFactorHeight); + if (event.addx) { X += event.addx; } + if (event.addy) { Y += event.addy; } + return { x: X, y: Y }; + } + + obj.m.mousemove = function (e) { + if (!obj.socket || (obj.State != 3)) return; + var m = getMousePosition(e); + obj.mouseNagleData = ['mouse', m.x, m.y, 0, false]; + if (obj.mouseNagleTimer == null) { obj.mouseNagleTimer = setTimeout(function () { obj.socket.send(JSON.stringify(obj.mouseNagleData)); obj.mouseNagleTimer = null; }, 50); } + e.preventDefault(); + return false; + } + obj.m.mouseup = function (e) { + if (!obj.socket || (obj.State != 3)) return; + if (obj.mouseNagleTimer != null) { clearTimeout(obj.mouseNagleTimer); obj.mouseNagleTimer = null; } + var m = getMousePosition(e); + obj.socket.send(JSON.stringify(['mouse', m.x, m.y, mouseButtonMap(e.button), false])); + e.preventDefault(); + return false; + } + obj.m.mousedown = function (e) { + if (!obj.socket || (obj.State != 3)) return; + if (obj.mouseNagleTimer != null) { clearTimeout(obj.mouseNagleTimer); obj.mouseNagleTimer = null; } + var m = getMousePosition(e); + obj.socket.send(JSON.stringify(['mouse', m.x, m.y, mouseButtonMap(e.button), true])); + e.preventDefault(); + return false; + } + obj.m.handleKeyUp = function (e) { + if (!obj.socket || (obj.State != 3)) return; + obj.socket.send(JSON.stringify(['scancode', Mstsc.scancode(e), false])); + e.preventDefault(); + return false; + } + obj.m.handleKeyDown = function (e) { + if (!obj.socket || (obj.State != 3)) return; + obj.socket.send(JSON.stringify(['scancode', Mstsc.scancode(e), true])); + e.preventDefault(); + return false; + } + obj.m.mousedblclick = function () { } + obj.m.handleKeyPress = function () { } + obj.m.setRotation = function () { } + + return obj; +} diff --git a/translate/translate.js b/translate/translate.js index 435f1108..878232bf 100644 --- a/translate/translate.js +++ b/translate/translate.js @@ -81,6 +81,7 @@ var minifyMeshCentralSourceFiles = [ "../views/mstsc.handlebars", "../views/ssh.handlebars", "../public/scripts/agent-desktop-0.0.2.js", + "../public/scripts/agent-rdp-0.0.1.js", "../public/scripts/agent-redir-rtc-0.1.0.js", "../public/scripts/agent-redir-ws-0.1.1.js", "../public/scripts/amt-0.2.0.js", diff --git a/views/default.handlebars b/views/default.handlebars index c6828efe..7404d02d 100644 --- a/views/default.handlebars +++ b/views/default.handlebars @@ -29,10 +29,16 @@ + + + + + + @@ -82,9 +88,10 @@