mirror of
				https://github.com/Ylianst/MeshCentral.git
				synced 2025-03-09 15:40:18 +00:00 
			
		
		
		
	Faster RSA signatures.
This commit is contained in:
		
							parent
							
								
									348065fec3
								
							
						
					
					
						commit
						c53d51175a
					
				
					 16 changed files with 419 additions and 60 deletions
				
			
		|  | @ -190,6 +190,7 @@ | |||
|     <Folder Include="typings\globals\express-handlebars\" /> | ||||
|     <Folder Include="typings\globals\express-session\" /> | ||||
|     <Folder Include="typings\globals\node-forge\" /> | ||||
|     <Folder Include="typings\globals\nodemailer\" /> | ||||
|     <Folder Include="typings\globals\node\" /> | ||||
|     <Folder Include="views\" /> | ||||
|   </ItemGroup> | ||||
|  | @ -198,6 +199,7 @@ | |||
|     <TypeScriptCompile Include="typings\globals\express-handlebars\index.d.ts" /> | ||||
|     <TypeScriptCompile Include="typings\globals\express-session\index.d.ts" /> | ||||
|     <TypeScriptCompile Include="typings\globals\node-forge\index.d.ts" /> | ||||
|     <TypeScriptCompile Include="typings\globals\nodemailer\index.d.ts" /> | ||||
|     <TypeScriptCompile Include="typings\globals\node\index.d.ts" /> | ||||
|     <TypeScriptCompile Include="typings\index.d.ts" /> | ||||
|   </ItemGroup> | ||||
|  |  | |||
|  | @ -36,7 +36,24 @@ function createMeshCore(agent) { | |||
|     var wifiScannerLib = null; | ||||
|     var wifiScanner = null; | ||||
|     var networkMonitor = null; | ||||
|      | ||||
|     var amtscanner = null; | ||||
| 
 | ||||
|     /* | ||||
|     var AMTScanner = require("AMTScanner"); | ||||
|     var scan = new AMTScanner(); | ||||
| 
 | ||||
|     scan.on("found", function (data) { | ||||
|         if (typeof data === 'string') { | ||||
|             console.log(data); | ||||
|         } else { | ||||
|             console.log(JSON.stringify(data, null, " ")); | ||||
|         } | ||||
|     }); | ||||
|     scan.scan("10.2.55.140", 1000); | ||||
|     scan.scan("10.2.55.139-10.2.55.145", 1000); | ||||
|     scan.scan("10.2.55.128/25", 2000); | ||||
|     */ | ||||
| 
 | ||||
|     // Try to load up the network monitor
 | ||||
|     try { | ||||
|         networkMonitor = require('NetworkMonitor'); | ||||
|  | @ -44,6 +61,13 @@ function createMeshCore(agent) { | |||
|         networkMonitor.on('add', function (addr) { sendNetworkUpdateNagle(); }); | ||||
|         networkMonitor.on('remove', function (addr) { sendNetworkUpdateNagle(); }); | ||||
|     } catch (e) { networkMonitor = null; } | ||||
| 
 | ||||
|     // Try to load up the Intel AMT scanner
 | ||||
|     try { | ||||
|         var AMTScannerModule = require('amt-scanner'); | ||||
|         amtscanner = new AMTScannerModule(); | ||||
|         //amtscanner.on('found', function (data) { if (typeof data != 'string') { data = JSON.stringify(data, null, " "); } sendConsoleText(data); });
 | ||||
|     } catch (e) { amtscanner = null; } | ||||
|      | ||||
|     // Try to load up the MEI module
 | ||||
|     try { | ||||
|  | @ -693,7 +717,7 @@ function createMeshCore(agent) { | |||
|             var response = null; | ||||
|             switch (cmd) { | ||||
|                 case 'help': { // Displays available commands
 | ||||
|                     response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist, wsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi.'; | ||||
|                     response = 'Available commands: help, info, args, print, type, dbget, dbset, dbcompact, parseuri, httpget, wslist,\r\nwsconnect, wssend, wsclose, notify, ls, amt, netinfo, location, power, wakeonlan, scanwifi, scanamt.'; | ||||
|                     break; | ||||
|                 } | ||||
|                 case 'notify': { // Send a notification message to the mesh
 | ||||
|  | @ -947,6 +971,36 @@ function createMeshCore(agent) { | |||
|                     } else { response = "Wifi module not present."; } | ||||
|                     break; | ||||
|                 } | ||||
|                 case 'scanamt': { | ||||
|                     if (amtscanner != null) { | ||||
|                         if (args['_'].length != 1) { | ||||
|                             response = 'Usage examples:\r\n  scanamt 1.2.3.4\r\n  scanamt 1.2.3.0-1.2.3.255\r\n  scanamt 1.2.3.0/24\r\n'; // Display correct command usage
 | ||||
|                         } else { | ||||
|                             response = 'Scanning: ' + args['_'][0] + '...'; | ||||
|                             amtscanner.scan(args['_'][0], 2000, function (data) { | ||||
|                                 if (data.length > 0) { | ||||
|                                     var r = '', pstates = ['NotActivated', 'InActivation', 'Activated']; | ||||
|                                     for (var i in data) { | ||||
|                                         var x = data[i]; | ||||
|                                         if (r != '') { r += '\r\n'; } | ||||
|                                         r += x.address + ' - Intel AMT v' + x.majorVersion + '.' + x.minorVersion; | ||||
|                                         if (x.provisioningState < 3) { r += (', ' + pstates[x.provisioningState]); } | ||||
|                                         if (x.provisioningState == 2) { r += (', ' + x.openPorts.join(', ')); } | ||||
|                                         r += '.'; | ||||
|                                     } | ||||
|                                 } else { | ||||
|                                     r = 'No Intel AMT found.'; | ||||
|                                 } | ||||
|                                 sendConsoleText(r); | ||||
|                             }); | ||||
|                         } | ||||
|                     } else { response = "Intel AMT scanner module not present."; } | ||||
|                     break; | ||||
|                 } | ||||
|                 case 'modules': { | ||||
|                     response = JSON.stringify(addedModules); | ||||
|                     break; | ||||
|                 } | ||||
|                 default: { // This is an unknown command, return an error message
 | ||||
|                     response = 'Unknown command \"' + cmd + '\", type \"help\" for list of avaialble commands.'; | ||||
|                     break; | ||||
|  |  | |||
							
								
								
									
										89
									
								
								agents/modules_meshcmd/amt-scanner.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								agents/modules_meshcmd/amt-scanner.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,89 @@ | |||
| /** | ||||
| * @description Meshcentral Intel AMT Local Scanner | ||||
| * @author Ylian Saint-Hilaire & Joko Sastriawan | ||||
| * @version v0.0.1 | ||||
| */ | ||||
| 
 | ||||
| // Construct a Intel AMT Scanner object
 | ||||
| 
 | ||||
| function AMTScanner() { | ||||
|     var emitterUtils = require('events').inherits(this); | ||||
|     emitterUtils.createEvent('found'); | ||||
| 
 | ||||
|     this.dgram = require('dgram'); | ||||
| 
 | ||||
|     this.buildRmcpPing = function (tag) { | ||||
|         var packet = Buffer.from('06000006000011BE80000000', 'hex'); | ||||
|         packet[9] = tag; | ||||
|         return packet; | ||||
|     }; | ||||
| 
 | ||||
|     this.parseRmcpPacket = function (server, data, rinfo, func) { | ||||
|         if (data == null || data.length < 20) return; | ||||
|         var res = {}; | ||||
|         if (((data[12] == 0) || (data[13] != 0) || (data[14] != 1) || (data[15] != 0x57)) && (data[21] & 32)) { | ||||
|             res.servertag = data[9]; | ||||
|             res.minorVersion = data[18] & 0x0F; | ||||
|             res.majorVersion = (data[18] >> 4) & 0x0F; | ||||
|             res.provisioningState = data[19] & 0x03; // Pre = 0, In = 1, Post = 2
 | ||||
| 
 | ||||
|             var openPort = (data[16] * 256) + data[17]; | ||||
|             var dualPorts = ((data[19] & 0x04) != 0) ? true : false; | ||||
|             res.openPorts = [openPort]; | ||||
|             res.address = rinfo.address; | ||||
|             if (dualPorts == true) { res.openPorts = [16992, 16993]; } | ||||
|             if (func !== undefined) { | ||||
|                 func(server, res); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     this.parseIPv4Range = function (range) { | ||||
|         if (range == undefined || range == null) return null; | ||||
|         var x = range.split('-'); | ||||
|         if (x.length == 2) { return { min: this.parseIpv4Addr(x[0]), max: this.parseIpv4Addr(x[1]) }; } | ||||
|         x = range.split('/'); | ||||
|         if (x.length == 2) { | ||||
|             var ip = this.parseIpv4Addr(x[0]), masknum = parseInt(x[1]), mask = 0; | ||||
|             if (masknum <= 16 || masknum > 32) return null; | ||||
|             masknum = 32 - masknum; | ||||
|             for (var i = 0; i < masknum; i++) { mask = (mask << 1); mask++; } | ||||
|             return { min: ip & (0xFFFFFFFF - mask), max: (ip & (0xFFFFFFFF - mask)) + mask }; | ||||
|         } | ||||
|         x = this.parseIpv4Addr(range); | ||||
|         if (x == null) return null; | ||||
|         return { min: x, max: x }; | ||||
|     }; | ||||
| 
 | ||||
|     // Parse IP address. Takes a 
 | ||||
|     this.parseIpv4Addr = function (addr) { | ||||
|         var x = addr.split('.'); | ||||
|         if (x.length == 4) { return (parseInt(x[0]) << 24) + (parseInt(x[1]) << 16) + (parseInt(x[2]) << 8) + (parseInt(x[3]) << 0); } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     // IP address number to string
 | ||||
|     this.IPv4NumToStr = function (num) { | ||||
|         return ((num >> 24) & 0xFF) + '.' + ((num >> 16) & 0xFF) + '.' + ((num >> 8) & 0xFF) + '.' + (num & 0xFF); | ||||
|     } | ||||
| 
 | ||||
|     this.scan = function (rangestr, timeout) { | ||||
|         var iprange = this.parseIPv4Range(rangestr); | ||||
|         var rmcp = this.buildRmcpPing(0); | ||||
|         var server = this.dgram.createSocket({ type: 'udp4' }); | ||||
|         server.parent = this; | ||||
|         server.scanResults = []; | ||||
|         server.on('error', function (err) { console.log('Error:' + err); }); | ||||
|         server.on('message', function (msg, rinfo) { if (rinfo.size > 4) { this.parent.parseRmcpPacket(this, msg, rinfo, function (s, res) { s.scanResults.push(res); }) }; }); | ||||
|         server.on('listening', function () { for (var i = iprange.min; i <= iprange.max; i++) { server.send(rmcp, 623, server.parent.IPv4NumToStr(i)); } }); | ||||
|         server.bind({ address: '0.0.0.0', port: 0, exclusive: true }); | ||||
|         var tmout = setTimeout(function cb() { | ||||
|             //console.log("Server closed");
 | ||||
|             //server.close();
 | ||||
|             server.parent.emit('found', server.scanResults); | ||||
|             delete server; | ||||
|         }, timeout); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| module.exports = AMTScanner; | ||||
							
								
								
									
										90
									
								
								agents/modules_meshcore/amt-scanner.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								agents/modules_meshcore/amt-scanner.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,90 @@ | |||
| /** | ||||
| * @description Meshcentral Intel AMT Local Scanner | ||||
| * @author Ylian Saint-Hilaire & Joko Sastriawan | ||||
| * @version v0.0.1 | ||||
| */ | ||||
| 
 | ||||
| // Construct a Intel AMT Scanner object
 | ||||
| 
 | ||||
| function AMTScanner() { | ||||
|     var emitterUtils = require('events').inherits(this); | ||||
|     emitterUtils.createEvent('found'); | ||||
| 
 | ||||
|     this.dgram = require('dgram'); | ||||
| 
 | ||||
|     this.buildRmcpPing = function (tag) { | ||||
|         var packet = Buffer.from('06000006000011BE80000000', 'hex'); | ||||
|         packet[9] = tag; | ||||
|         return packet; | ||||
|     }; | ||||
| 
 | ||||
|     this.parseRmcpPacket = function (server, data, rinfo, func) { | ||||
|         if (data == null || data.length < 20) return; | ||||
|         var res = {}; | ||||
|         if (((data[12] == 0) || (data[13] != 0) || (data[14] != 1) || (data[15] != 0x57)) && (data[21] & 32)) { | ||||
|             res.servertag = data[9]; | ||||
|             res.minorVersion = data[18] & 0x0F; | ||||
|             res.majorVersion = (data[18] >> 4) & 0x0F; | ||||
|             res.provisioningState = data[19] & 0x03; // Pre = 0, In = 1, Post = 2
 | ||||
| 
 | ||||
|             var openPort = (data[16] * 256) + data[17]; | ||||
|             var dualPorts = ((data[19] & 0x04) != 0) ? true : false; | ||||
|             res.openPorts = [openPort]; | ||||
|             res.address = rinfo.address; | ||||
|             if (dualPorts == true) { res.openPorts = [16992, 16993]; } | ||||
|             if (func !== undefined) { | ||||
|                 func(server, res); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     this.parseIPv4Range = function (range) { | ||||
|         if (range == undefined || range == null) return null; | ||||
|         var x = range.split('-'); | ||||
|         if (x.length == 2) { return { min: this.parseIpv4Addr(x[0]), max: this.parseIpv4Addr(x[1]) }; } | ||||
|         x = range.split('/'); | ||||
|         if (x.length == 2) { | ||||
|             var ip = this.parseIpv4Addr(x[0]), masknum = parseInt(x[1]), mask = 0; | ||||
|             if (masknum <= 16 || masknum > 32) return null; | ||||
|             masknum = 32 - masknum; | ||||
|             for (var i = 0; i < masknum; i++) { mask = (mask << 1); mask++; } | ||||
|             return { min: ip & (0xFFFFFFFF - mask), max: (ip & (0xFFFFFFFF - mask)) + mask }; | ||||
|         } | ||||
|         x = this.parseIpv4Addr(range); | ||||
|         if (x == null) return null; | ||||
|         return { min: x, max: x }; | ||||
|     }; | ||||
| 
 | ||||
|     // Parse IP address. Takes a 
 | ||||
|     this.parseIpv4Addr = function (addr) { | ||||
|         var x = addr.split('.'); | ||||
|         if (x.length == 4) { return (parseInt(x[0]) << 24) + (parseInt(x[1]) << 16) + (parseInt(x[2]) << 8) + (parseInt(x[3]) << 0); } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     // IP address number to string
 | ||||
|     this.IPv4NumToStr = function (num) { | ||||
|         return ((num >> 24) & 0xFF) + '.' + ((num >> 16) & 0xFF) + '.' + ((num >> 8) & 0xFF) + '.' + (num & 0xFF); | ||||
|     } | ||||
| 
 | ||||
|     this.scan = function (rangestr, timeout, func) { | ||||
|         var iprange = this.parseIPv4Range(rangestr); | ||||
|         var rmcp = this.buildRmcpPing(0); | ||||
|         var server = this.dgram.createSocket({ type: 'udp4' }); | ||||
|         server.parent = this; | ||||
|         server.scanResults = []; | ||||
|         server.on('error', function (err) { console.log('Error:' + err); }); | ||||
|         server.on('message', function (msg, rinfo) { if (rinfo.size > 4) { this.parent.parseRmcpPacket(this, msg, rinfo, function (s, res) { s.scanResults.push(res); }) }; }); | ||||
|         server.on('listening', function () { for (var i = iprange.min; i <= iprange.max; i++) { server.send(rmcp, 623, server.parent.IPv4NumToStr(i)); } }); | ||||
|         server.bind({ address: '0.0.0.0', port: 0, exclusive: true }); | ||||
|         var tmout = setTimeout(function cb() { | ||||
|             //console.log("Server closed");
 | ||||
|             //server.close();
 | ||||
|             server.parent.emit('found', server.scanResults); | ||||
|             if (func != null) { func(server.scanResults); } | ||||
|             delete server; | ||||
|         }, timeout); | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| module.exports = AMTScanner; | ||||
|  | @ -412,5 +412,52 @@ module.exports.CertificateOperations = function () { | |||
|         return r; | ||||
|     } | ||||
| 
 | ||||
|     // Start accelerators
 | ||||
|     const fork = require('child_process').fork; | ||||
|     const program = require('path').resolve('meshaccelerator.js'); | ||||
|     const acceleratorCreateCount = require('os').cpus().length; | ||||
|     var freeAccelerators = []; | ||||
| 
 | ||||
|     // Create a new accelerator module
 | ||||
|     obj.getAccelerator = function() { | ||||
|         if (freeAccelerators.length > 0) { return freeAccelerators.pop(); } | ||||
|         if (acceleratorCreateCount > 0) { | ||||
|             var accelerator = fork(program, [], { stdio: ['pipe', 'pipe', 'pipe', 'ipc'] }); | ||||
|             accelerator.on('message', function (message) { this.func(message); freeAccelerators.push(this); }); | ||||
|             if (obj.acceleratorCertStore != null) { accelerator.send({ action: 'setState', certs: obj.acceleratorCertStore }); } | ||||
|             return accelerator; | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
| 
 | ||||
|     // Set the state of the accelerators. This way, we don't have to send certificate & keys to them each time.
 | ||||
|     obj.acceleratorCertStore = null; | ||||
|     obj.acceleratorPerformSetState = function (certificates) { | ||||
|         obj.acceleratorCertStore = [{ cert: certificates.agent.cert, key: certificates.agent.key }]; | ||||
|         if (certificates.swarmserver != null) { obj.acceleratorCertStore.push({ cert: certificates.swarmserver.cert, key: certificates.swarmserver.key }); } | ||||
|     } | ||||
| 
 | ||||
|     // Perform any RSA signature, just pass in the private key and data.
 | ||||
|     obj.acceleratorPerformSignature = function (privatekey, data, func) { | ||||
|         var acc = obj.getAccelerator(); | ||||
|         if (acc == null) { | ||||
|             // No accelerators available
 | ||||
|             if (typeof privatekey == 'number') { privatekey = obj.acceleratorCertStore[privatekey].key; } | ||||
|             const sign = crypto.createSign('SHA384'); | ||||
|             sign.end(new Buffer(data, 'binary')); | ||||
|             func(sign.sign(privatekey).toString('binary')); | ||||
|         } else { | ||||
|             // Use the accelerator
 | ||||
|             acc.func = func; | ||||
|             acc.send({ action: 'sign', key: privatekey, data: data }); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // Perform a RSA signature. This is time consuming
 | ||||
|     obj.acceleratorPerformVerify = function (publickey, data, msg, func) { | ||||
|         console.log('Performing verification...'); | ||||
|         func(publickey.verify(data, msg)); | ||||
|     } | ||||
| 
 | ||||
|     return obj; | ||||
| }; | ||||
|  |  | |||
							
								
								
									
										28
									
								
								meshaccelerator.js
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								meshaccelerator.js
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| /** | ||||
| * @description MeshCentral accelerator | ||||
| * @author Ylian Saint-Hilaire | ||||
| * @copyright Intel Corporation 2018 | ||||
| * @license Apache-2.0 | ||||
| * @version v0.0.1 | ||||
| */ | ||||
| 
 | ||||
| const crypto = require('crypto'); | ||||
| var certStore = null; | ||||
| 
 | ||||
| process.on('message', function (message) { | ||||
|     switch (message.action) { | ||||
|         case 'sign': { | ||||
|             if (typeof message.key == 'number') { message.key = certStore[message.key].key; } | ||||
|             try { | ||||
|                 const sign = crypto.createSign('SHA384'); | ||||
|                 sign.end(new Buffer(message.data, 'binary')); | ||||
|                 process.send(sign.sign(message.key).toString('binary')); | ||||
|             } catch (e) { process.send(null); } | ||||
|             break; | ||||
|         } | ||||
|         case 'setState': { | ||||
|             certStore = message.certs; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										31
									
								
								meshagent.js
									
										
									
									
									
								
							
							
						
						
									
										31
									
								
								meshagent.js
									
										
									
									
									
								
							|  | @ -162,23 +162,20 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { | |||
|                 if (getWebCertHash(obj.domain) != msg.substring(2, 50)) { console.log('Agent connected with bad web certificate hash, holding connection (' + obj.remoteaddr + ').'); return; } | ||||
| 
 | ||||
|                 // Use our server private key to sign the ServerHash + AgentNonce + ServerNonce
 | ||||
|                 var privateKey, certasn1; | ||||
|                 if (obj.useSwarmCert == true) { | ||||
|                     // Use older SwarmServer certificate of MC1
 | ||||
|                     certasn1 = obj.parent.swarmCertificateAsn1; | ||||
|                     privateKey = obj.forge.pki.privateKeyFromPem(obj.parent.certificates.swarmserver.key); | ||||
|                 } else { | ||||
|                     // Use new MC2 certificate
 | ||||
|                     certasn1 = obj.parent.agentCertificateAsn1; | ||||
|                     privateKey = obj.forge.pki.privateKeyFromPem(obj.parent.certificates.agent.key); | ||||
|                 } | ||||
|                 var md = obj.forge.md.sha384.create(); | ||||
|                 md.update(msg.substring(2), 'binary'); | ||||
|                 md.update(obj.nonce, 'binary'); | ||||
|                 obj.agentnonce = msg.substring(50); | ||||
| 
 | ||||
|                 // Send back our certificate + signature
 | ||||
|                 obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(certasn1.length) + certasn1 + privateKey.sign(md)); // Command 2, certificate + signature
 | ||||
|                 if (obj.useSwarmCert == true) { | ||||
|                     // Perform the hash signature using older swarm server certificate
 | ||||
|                     obj.parent.parent.certificateOperations.acceleratorPerformSignature(1, msg.substring(2) + obj.nonce, function (signature) { | ||||
|                         // Send back our certificate + signature
 | ||||
|                         obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.parent.swarmCertificateAsn1.length) + obj.parent.swarmCertificateAsn1 + signature); // Command 2, certificate + signature
 | ||||
|                     }); | ||||
|                 } else { | ||||
|                     // Perform the hash signature using new server agent certificate
 | ||||
|                     obj.parent.parent.certificateOperations.acceleratorPerformSignature(0, msg.substring(2) + obj.nonce, function (signature) { | ||||
|                         // Send back our certificate + signature
 | ||||
|                         obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.parent.agentCertificateAsn1.length) + obj.parent.agentCertificateAsn1 + signature); // Command 2, certificate + signature
 | ||||
|                     }); | ||||
|                 } | ||||
| 
 | ||||
|                 // Check the agent signature if we can
 | ||||
|                 if (obj.unauthsign != null) { | ||||
|  | @ -371,7 +368,7 @@ module.exports.CreateMeshAgent = function (parent, db, ws, req, args, domain) { | |||
|         md.update(getWebCertHash(obj.domain), 'binary'); | ||||
|         md.update(obj.nonce, 'binary'); | ||||
|         md.update(obj.agentnonce, 'binary'); | ||||
|         if (obj.unauth.nodeCert.publicKey.verify(md.digest().bytes(), msg) == false) { return false; } | ||||
|         if (obj.unauth.nodeCert.publicKey.verify(md.digest().bytes(), msg) == false) { return false; } // TODO: Check if this is slow or not. May n
 | ||||
| 
 | ||||
|         // Connection is a success, clean up
 | ||||
|         obj.nodeid = obj.unauth.nodeid; | ||||
|  |  | |||
|  | @ -6,6 +6,9 @@ | |||
| * @version v0.0.1 | ||||
| */ | ||||
| 
 | ||||
| // If app metrics is available
 | ||||
| if (process.argv[2] == '--launch') { try { require('appmetrics-dash').monitor({ url: '/', title: 'MeshCentral', port: 88, host: '127.0.0.1' }); } catch (e) { } } | ||||
| 
 | ||||
| function CreateMeshCentralServer() { | ||||
|     var obj = {}; | ||||
|     obj.db; | ||||
|  | @ -30,7 +33,7 @@ function CreateMeshCentralServer() { | |||
|     obj.debugLevel = 0; | ||||
|     obj.config = {};                  // Configuration file
 | ||||
|     obj.dbconfig = {};                // Persistance values, loaded from database
 | ||||
|     obj.certificateOperations = require('./certoperations.js').CertificateOperations(); | ||||
|     obj.certificateOperations = null; | ||||
|     obj.defaultMeshCmd = null; | ||||
|     obj.defaultMeshCore = null; | ||||
|     obj.defaultMeshCoreHash = null; | ||||
|  | @ -308,8 +311,10 @@ function CreateMeshCentralServer() { | |||
|                 obj.updateMeshCmd(); | ||||
| 
 | ||||
|                 // Load server certificates
 | ||||
|                 obj.certificateOperations = require('./certoperations.js').CertificateOperations() | ||||
|                 obj.certificateOperations.GetMeshServerCertificate(obj.datapath, obj.args, obj.config, function (certs) { | ||||
|                     obj.certificates = certs; | ||||
|                     obj.certificateOperations.acceleratorPerformSetState(certs); // Set the state of the accelerators
 | ||||
| 
 | ||||
|                     // If the certificate is un-configured, force LAN-only mode
 | ||||
|                     if (obj.certificates.CommonName == 'un-configured') { console.log('Server name not configured, running in LAN-only mode.'); obj.args.lanonly = true; } | ||||
|  | @ -719,7 +724,7 @@ function CreateMeshCentralServer() { | |||
|                     var moduleName = modulesDir[i].substring(0, modulesDir[i].length - 3); | ||||
|                     var moduleDataB64 = obj.fs.readFileSync(obj.path.join(meshcorePath, 'modules_meshcore', modulesDir[i])).toString('base64'); | ||||
|                     moduleAdditions += 'try { addModule("' + moduleName + '", Buffer.from("' + moduleDataB64 + '", "base64")); addedModules.push("' + moduleName + '"); } catch (e) { }\r\n'; | ||||
|                     if ((moduleName != 'amt_heci') && (moduleName != 'lme_heci')) { | ||||
|                     if ((moduleName != 'amt_heci') && (moduleName != 'lme_heci') && (moduleName != 'amt-0.2.0.js') && (moduleName != 'amt-script-0.2.0.js') && (moduleName != 'amt-wsman-0.2.0.js') && (moduleName != 'amt-wsman-duk-0.2.0.js')) { | ||||
|                         moduleAdditionsNoMei += 'try { addModule("' + moduleName + '", Buffer.from("' + moduleDataB64 + '", "base64")); addedModules.push("' + moduleName + '"); } catch (e) { }\r\n'; | ||||
|                     } | ||||
|                 } | ||||
|  |  | |||
|  | @ -95,14 +95,13 @@ module.exports.CreateMultiServer = function (parent, args) { | |||
|                             obj.servernonce = msg.substring(50); | ||||
| 
 | ||||
|                             // Use our agent certificate root private key to sign the ServerHash + ServerNonce + PeerNonce
 | ||||
|                             var privateKey = obj.forge.pki.privateKeyFromPem(obj.certificates.agent.key); | ||||
|                             var md = obj.forge.md.sha384.create(); | ||||
|                             md.update(msg.substring(2), 'binary'); | ||||
|                             md.update(obj.nonce, 'binary'); | ||||
| 
 | ||||
|                             // Send back our certificate + signature
 | ||||
|                             agentRootCertificateAsn1 = obj.forge.asn1.toDer(obj.forge.pki.certificateToAsn1(obj.forge.pki.certificateFromPem(obj.certificates.agent.cert))).getBytes(); | ||||
|                             obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(agentRootCertificateAsn1.length) + agentRootCertificatAsn1 + privateKey.sign(md)); // Command 3, signature
 | ||||
|                             agentRootCertificateAsn1 = obj.forge.asn1.toDer(obj.forge.pki.certificateToAsn1(obj.certificates.agent.fcert)).getBytes(); | ||||
|                             obj.ws.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(agentRootCertificateAsn1.length) + agentRootCertificatAsn1 + obj.certificates.agent.fkey.sign(md)); // Command 3, signature
 | ||||
|                             break; | ||||
|                         } | ||||
|                         case 2: { | ||||
|  | @ -261,14 +260,13 @@ module.exports.CreateMultiServer = function (parent, args) { | |||
|                     if (obj.webCertificateHash != msg.substring(2, 50)) { obj.close(); return; } | ||||
| 
 | ||||
|                     // Use our server private key to sign the ServerHash + PeerNonce + ServerNonce
 | ||||
|                     var privateKey = obj.forge.pki.privateKeyFromPem(obj.parent.parent.certificates.agent.key); | ||||
|                     var md = obj.forge.md.sha384.create(); | ||||
|                     md.update(msg.substring(2), 'binary'); | ||||
|                     md.update(obj.nonce, 'binary'); | ||||
|                     obj.peernonce = msg.substring(50); | ||||
| 
 | ||||
|                     // Send back our certificate + signature
 | ||||
|                     obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + privateKey.sign(md)); // Command 2, certificate + signature
 | ||||
|                     obj.send(obj.common.ShortToStr(2) + obj.common.ShortToStr(obj.agentCertificateAsn1.length) + obj.agentCertificateAsn1 + obj.parent.parent.certificates.agent.fkey.sign(md)); // Command 2, certificate + signature
 | ||||
| 
 | ||||
|                     // Check the peer server signature if we can
 | ||||
|                     if (obj.unauthsign != null) { | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| { | ||||
|   "name": "meshcentral", | ||||
|   "version": "0.1.1-v", | ||||
|   "version": "0.1.2-b", | ||||
|   "keywords": [ | ||||
|     "Remote Management", | ||||
|     "Intel AMT", | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { | |||
|     obj.connectioncount = 0; | ||||
|     obj.rotation = 0; | ||||
|     obj.protocol = 2; // KVM
 | ||||
|     obj.debugmode = 0; | ||||
| 
 | ||||
|     obj.sessionid = 0; | ||||
|     obj.username; | ||||
|  | @ -169,13 +170,15 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) { | |||
|         if (str.length < 4) return; | ||||
|         var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2); | ||||
|         if (command >= 18) { console.error("Invalid KVM command " + command + " of size " + cmdsize); obj.parent.Stop(); return; } | ||||
|         if (cmdsize > str.length) return; | ||||
|         if (cmdsize > str.length) { console.error("KVM invalid command size", cmdsize, str.length); return; } | ||||
|         //meshOnDebug("KVM Command: " + command + " Len:" + cmdsize);
 | ||||
|         if (obj.debugmode == 1) { console.log("KVM Command: " + command + " Len:" + cmdsize); } | ||||
| 
 | ||||
|         if (command == 3 || command == 4 || command == 7) { | ||||
|             cmdmsg = str.substring(4, cmdsize); | ||||
|             X = ((cmdmsg.charCodeAt(0) & 0xFF) << 8) + (cmdmsg.charCodeAt(1) & 0xFF); | ||||
|             Y = ((cmdmsg.charCodeAt(2) & 0xFF) << 8) + (cmdmsg.charCodeAt(3) & 0xFF); | ||||
|             //if (obj.debugmode == 1) { console.log("X=" + X + " Y=" + Y); }
 | ||||
|         } | ||||
| 
 | ||||
|         switch (command) { | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) { | |||
|     obj.webrtc = null; | ||||
|     obj.webchannel = null; | ||||
|     obj.onStateChanged = null; | ||||
|     obj.debugmode = 0; | ||||
| 
 | ||||
|     // Private method
 | ||||
|     //obj.debug = function (msg) { console.log(msg); }
 | ||||
|  | @ -41,6 +42,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) { | |||
|     } | ||||
| 
 | ||||
|     obj.xxOnSocketConnected = function () { | ||||
|         if (obj.debugmode == 1) { console.log('onSocketConnected'); } | ||||
|         //obj.debug("Agent Redir Socket Connected");
 | ||||
|         obj.xxStateChange(2); | ||||
|     } | ||||
|  | @ -63,6 +65,7 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) { | |||
|     } | ||||
| 
 | ||||
|     obj.xxOnMessage = function (e) { | ||||
|         if (obj.debugmode == 1) { console.log('Recv', e.data); } | ||||
|         if (obj.State < 3) { | ||||
|             if (e.data == 'c') { | ||||
|                 obj.socket.send(obj.protocol); | ||||
|  | @ -156,10 +159,18 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) { | |||
|         //obj.debug("Agent Redir Send(" + x.length + "): " + rstr2hex(x));
 | ||||
|         if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) { | ||||
|             if (typeof x == 'string') { | ||||
|                 var b = new Uint8Array(x.length); | ||||
|                 for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); } | ||||
|                 obj.socket.send(b.buffer); | ||||
|                 if (obj.debugmode == 1) { | ||||
|                     var b = new Uint8Array(x.length), c = []; | ||||
|                     for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); c.push(x.charCodeAt(i)); } | ||||
|                     obj.socket.send(b.buffer); | ||||
|                     console.log('Send', c); | ||||
|                 } else { | ||||
|                     var b = new Uint8Array(x.length); | ||||
|                     for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); } | ||||
|                     obj.socket.send(b.buffer); | ||||
|                 } | ||||
|             } else { | ||||
|                 if (obj.debugmode == 1) { console.log('Send', x); } | ||||
|                 obj.socket.send(x); | ||||
|             } | ||||
|         } | ||||
|  | @ -167,7 +178,8 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) { | |||
| 
 | ||||
|     obj.xxOnSocketClosed = function () { | ||||
|         //obj.debug("Agent Redir Socket Closed");
 | ||||
|         obj.Stop(); | ||||
|         if (obj.debugmode == 1) { console.log('onSocketClosed'); } | ||||
|         obj.Stop(1); | ||||
|     } | ||||
| 
 | ||||
|     obj.xxStateChange = function(newstate) { | ||||
|  | @ -177,7 +189,8 @@ var CreateAgentRedirect = function (meshserver, module, serverPublicNamePort) { | |||
|         if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State); | ||||
|     } | ||||
| 
 | ||||
|     obj.Stop = function () { | ||||
|     obj.Stop = function (x) { | ||||
|         if (obj.debugmode == 1) { console.log('stop', x); } | ||||
|         //obj.debug("Agent Redir Socket Stopped");
 | ||||
|         obj.xxStateChange(0); | ||||
|         obj.connectstate = -1; | ||||
|  |  | |||
|  | @ -22,6 +22,7 @@ var CreateAmtRedirect = function (module) { | |||
|     // ###END###{!Mode-Firmware}
 | ||||
|     obj.connectstate = 0; | ||||
|     obj.protocol = module.protocol; // 1 = SOL, 2 = KVM, 3 = IDER
 | ||||
|     obj.debugmode = 0; | ||||
| 
 | ||||
|     obj.amtaccumulator = ""; | ||||
|     obj.amtsequence = 1; | ||||
|  | @ -48,6 +49,7 @@ var CreateAmtRedirect = function (module) { | |||
| 
 | ||||
|     obj.xxOnSocketConnected = function () { | ||||
|         //obj.Debug("Redir Socket Connected");
 | ||||
|         if (obj.debugmode == 1) { console.log('onSocketConnected'); } | ||||
|         obj.xxStateChange(2); | ||||
|         if (obj.protocol == 1) obj.xxSend(obj.RedirectStartSol); // TODO: Put these strings in higher level module to tighten code
 | ||||
|         if (obj.protocol == 2) obj.xxSend(obj.RedirectStartKvm); // Don't need these is the feature is not compiled-in.
 | ||||
|  | @ -55,6 +57,7 @@ var CreateAmtRedirect = function (module) { | |||
|     } | ||||
| 
 | ||||
|     obj.xxOnMessage = function (e) { | ||||
|         if (obj.debugmode == 1) { console.log('Recv', e.data); } | ||||
|         obj.inDataCount++; | ||||
|         if (typeof e.data == 'object') { | ||||
|             var f = new FileReader(); | ||||
|  | @ -113,7 +116,7 @@ var CreateAmtRedirect = function (module) { | |||
|                             cmdsize = (13 + oemlen); | ||||
|                             break; | ||||
|                         default: | ||||
|                             obj.Stop(); | ||||
|                             obj.Stop(1); | ||||
|                             break; | ||||
|                     } | ||||
|                     break; | ||||
|  | @ -141,7 +144,7 @@ var CreateAmtRedirect = function (module) { | |||
|                             // Basic Auth (Probably a good idea to not support this unless this is an old version of Intel AMT)
 | ||||
|                             obj.xxSend(String.fromCharCode(0x13, 0x00, 0x00, 0x00, 0x01) + IntToStrX(obj.user.length + obj.pass.length + 2) + String.fromCharCode(obj.user.length) + obj.user + String.fromCharCode(obj.pass.length) + obj.pass); | ||||
|                         } | ||||
|                         else obj.Stop(); | ||||
|                         else obj.Stop(2); | ||||
|                     } | ||||
|                     else if ((authType == 3 || authType == 4) && status == 1) { | ||||
|                         var curptr = 0; | ||||
|  | @ -197,7 +200,7 @@ var CreateAmtRedirect = function (module) { | |||
|                             obj.connectstate = 1; | ||||
|                             obj.xxStateChange(3); | ||||
|                         } | ||||
|                     } else obj.Stop(); | ||||
|                     } else obj.Stop(3); | ||||
|                     break; | ||||
|                 case 0x21: // Response to settings (33)
 | ||||
|                     if (obj.amtaccumulator.length < 23) break; | ||||
|  | @ -232,7 +235,7 @@ var CreateAmtRedirect = function (module) { | |||
|                     break; | ||||
|                 default: | ||||
|                     console.log("Unknown Intel AMT command: " + obj.amtaccumulator.charCodeAt(0) + " acclen=" + obj.amtaccumulator.length); | ||||
|                     obj.Stop(); | ||||
|                     obj.Stop(4); | ||||
|                     return; | ||||
|             } | ||||
|             if (cmdsize == 0) return; | ||||
|  | @ -243,6 +246,7 @@ var CreateAmtRedirect = function (module) { | |||
|     obj.xxSend = function (x) { | ||||
|         //obj.Debug("Redir Send(" + x.length + "): " + rstr2hex(x));
 | ||||
|         if (obj.socket != null && obj.socket.readyState == WebSocket.OPEN) { | ||||
|             if (obj.debugmode == 1) { console.log('Send', x); } | ||||
|             var b = new Uint8Array(x.length); | ||||
|             for (var i = 0; i < x.length; ++i) { b[i] = x.charCodeAt(i); } | ||||
|             obj.socket.send(b.buffer); | ||||
|  | @ -267,6 +271,7 @@ var CreateAmtRedirect = function (module) { | |||
|     } | ||||
| 
 | ||||
|     obj.xxOnSocketClosed = function () { | ||||
|         if (obj.debugmode == 1) { console.log('onSocketClosed'); } | ||||
|         //obj.Debug("Redir Socket Closed");
 | ||||
|         if ((obj.inDataCount == 0) && (obj.tlsv1only == 0)) { | ||||
|             obj.tlsv1only = 1; | ||||
|  | @ -275,7 +280,7 @@ var CreateAmtRedirect = function (module) { | |||
|             obj.socket.onmessage = obj.xxOnMessage; | ||||
|             obj.socket.onclose = obj.xxOnSocketClosed; | ||||
|         } else { | ||||
|             obj.Stop(); | ||||
|             obj.Stop(5); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -286,7 +291,8 @@ var CreateAmtRedirect = function (module) { | |||
|         if (obj.onStateChanged != null) obj.onStateChanged(obj, obj.State); | ||||
|     } | ||||
| 
 | ||||
|     obj.Stop = function () { | ||||
|     obj.Stop = function (x) { | ||||
|         if (obj.debugmode == 1) { console.log('onSocketStop', x); } | ||||
|         //obj.Debug("Redir Socket Stopped");
 | ||||
|         obj.xxStateChange(0); | ||||
|         obj.connectstate = -1; | ||||
|  |  | |||
|  | @ -482,7 +482,7 @@ | |||
|                         </tr> | ||||
|                         <tr> | ||||
|                             <td style="background:black;text-align:center;height:500px;position:relative"> | ||||
|                                 <div id="p15agentConsole" style="background:black;margin:0;padding:0;color:lightgray;width:100%;max-width:930px;height:100%;text-align:left;overflow-y:scroll"></div> | ||||
|                                 <div id=p15agentConsole style="background:black;margin:0;padding:0;color:lightgray;width:100%;max-width:930px;height:100%;text-align:left;overflow-y:scroll"><pre id=p15agentConsoleText></pre></div> | ||||
|                             </td> | ||||
|                         </tr> | ||||
|                         <tr> | ||||
|  | @ -509,7 +509,9 @@ | |||
|             <div id=footer class=noselect> | ||||
|                 <table cellpadding=0 cellspacing=10 style="width:100%"> | ||||
|                     <tr> | ||||
|                         <td style="text-align:left"></td> | ||||
|                         <td style="text-align:left;color:white"> | ||||
|                             {{{footer}}} | ||||
|                         </td> | ||||
|                         <td style="text-align:right"> | ||||
|                             <a id="verifyEmailId2" style="color:yellow;margin-left:3px;cursor:pointer;display:none" onclick="account_showVerifyEmail()">Verify Email</a> | ||||
|                             <a style="margin-left:3px" href="terms">Terms & Privacy</a> | ||||
|  | @ -2919,6 +2921,7 @@ | |||
|                     // Setup the Intel AMT remote desktop | ||||
|                     if ((desktopNode.intelamt.user == null) || (desktopNode.intelamt.user == '')) { editDeviceAmtSettings(desktopNode._id, connectDesktop); return; } | ||||
|                     desktop = CreateAmtRedirect(CreateAmtRemoteDesktop('Desk')); | ||||
|                     desktop.debugmode = debugmode; | ||||
|                     desktop.onStateChanged = onDesktopStateChange; | ||||
|                     desktop.m.bpp = (desktopsettings.encoding == 1 || desktopsettings.encoding == 3) ? 1 : 2; | ||||
|                     desktop.m.useZRLE = (desktopsettings.encoding < 3); | ||||
|  | @ -2929,7 +2932,9 @@ | |||
|                 } else { | ||||
|                     // Setup the Mesh Agent remote desktop | ||||
|                     desktop = CreateAgentRedirect(meshserver, CreateAgentRemoteDesktop('Desk'), serverPublicNamePort); | ||||
|                     desktop.attemptWebRTC = debugmode; | ||||
|                     desktop.debugmode = debugmode; | ||||
|                     desktop.m.debugmode = debugmode; | ||||
|                     //desktop.attemptWebRTC = debugmode; | ||||
|                     desktop.onStateChanged = onDesktopStateChange; | ||||
|                     desktop.m.CompressionLevel = desktopsettings.quality; // Number from 1 to 100. 50 or less is best. | ||||
|                     desktop.m.ScalingLevel = desktopsettings.scaling; | ||||
|  | @ -3165,13 +3170,16 @@ | |||
|                     // Setup the Intel AMT terminal | ||||
|                     if ((terminalNode.intelamt.user == null) || (terminalNode.intelamt.user == '')) { editDeviceAmtSettings(terminalNode._id, connectTerminal); return; } | ||||
|                     terminal = CreateAmtRedirect(CreateAmtRemoteTerminal('Term')); | ||||
|                     terminal.debugmode = debugmode; | ||||
|                     terminal.onStateChanged = onTerminalStateChange; | ||||
|                     terminal.Start(terminalNode._id, 16994, '*', '*', 0); | ||||
|                     terminal.contype = 2; | ||||
|                 } else { | ||||
|                     // Setup a mesh agent terminal | ||||
|                     terminal = CreateAgentRedirect(meshserver, CreateAmtRemoteTerminal('Term'), serverPublicNamePort); | ||||
|                     terminal.attemptWebRTC = debugmode; | ||||
|                     terminal.debugmode = debugmode; | ||||
|                     terminal.m.debugmode = debugmode; | ||||
|                     //terminal.attemptWebRTC = debugmode; | ||||
|                     terminal.onStateChanged = onTerminalStateChange; | ||||
|                     terminal.Start(terminalNode._id); | ||||
|                     terminal.contype = 1; | ||||
|  | @ -3649,6 +3657,7 @@ | |||
|                     if ((e.keyCode == 38) && ((consoleHistory.length - 1) > hindex)) { box.value = consoleHistory[hindex + 1]; } | ||||
|                     else if ((e.keyCode == 40) && (hindex > 0)) { box.value = consoleHistory[hindex - 1]; } | ||||
|                     else if ((e.keyCode == 40) && (hindex == 0)) { box.value = ''; } | ||||
|                     processed = 1; | ||||
|                 } | ||||
|             } else { | ||||
|                 if (e.charCode != 0 && consoleFocus == 0) { box.value = ((box.value + String.fromCharCode(e.charCode))); processed = 1; } | ||||
|  | @ -3667,7 +3676,7 @@ | |||
|             if ((meshrights & 16) != 0) { | ||||
|                 if (consoleNode.consoleText == null) { consoleNode.consoleText = ''; } | ||||
|                 if (samenode == false) { | ||||
|                     QH('p15agentConsole', consoleNode.consoleText); | ||||
|                     QH('p15agentConsoleText', consoleNode.consoleText); | ||||
|                     Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight; | ||||
|                 } | ||||
|                 var online = ((consoleNode.conn & 1) != 0)?true:false; | ||||
|  | @ -3683,7 +3692,7 @@ | |||
| 
 | ||||
|         // Clear the console for this node | ||||
|         function p15consoleClear() { | ||||
|             QH('p15agentConsole', ''); | ||||
|             QH('p15agentConsoleText', ''); | ||||
|             Q('id_p15consoleClear').blur(); | ||||
|             consoleNode.consoleText = ''; | ||||
|         } | ||||
|  | @ -3693,7 +3702,7 @@ | |||
|         function p15consoleSend(e) { | ||||
|             if (e && e.keyCode != 13) return; | ||||
|             var v = Q('p15consoleText').value, t = '<div style=color:green>> ' + EscapeHtml(Q('p15consoleText').value) + '<br/></div>'; | ||||
|             Q('p15agentConsole').innerHTML += t; | ||||
|             Q('p15agentConsoleText').innerHTML += t; | ||||
|             consoleNode.consoleText += t; | ||||
|             Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight; | ||||
|             Q('p15consoleText').value = ''; | ||||
|  | @ -3716,7 +3725,7 @@ | |||
|             data = '<div>' + EscapeHtmlBreaks(data) + '</div>' | ||||
|             if (node.consoleText == null) { node.consoleText = data; } else { node.consoleText += data; } | ||||
|             if (consoleNode == node) { | ||||
|                 Q('p15agentConsole').innerHTML += data; | ||||
|                 Q('p15agentConsoleText').innerHTML += data; | ||||
|                 Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight; | ||||
|             } | ||||
|         } | ||||
|  |  | |||
|  | @ -136,7 +136,9 @@ | |||
|             <div id=footer> | ||||
|                 <table cellpadding=0 cellspacing=10 style=width:100%> | ||||
|                     <tr> | ||||
|                         <td style=text-align:left></td> | ||||
|                         <td style=text-align:left;color:white> | ||||
|                             {{{footer}}} | ||||
|                         </td> | ||||
|                         <td style=text-align:right> | ||||
|                             {{{rootCertLink}}} | ||||
|                              <a href=terms>Terms & Privacy</a> | ||||
|  |  | |||
							
								
								
									
										40
									
								
								webserver.js
									
										
									
									
									
								
							
							
						
						
									
										40
									
								
								webserver.js
									
										
									
									
									
								
							|  | @ -39,7 +39,7 @@ if (!String.prototype.endsWith) { String.prototype.endsWith = function (searchSt | |||
| module.exports.CreateWebServer = function (parent, db, args, secret, certificates) { | ||||
|     var obj = {}; | ||||
| 
 | ||||
|     // Modules    
 | ||||
|     // Modules
 | ||||
|     obj.fs = require('fs'); | ||||
|     obj.net = require('net'); | ||||
|     obj.tls = require('tls'); | ||||
|  | @ -270,6 +270,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate | |||
| 
 | ||||
|     // Return the current domain of the request
 | ||||
|     function getDomain(req) { | ||||
|         if (req.xdomain != null) { return req.xdomain; } // Domain already set for this request, return it.
 | ||||
|         if (req.headers.host != null) { var d = obj.dnsDomains[req.headers.host.toLowerCase()]; if (d != null) return d; } // If this is a DNS name domain, return it here.
 | ||||
|         var x = req.url.split('/'); | ||||
|         if (x.length < 2) return parent.config.domains['']; | ||||
|  | @ -682,14 +683,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate | |||
|             if (obj.args.tlsoffload == true) { features += 16; } // No mutual-auth CIRA
 | ||||
|             if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
 | ||||
|             if ((!obj.args.user) && (obj.args.nousers != true) && (nologout == false)) { logoutcontrol += ' <a href=' + domain.url + 'logout?' + Math.random() + ' style=color:white>Logout</a>'; } // If a default user is in use or no user mode, don't display the logout button
 | ||||
|             res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass, webcerthash: obj.webCertificateHashBase64 }); | ||||
|             res.render(obj.path.join(__dirname, 'views/default'), { viewmode: viewmode, currentNode: currentNode, logoutControl: logoutcontrol, title: domain.title, title2: domain.title2, domainurl: domain.url, domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass, webcerthash: obj.webCertificateHashBase64, footer: (domain.footer == null) ? '' : domain.footer }); | ||||
|         } else { | ||||
|             // Send back the login application
 | ||||
|             var loginmode = req.session.loginmode; | ||||
|             delete req.session.loginmode; // Clear this state, if the user hits refresh, we want to go back to the login page.
 | ||||
|             var features = 0; | ||||
|             if ((parent.config != null) && (parent.config.settings != null) && (parent.config.settings.allowframing == true)) { features += 32; } // Allow site within iframe
 | ||||
|             res.render(obj.path.join(__dirname, 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: obj.args.port, emailcheck: obj.parent.mailserver != null, features: features }); | ||||
|             res.render(obj.path.join(__dirname, 'views/login'), { loginmode: loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: getWebServerName(domain), serverPublicPort: obj.args.port, emailcheck: obj.parent.mailserver != null, features: features, footer: (domain.footer == null) ? '' : domain.footer }); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|  | @ -1518,18 +1519,33 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate | |||
| 
 | ||||
|     // Add HTTP security headers to all responses
 | ||||
|     obj.app.use(function (req, res, next) { | ||||
|         // Two more headers to take a look at:
 | ||||
|         //   'Public-Key-Pins': 'pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg="; max-age=10'
 | ||||
|         //   'strict-transport-security': 'max-age=31536000; includeSubDomains'
 | ||||
|         res.removeHeader("X-Powered-By"); | ||||
|         if (obj.args.notls) { | ||||
|             // Default headers if no TLS is used
 | ||||
|             res.set({ 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src http: ws: data: 'self';script-src http: 'unsafe-inline';style-src http: 'unsafe-inline'" }); | ||||
|         var domain = req.xdomain = getDomain(req); | ||||
| 
 | ||||
|         // Detect if this is a file sharing domain, if so, just share files.
 | ||||
|         if ((domain != null) && (domain.share != null)) { | ||||
|             var rpath; | ||||
|             if (domain.dns == null) { rpath = req.url.split('/'); rpath.splice(1, 1); rpath = rpath.join('/'); } else { rpath = req.url; } | ||||
|             if ((res.headers != null) && (res.headers.upgrade)) { | ||||
|                 // If this is a websocket, stop here.
 | ||||
|                 res.sendStatus(404); | ||||
|             } else { | ||||
|                 // Check if the file exists, if so, serve it.
 | ||||
|                 obj.fs.exists(obj.path.join(domain.share, rpath), function (exists) { if (exists == true) { res.sendfile(rpath, { root: domain.share }); } else { res.sendStatus(404); } }); | ||||
|             } | ||||
|         } else { | ||||
|             // Default headers if TLS is used
 | ||||
|             res.set({ 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src https: wss: data: 'self';script-src https: 'unsafe-inline';style-src https: 'unsafe-inline'" }); | ||||
|             // Two more headers to take a look at:
 | ||||
|             //   'Public-Key-Pins': 'pin-sha256="X3pGTSOuJeEVw989IJ/cEtXUEmy52zs1TZQrU06KUKg="; max-age=10'
 | ||||
|             //   'strict-transport-security': 'max-age=31536000; includeSubDomains'
 | ||||
|             if (obj.args.notls) { | ||||
|                 // Default headers if no TLS is used
 | ||||
|                 res.set({ 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src http: ws: data: 'self';script-src http: 'unsafe-inline';style-src http: 'unsafe-inline'" }); | ||||
|             } else { | ||||
|                 // Default headers if TLS is used
 | ||||
|                 res.set({ 'Referrer-Policy': 'no-referrer', 'x-frame-options': 'SAMEORIGIN', 'X-XSS-Protection': '1; mode=block', 'X-Content-Type-Options': 'nosniff', 'Content-Security-Policy': "default-src https: wss: data: 'self';script-src https: 'unsafe-inline';style-src https: 'unsafe-inline'" }); | ||||
|             } | ||||
|             return next(); | ||||
|         } | ||||
|         return next(); | ||||
|     }); | ||||
| 
 | ||||
|     // Setup all HTTP handlers
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue