Improved web interface for getting started.

Ylian Saint-Hilaire committed Oct 2, 2017 at 14:12 UTC 5474f1d3869cd6dbe6e0d1a22c5637a8792651c9
9 files changed +263 -127
MeshCentralServer.njsproj
-3
@@ -71,7 +71,6 @@
71 <Content Include="public\images-isdu\info.gif" />
72 <Content Include="public\images-isdu\warning.gif" />
73 <Content Include="public\images-isdu\isdu.ico" />
74 - <Content Include="public\styles\font-awesome\css\font-awesome.css" />
74 <Content Include="public\styles\font-awesome\css\font-awesome.min.css" />
75 <Content Include="public\styles\font-awesome\fonts\fontawesome-webfont.eot" />
76 <Content Include="public\styles\font-awesome\fonts\fontawesome-webfont.svg" />
@@ -120,8 +119,6 @@
119 <Folder Include="public\images-isdu" />
120 <Folder Include="public\scripts\" />
121 <Folder Include="public\styles\" />
123 - <Folder Include="public\styles\font-awesome\" />
124 - <Folder Include="public\styles\font-awesome\css\" />
122 <Folder Include="public\styles\font-awesome\fonts\" />
123 <Folder Include="public\styles\font-awesome\less\" />
124 <Folder Include="public\styles\font-awesome\scss\" />
agents/meshcore.js
+2 -2
@@ -277,9 +277,9 @@ function createMeshCore(agent) {
277 else if (data.type == 'tunnel') { // Process a new tunnel connection request
278 if (data.value && data.sessionid) {
279 // Create a new tunnel object
280 - //sendConsoleText(data.value);
280 + sendConsoleText(data.value);
281 var xurl = getServerTargetUrlEx(data.value);
282 - //sendConsoleText(xurl);
282 + sendConsoleText(xurl);
283 if (xurl != null) {
284 var tunnel = http.request(http.parseUri(xurl));
285 tunnel.upgrade = onTunnelUpgrade;
certoperations.js
+37 -28
@@ -38,24 +38,23 @@ module.exports.CertificateOperations = function () {
38 cert.validity.notAfter = new Date();
39 cert.validity.notAfter.setFullYear(cert.validity.notAfter.getFullYear() + 30);
40 if (addThumbPrintToName == true) { commonName += '-' + obj.pki.getPublicKeyFingerprint(cert.publicKey, { encoding: 'hex' }).substring(0, 6); }
41 - var attrs = [ { name: 'commonName', value: commonName } ];
42 - if (country != undefined) attrs.push({ name: 'countryName', value: country });
43 - if (organization != undefined) attrs.push({ name: 'organizationName', value: organization });
41 + if (country == undefined) { country = 'unknown'; }
42 + if (organization == undefined) { organization = 'unknown'; }
43 + var attrs = [{ name: 'commonName', value: commonName }, { name: 'organizationName', value: organization }, { name: 'countryName', value: country }];
44 cert.setSubject(attrs);
45 cert.setIssuer(attrs);
46 - cert.setExtensions([
47 - { name: 'basicConstraints', cA: true },
48 - {
46 + // Create a root certificate
47 + cert.setExtensions([{
48 + name: 'basicConstraints',
49 + cA: true
50 + }, {
51 name: 'nsCertType',
50 - client: false,
51 - server: false,
52 - email: false,
53 - objsign: false,
52 sslCA: true,
55 - emailCA: false,
53 + emailCA: true,
54 objCA: true
57 - }
58 - ]);
55 + }, {
56 + name: 'subjectKeyIdentifier'
57 + }]);
58 cert.sign(keys.privateKey, obj.forge.md.sha256.create());
59
60 return { cert: cert, key: keys.privateKey };
@@ -136,7 +135,8 @@ module.exports.CertificateOperations = function () {
135 }
136
137 // Returns the web server TLS certificate and private key, if not present, create demonstration ones.
139 - obj.GetMeshServerCertificate = function (directory, certargs, func) {
138 + obj.GetMeshServerCertificate = function (directory, args, func) {
139 + var certargs = args.cert;
140 // commonName, country, organization
141
142 // If the certificates directory does not exist, create it.
@@ -151,16 +151,25 @@ module.exports.CertificateOperations = function () {
151 r.root = { cert: rootCertificate, key: rootPrivateKey };
152 rcount++;
153 }
154 -
155 - // If the web certificate already exist, load it
156 - if (obj.fileExists(directory + '/webserver-cert-public.crt') && obj.fileExists(directory + '/webserver-cert-private.key')) {
157 - var webCertificate = obj.fs.readFileSync(directory + '/webserver-cert-public.crt', 'utf8');
158 - var webPrivateKey = obj.fs.readFileSync(directory + '/webserver-cert-private.key', 'utf8');
159 - r.web = { cert: webCertificate, key: webPrivateKey };
160 - rcount++;
154 +
155 + if (args.tlsoffload == true) {
156 + // If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
157 + if (obj.fileExists(directory + '/webserver-cert-public.crt')) {
158 + var webCertificate = obj.fs.readFileSync(directory + '/webserver-cert-public.crt', 'utf8');
159 + r.web = { cert: webCertificate };
160 + rcount++;
161 + }
162 + } else {
163 + // If the web certificate already exist, load it. Load both certificate and private key
164 + if (obj.fileExists(directory + '/webserver-cert-public.crt') && obj.fileExists(directory + '/webserver-cert-private.key')) {
165 + var webCertificate = obj.fs.readFileSync(directory + '/webserver-cert-public.crt', 'utf8');
166 + var webPrivateKey = obj.fs.readFileSync(directory + '/webserver-cert-private.key', 'utf8');
167 + r.web = { cert: webCertificate, key: webPrivateKey };
168 + rcount++;
169 + }
170 }
171
163 - // If the bin certificate already exist, load it
172 + // If the mps certificate already exist, load it
173 if (obj.fileExists(directory + '/mpsserver-cert-public.crt') && obj.fileExists(directory + '/mpsserver-cert-private.key')) {
174 var mpsCertificate = obj.fs.readFileSync(directory + '/mpsserver-cert-public.crt', 'utf8');
175 var mpsPrivateKey = obj.fs.readFileSync(directory + '/mpsserver-cert-private.key', 'utf8');
@@ -168,7 +177,7 @@ module.exports.CertificateOperations = function () {
177 rcount++;
178 }
179
171 - // If the bin certificate already exist, load it
180 + // If the agent certificate already exist, load it
181 if (obj.fileExists(directory + '/agentserver-cert-public.crt') && obj.fileExists(directory + '/agentserver-cert-private.key')) {
182 var agentCertificate = obj.fs.readFileSync(directory + '/agentserver-cert-public.crt', 'utf8');
183 var agentPrivateKey = obj.fs.readFileSync(directory + '/agentserver-cert-private.key', 'utf8');
@@ -176,7 +185,7 @@ module.exports.CertificateOperations = function () {
185 rcount++;
186 }
187
179 - // If the bin certificate already exist, load it
188 + // If the console certificate already exist, load it
189 if (obj.fileExists(directory + '/amtconsole-cert-public.crt') && obj.fileExists(directory + '/agentserver-cert-private.key')) {
190 var amtConsoleCertificate = obj.fs.readFileSync(directory + '/amtconsole-cert-public.crt', 'utf8');
191 var amtConsolePrivateKey = obj.fs.readFileSync(directory + '/amtconsole-cert-private.key', 'utf8');
@@ -198,14 +207,14 @@ module.exports.CertificateOperations = function () {
207 r.calist = calist;
208
209 // Decode certificate arguments
201 - var commonName = 'un-configured', country, organization;
210 + var commonName = 'un-configured', country, organization, forceWebCertGen = 0;
211 if (certargs != undefined) {
212 var args = certargs.split(',');
213 if (args.length > 0) commonName = args[0];
214 if (args.length > 1) country = args[1];
215 if (args.length > 2) organization = args[2];
216 }
208 -
217 +
218 if (rcount == 5) {
219 // Fetch the Intel AMT console name
220 var consoleCertificate = obj.pki.certificateFromPem(r.console.cert);
@@ -220,7 +229,7 @@ module.exports.CertificateOperations = function () {
229 if (xcountryField != null) { xcountry = xcountryField.value; }
230 var xorganization, xorganizationField = webCertificate.subject.getField('O');
231 if (xorganizationField != null) { xorganization = xorganizationField.value; }
223 - if ((r.CommonName == commonName) && (xcountry == country) && (xorganization == organization)) { if (func != undefined) { func(r); } return r; } // If the certificate matches what we want, keep it.
232 + if ((r.CommonName == commonName) && (xcountry == country) && (xorganization == organization)) { if (func != undefined) { func(r); } return r; } else { forceWebCertGen = 1; } // If the certificate matches what we want, keep it.
233 }
234 console.log('Generating certificates...');
235
@@ -242,7 +251,7 @@ module.exports.CertificateOperations = function () {
251
252 // If the web certificate does not exist, create one
253 var webCertAndKey, webCertificate, webPrivateKey;
245 - if (r.web == undefined) {
254 + if ((r.web == undefined) || (forceWebCertGen == 1)) {
255 webCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, commonName, country, organization);
256 webCertificate = obj.pki.certificateToPem(webCertAndKey.cert);
257 webPrivateKey = obj.pki.privateKeyToPem(webCertAndKey.key);
meshcentral.js
+7 -3
@@ -201,8 +201,12 @@ function CreateMeshCentralServer() {
201 var xdomains = {}; for (var i in obj.config.domains) { if (!obj.config.domains[i].title) { obj.config.domains[i].title = 'MeshCentral'; } if (!obj.config.domains[i].title2) { obj.config.domains[i].title2 = '2.0 Beta 1'; } xdomains[i.toLowerCase()] = obj.config.domains[i]; } obj.config.domains = xdomains;
202 var bannedDomains = ['public', 'private', 'images', 'scripts', 'styles', 'views']; // List of banned domains
203 for (var i in obj.config.domains) { for (var j in bannedDomains) { if (i == bannedDomains[j]) { console.log("ERROR: Domain '" + i + "' is not allowed domain name in ./data/config.json."); return; } } }
204 - for (var i in obj.config.domains) { obj.config.domains[i].url = (i == '')?'/':('/' + i + '/'); obj.config.domains[i].id = i; }
205 -
204 + for (var i in obj.config.domains) {
205 + for (var j in obj.config.domains[i]) { obj.config.domains[i][j.toLocaleLowerCase()] = obj.config.domains[i][j]; } // LowerCase all domain keys
206 + obj.config.domains[i].url = (i == '') ? '/' : ('/' + i + '/'); obj.config.domains[i].id = i;
207 + if (typeof obj.config.domains[i].userallowedip == 'string') { obj.config.domains[i].userallowedip = null; if (obj.config.domains[i].userallowedip != "") { obj.config.domains[i].userallowedip = obj.config.domains[i].userallowedip.split(','); } }
208 + }
209 +
210 // Log passed arguments into Windows Service Log
211 //if (obj.servicelog != null) { var s = ''; for (var i in obj.args) { if (i != '_') { if (s.length > 0) { s += ', '; } s += i + "=" + obj.args[i]; } } logInfoEvent('MeshServer started with arguments: ' + s); }
212
@@ -283,7 +287,7 @@ function CreateMeshCentralServer() {
287 obj.updateMeshCore();
288
289 // Load server certificates
286 - obj.certificateOperations.GetMeshServerCertificate(obj.datapath, obj.args.cert, function (certs) {
290 + obj.certificateOperations.GetMeshServerCertificate(obj.datapath, obj.args, function (certs) {
291 obj.certificates = certs;
292
293 // If the certificate is un-configured, force LAN-only mode
mesherrors.txt
+94
@@ -189,3 +189,97 @@ TypeError: Cannot read property 'SSL_OP_NO_SSLv2' of undefined
189 at Immediate._onImmediate (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\async\lib\async.js:498:34)
190
191
192 +-------- 10/1/2017, 10:21:38 AM --------
193 +
194 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:91
195 + console.log(obj.servers4.keys());
196 + ^
197 +
198 +TypeError: obj.servers4.keys is not a function
199 + at setupServers (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:91:34)
200 + at Object.obj.start (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:136:9)
201 + at InternalFieldObject.ondone (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshcentral.js:328:98)
202 +
203 +
204 +-------- 10/1/2017, 10:21:40 AM --------
205 +
206 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:91
207 + console.log(obj.servers4.keys());
208 + ^
209 +
210 +TypeError: obj.servers4.keys is not a function
211 + at setupServers (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:91:34)
212 + at Object.obj.start (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:136:9)
213 + at InternalFieldObject.ondone (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshcentral.js:328:98)
214 +
215 +
216 +-------- 10/1/2017, 10:54:43 AM --------
217 +
218 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:96
219 + performScan(server6);
220 + ^
221 +
222 +ReferenceError: performScan is not defined
223 + at Socket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:96:21)
224 + at Socket.g (events.js:286:16)
225 + at emitNone (events.js:86:13)
226 + at Socket.emit (events.js:185:7)
227 + at startListening (dgram.js:121:10)
228 + at dgram.js:228:7
229 + at _combinedTickCallback (internal/process/next_tick.js:77:11)
230 + at process._tickCallback (internal/process/next_tick.js:98:9)
231 +
232 +
233 +-------- 10/1/2017, 10:54:45 AM --------
234 +
235 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:96
236 + performScan(server6);
237 + ^
238 +
239 +ReferenceError: performScan is not defined
240 + at Socket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:96:21)
241 + at Socket.g (events.js:286:16)
242 + at emitNone (events.js:86:13)
243 + at Socket.emit (events.js:185:7)
244 + at startListening (dgram.js:121:10)
245 + at dgram.js:228:7
246 + at _combinedTickCallback (internal/process/next_tick.js:77:11)
247 + at process._tickCallback (internal/process/next_tick.js:98:9)
248 +
249 +
250 +-------- 10/1/2017, 10:54:47 AM --------
251 +
252 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:96
253 + performScan(server6);
254 + ^
255 +
256 +ReferenceError: performScan is not defined
257 + at Socket.<anonymous> (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshscanner.js:96:21)
258 + at Socket.g (events.js:286:16)
259 + at emitNone (events.js:86:13)
260 + at Socket.emit (events.js:185:7)
261 + at startListening (dgram.js:121:10)
262 + at dgram.js:228:7
263 + at _combinedTickCallback (internal/process/next_tick.js:77:11)
264 + at process._tickCallback (internal/process/next_tick.js:98:9)
265 +
266 +
267 +-------- 10/1/2017, 11:49:12 AM --------
268 +
269 +C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\node-forge\js\x509.js:2052
270 + throw error;
271 + ^
272 +
273 +Error: Attribute value not specified.
274 + at _fillMissingFields (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\node-forge\js\x509.js:2050:19)
275 + at Object.cert.setSubject (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\node-forge\js\x509.js:948:5)
276 + at Object.obj.GenerateRootCertificate (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\certoperations.js:44:14)
277 + at Object.obj.GetMeshServerCertificate (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\certoperations.js:230:34)
278 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\meshcentral.js:286:43
279 + at newArguments.(anonymous function) (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\executor.js:29:17)
280 + at Cursor.execFn (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\datastore.js:484:12)
281 + at callback (C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\cursor.js:126:19)
282 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\cursor.js:193:12
283 + at C:\Users\Default.DESKTOP-M9I88C9\Desktop\AmtWebApp\meshcentral\node_modules\nedb\lib\datastore.js:329:14
284 +
285 +
meshscanner.js
+39 -29
@@ -22,8 +22,7 @@ module.exports.CreateMeshScanner = function (parent) {
22
23 // Get a list of IPv4 and IPv6 interface addresses
24 function getInterfaceList() {
25 - var ipv4 = [];
26 - var ipv6 = [];
25 + var ipv4 = ['*'], ipv6 = ['*'];
26 var interfaces = require('os').networkInterfaces();
27 for (var i in interfaces) {
28 var interface = interfaces[i];
@@ -50,25 +49,32 @@ module.exports.CreateMeshScanner = function (parent) {
49 obj.servers4[localAddress].xxclear = false;
50 } else {
51 // Create a new IPv4 server
53 - var server4 = obj.dgram.createSocket("udp4");
54 - server4.xxclear = false;
55 - server4.xxtype = 4;
56 - server4.xxlocal = localAddress;
57 - server4.on('error', function (err) { console.log("ERROR: Server port " + server4.xxlocal + ":16989 not available, check if server is running twice."); server4.close(); server4 = null; });
58 - server4.bind({ address: server4.xxlocal, port: 16989, exclusive: false }, function () {
59 - try {
60 - server4.setBroadcast(true);
61 - server4.setMulticastTTL(128);
62 - server4.addMembership(membershipIPv4);
63 - server4.on('error', function (error) { console.log('Error: ' + error); });
64 - server4.on('message', function (msg, info) { onUdpPacket(msg, info, server4); });
65 - obj.performScan(server4);
66 - obj.performScan(server4);
67 - } catch (e) { }
68 - });
69 - obj.servers4[localAddress] = server4;
52 + try {
53 + var server4 = obj.dgram.createSocket("udp4");
54 + server4.xxclear = false;
55 + server4.xxtype = 4;
56 + server4.xxlocal = localAddress;
57 + server4.on('error', function (err) { console.log("ERROR: Server port " + server4.xxlocal + ":16989 not available, check if server is running twice."); server4.close(); server4 = null; });
58 + var bindOptions = { port: 16989, exclusive: false };
59 + if (server4.xxlocal != '*') { bindOptions.address = server4.xxlocal; }
60 + server4.bind(bindOptions, function () {
61 + try {
62 + this.setBroadcast(true);
63 + this.setMulticastTTL(128);
64 + this.addMembership(membershipIPv4);
65 + server4.on('error', function (error) { console.log('Error: ' + error); });
66 + server4.on('message', function (msg, info) { onUdpPacket(msg, info, server4); });
67 + obj.performScan(this);
68 + obj.performScan(this);
69 + } catch (e) { }
70 + });
71 + obj.servers4[localAddress] = server4;
72 + } catch (e) {
73 + console.log(e);
74 + }
75 }
76 }
77 +
78 for (var i in addresses.ipv6) {
79 var localAddress = addresses.ipv6[i];
80 if (obj.servers6[localAddress] != null) {
@@ -80,16 +86,18 @@ module.exports.CreateMeshScanner = function (parent) {
86 server6.xxclear = false;
87 server6.xxtype = 6;
88 server6.xxlocal = localAddress;
83 - server6.on('error', function (err) { console.log("ERROR: Server port [" + server6.xxlocal + "]:16989 not available, check if server is running twice.");server6.close(); obj.server6 = null; });
84 - server6.bind({ address: server6.xxlocal, port: 16989, exclusive: false }, function () {
89 + server6.on('error', function (err) { console.log("ERROR: Server port [" + server6.xxlocal + "]:16989 not available, check if server is running twice."); server6.close(); obj.server6 = null; });
90 + var bindOptions = { port: 16989, exclusive: false };
91 + if (server6.xxlocal != '*') { bindOptions.address = server6.xxlocal; }
92 + server6.bind(bindOptions, function () {
93 try {
86 - server6.setBroadcast(true);
87 - server6.setMulticastTTL(128);
88 - server6.addMembership(membershipIPv6);
89 - server6.on('error', function (error) { console.log('Error: ' + error); });
90 - server6.on('message', function (msg, info) { onUdpPacket(msg, info, server6); });
91 - performScan(server6);
92 - performScan(server6);
94 + this.setBroadcast(true);
95 + this.setMulticastTTL(128);
96 + this.addMembership(membershipIPv6);
97 + this.on('error', function (error) { console.log('Error: ' + error); });
98 + this.on('message', function (msg, info) { onUdpPacket(msg, info, this); });
99 + obj.performScan(this);
100 + obj.performScan(this);
101 } catch (e) { }
102 });
103 obj.servers6[localAddress] = server6;
@@ -128,6 +136,8 @@ module.exports.CreateMeshScanner = function (parent) {
136 if (server != null) {
137 if (server.xxtype == 4) { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); }
138 if (server.xxtype == 6) { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); }
139 + if ((server.xxtype == 4) && (server.xxlocal == '*')) { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, '127.0.0.1'); server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, '255.255.255.255'); }
140 + if ((server.xxtype == 6) && (server.xxlocal == '*')) { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, '::1'); }
141 } else {
142 for (var i in obj.servers4) { obj.servers4[i].send(obj.multicastPacket4, 0, obj.multicastPacket4.length, 16990, membershipIPv4); }
143 for (var i in obj.servers6) { obj.servers6[i].send(obj.multicastPacket6, 0, obj.multicastPacket6.length, 16990, membershipIPv6); }
@@ -137,7 +147,7 @@ module.exports.CreateMeshScanner = function (parent) {
147
148 // Called when a UDP packet is received from an agent.
149 function onUdpPacket(msg, info, server) {
140 - // console.log('Received ' + msg.length + ' bytes from ' + info.address + ':' + info.port + ', on interface: ' + server.xxlocal + '.');
150 + //console.log('Received ' + msg.length + ' bytes from ' + info.address + ':' + info.port + ', on interface: ' + server.xxlocal + '.');
151 if ((msg.length == 64) && (msg.toString('ascii') == obj.agentCertificatHashHex.toUpperCase())) {
152 if (server.xxtype == 4) { server.send(obj.multicastPacket4, 0, obj.multicastPacket4.length, info.port, info.address); }
153 if (server.xxtype == 6) { server.send(obj.multicastPacket6, 0, obj.multicastPacket6.length, info.port, info.address); }
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.0.8-g",
3 + "version": "0.0.8-j",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
views/default.handlebars
+22 -16
@@ -119,7 +119,7 @@
119 <div class="auto-style1" style="height: 100%; float: right">
120 <div style="height:100%;width:4px;float:right;background-color:#ffffff"></div>
121 <div class=h2 style="height:100%;float:right">&nbsp;</div>
122 - <div style=float:right>
122 + <div style=float:right id=devListToolbarView>
123 View
124 <select id=viewselect onchange=onDeviceViewChange()>
125 <option value=1>3 wide</option>
@@ -138,18 +138,17 @@
138 </div>
139 </div>
140 </div>
141 - <div id=NoNodesPanel style=display:none>
142 - <table style="width: 100%">
141 + <div id=NoMeshesPanel style=display:none>
142 + <table style="width:100%;padding:20px">
143 <tr>
144 <td valign="top" style="width: 50px">
145 <img src="images/info.png" height="48" width="47" />
146 </td>
147 <td>
148 - No nodes found with this search criteria. To create a mesh network and add devices, start at the <a onclick=go(2) style="cursor:pointer">My Account</a> page.
148 + To get started managing devices, <a onclick=account_createMesh() style=cursor:pointer><strong>click here to create a new group of devices called a Mesh</strong></a>.
149 </td>
150 </tr>
151 </table>
152 - <p></p>
152 </div>
153 <div id="xdevices" style="max-height:calc(100vh - 228px);overflow-y:auto;-webkit-overflow-scrolling:touch"></div>
154 <div id="xdevicesmap" style="height:500px;width:100%;overflow:hidden;position:relative">
@@ -184,7 +183,7 @@
183 ( <a onclick=account_createMesh() style=cursor:pointer><img height=12 src="images/icon-addnew.png" width=12 border=0 /> New</a> )
184 <br /><br />
185 <div id=p2meshes></div>
187 - <div id=p2noMeshFound style=margin-left:40px;display:none>No meshes found. <a onclick=account_createMesh() style=cursor:pointer><strong>Get started here!</strong></a><br /><br /></div>
186 + <div id=p2noMeshFound style=margin-left:40px;display:none>No meshes. <a onclick=account_createMesh() style=cursor:pointer><strong>Get started here!</strong></a><br /><br /></div>
187 </div>
188 <div id=p3 style=display:none>
189 <h1>My Events</h1>
@@ -406,13 +405,13 @@
405 <td style="width:100%;background-color:#d3d9d6;text-align:left;padding:4px" valign=bottom>
406 <div id="p13rightOfButtons" style="float:right;margin-top:3px"></div>
407 <div>
409 - <input type=button id="p13FolderUp" disabled="disabled" onclick="p13folderup()" value="Up" />&nbsp;
410 - <input type=button id="p13SelectAllButton" disabled="disabled" onclick="p13selectallfile()" value="Select All" onkeypress="return false" onkeydown="return false" />&nbsp;
411 - <input type=button id="p13RenameFileButton" disabled="disabled" value="Rename" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false" />&nbsp;
412 - <input type=button id="p13DeleteFileButton" disabled="disabled" value="Delete" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false" />&nbsp;
413 - <input type=button id="p13NewFolderButton" disabled="disabled" value="New Folder" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false" />&nbsp;
414 - <input type=button id="p13UploadButton" disabled="disabled" value="Upload" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false" />&nbsp;
415 - <input type=button id="p13RefreshButton" disabled="disabled" value="Refresh" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false" />&nbsp;
408 + <input type=button id=p13FolderUp disabled="disabled" onclick="p13folderup()" value="Up" />&nbsp;
409 + <input type=button id=p13SelectAllButton disabled="disabled" onclick="p13selectallfile()" value="Select All" onkeypress="return false" onkeydown="return false" />&nbsp;
410 + <input type=button id=p13RenameFileButton disabled="disabled" value="Rename" onclick="p13renamefile()" onkeypress="return false" onkeydown="return false" />&nbsp;
411 + <input type=button id=p13DeleteFileButton disabled="disabled" value="Delete" onclick="p13deletefile()" onkeypress="return false" onkeydown="return false" />&nbsp;
412 + <input type=button id=p13NewFolderButton disabled="disabled" value="New Folder" onclick="p13createfolder()" onkeypress="return false" onkeydown="return false" />&nbsp;
413 + <input type=button id=p13UploadButton disabled="disabled" value="Upload" onclick="p13uploadFile()" onkeypress="return false" onkeydown="return false" />&nbsp;
414 + <input type=button id=p13RefreshButton disabled="disabled" value="Refresh" onclick="p13folderup(9999)" onkeypress="return false" onkeydown="return false" />&nbsp;
415 </div>
416 </td>
417 </tr>
@@ -602,6 +601,7 @@
601 var showHostnames = false;
602 var meshserver = null;
603 var meshes = {};
604 + var meshcount = 0;
605 var nodes = [];
606 var filetree = {};
607 var userinfo = null;
@@ -1195,8 +1195,11 @@
1195 QV('devListToolbar', view < 3);
1196 QV('devMapToolbar', view == 3);
1197 QV('devListToolbarSort', view < 3);
1198 + QV('NoMeshesPanel', meshcount == 0);
1199 + QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
1200 + QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0));
1201 + if ((meshcount == 0) || (nodes.length == 0)) { view = 1; }
1202 if (view == 3) {
1199 - QV('NoNodesPanel',false); //Hide NoNodesPanel user views Map
1203 setTimeout( function() { if (xxmap.map != null) { xxmap.map.updateSize(); } }, 200);
1204 // TODO
1205 } else {
@@ -1300,9 +1303,12 @@
1303 }
1304 r += '</tr></table><div style=height:1px></div>'; // This height of 1 div fixes a problem in Linux firefox browsers
1305
1306 + // Add a "Add Mesh" option
1307 + if (view == 1) { r += '<div style=border-top-style:solid;border-top-width:1px;border-top-color:#DDDDDD;cursor:pointer;font-size:10px title="Create a new group of computers."><a onclick=account_createMesh() style=cursor:pointer>Add Mesh</a></div>'; }
1308 +
1309 QH('xdevices', r);
1310 deviceHeaderSet();
1305 - QV('NoNodesPanel', count == 0);
1311 + //QV('NoMeshesPanel', count == 0);
1312
1313 // Re-check nodeid's
1314 var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
@@ -1671,7 +1677,6 @@
1677 markersLayer: null,
1678 mapLayer: null, // Create a tile and use OSM source
1679 mapView: null, // Sets the initial view
1674 - selectedNodes: {} // Save details of Node that was selected from 'Put a node' option from contextmenu
1680 }
1681
1682 // Add a feature for every Node and change style if connection status changes
@@ -3642,6 +3647,7 @@
3647 }
3648 r += '</tr></table>';
3649
3650 + meshcount = count;
3651 QH('p2meshes', r);
3652 QV('p2noMeshFound', count == 0);
3653 }
webserver.js
+61 -45
@@ -138,7 +138,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
138 for (var i in docs) { var u = obj.users[docs[i]._id] = docs[i]; domainUserCount[u.domain]++; }
139 for (var i in parent.config.domains) {
140 if (domainUserCount[i] == 0) {
141 - if (parent.config.domains[i].newAccounts == 0) { parent.config.domains[i].newAccounts = 2; }
141 + if (parent.config.domains[i].newaccounts == 0) { parent.config.domains[i].newaccounts = 2; }
142 console.log('Server ' + ((i == '') ? '' : (i + ' ')) + 'has no users, next new account will be site administrator.');
143 }
144 }
@@ -178,22 +178,35 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
178 }
179 */
180
181 - // Check if the source IP address is allowed, return false if not
182 - function checkUserIpAddress(req, res) {
183 - if (obj.userAllowedIp == null) { return true; }
181 + // Check if the source IP address is allowed for a given allowed list, return false if not
182 + function checkUserIpAddressEx(req, res, allowedIpList) {
183 + if (allowedIpList == null) { return true; }
184 try {
185 - if (typeof obj.userAllowedIp == 'string') { if (obj.userAllowedIp == "") { obj.userAllowedIp = null; return true; } else { obj.userAllowedIp = obj.userAllowedIp.split(','); } }
185 var ip = null, type = 0;
186 if (req.connection) { ip = req.connection.remoteAddress; type = 1; } // HTTP(S) request
187 else if (req._socket) { ip = req._socket.remoteAddress; type = 2; } // WebSocket request
188 if (ip.startsWith('::ffff:')) { ip = ip.substring(7); } // Fix IPv4 IP's encoded in IPv6 form
190 - if ((ip != null) && (obj.userAllowedIp.indexOf(ip) >= 0)) { return true; }
189 + if ((ip != null) && (allowedIpList.indexOf(ip) >= 0)) { return true; }
190 if (type == 1) { res.sendStatus(401); }
191 else if (type == 2) { try { req.close(); } catch (e) { } }
192 } catch (e) { console.log(e); }
193 return false;
194 }
195
196 + // Check if the source IP address is allowed, return domain if allowed
197 + function checkUserIpAddress(req, res, rootonly) {
198 + if (obj.userAllowedIp != null) {
199 + if (typeof obj.userAllowedIp == 'string') { if (obj.userAllowedIp == "") { obj.userAllowedIp = null; return true; } else { obj.userAllowedIp = obj.userAllowedIp.split(','); } }
200 + if (checkUserIpAddressEx(req, res, obj.userAllowedIp) == false) return null;
201 + }
202 + if (rootonly == true) return;
203 + var domain;
204 + if (req.url) { domain = getDomain(req); } else { domain = getDomain(res); }
205 + if (domain.userallowedip == null) return domain;
206 + if (checkUserIpAddressEx(req, res, domain.userallowedip) == false) return null;
207 + return domain;
208 + }
209 +
210 // Return the current domain of the request
211 function getDomain(req) {
212 var x = req.url.split('/');
@@ -203,8 +216,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
216 }
217
218 function handleLogoutRequest(req, res) {
206 - if (checkUserIpAddress(req, res) == false) { return; }
207 - var domain = getDomain(req);
219 + var domain = checkUserIpAddress(req, res);
220 + if (domain == null) return;
221 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
222 // Destroy the user's session to log them out will be re-created next request
223 if (req.session.userid) {
@@ -217,8 +230,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
230 }
231
232 function handleLoginRequest(req, res) {
220 - if (checkUserIpAddress(req, res) == false) { return; }
221 - var domain = getDomain(req);
233 + var domain = checkUserIpAddress(req, res);
234 + if (domain == null) return;
235 obj.authenticate(req.body.username, req.body.password, domain, function (err, userid, passhint) {
236 if (userid) {
237 var user = obj.users[userid];
@@ -269,16 +282,16 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
282 }
283
284 function handleCreateAccountRequest(req, res) {
272 - if (checkUserIpAddress(req, res) == false) { return; }
273 - var domain = getDomain(req);
274 - if (domain.newAccounts == 0) { res.sendStatus(401); return; }
285 + var domain = checkUserIpAddress(req, res);
286 + if (domain == null) return;
287 + if (domain.newaccounts == 0) { res.sendStatus(401); return; }
288 if (!req.body.username || !req.body.email || !req.body.password1 || !req.body.password2 || (req.body.password1 != req.body.password2) || req.body.username == '~') {
289 req.session.loginmode = 2;
290 req.session.error = '<b style=color:#8C001A>Unable to create account.</b>';;
291 res.redirect(domain.url);
292 } else {
293 // Check if there is domain.newAccountToken, check if supplied token is valid
281 - if ((domain.newAccountsPass != null) && (domain.newAccountsPass != '') && (req.body.anewaccountpass != domain.newAccountsPass)) {
294 + if ((domain.newaccountspass != null) && (domain.newaccountspass != '') && (req.body.anewaccountpass != domain.newaccountspass)) {
295 req.session.loginmode = 2;
296 req.session.error = '<b style=color:#8C001A>Invalid account creation token.</b>';
297 res.redirect(domain.url);
@@ -294,7 +307,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
307 var user = { type: 'user', _id: 'user/' + domain.id + '/' + req.body.username.toLowerCase(), name: req.body.username, email: req.body.email, creation: Date.now(), login: Date.now(), domain: domain.id, passhint: hint };
308 var usercount = 0;
309 for (var i in obj.users) { if (obj.users[i].domain == domain.id) { usercount++; } }
297 - if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newAccounts == 2) { domain.newAccounts = 0; } } // If this is the first user, give the account site admin.
310 + if (usercount == 0) { user.siteadmin = 0xFFFFFFFF; if (domain.newaccounts == 2) { domain.newaccounts = 0; } } // If this is the first user, give the account site admin.
311 obj.users[user._id] = user;
312 req.session.userid = user._id;
313 req.session.domainid = domain.id;
@@ -312,8 +325,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
325 }
326
327 function handleDeleteAccountRequest(req, res) {
315 - if (checkUserIpAddress(req, res) == false) { return; }
316 - var domain = getDomain(req);
328 + var domain = checkUserIpAddress(req, res);
329 + if (domain == null) return;
330 // Check if the user is logged and we have all required parameters
331 if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) { res.redirect(domain.url); return; }
332 var user = obj.users[req.session.userid];
@@ -335,8 +348,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
348
349 // Handle password changes
350 function handlePasswordChangeRequest(req, res) {
338 - if (checkUserIpAddress(req, res) == false) { return; }
339 - var domain = getDomain(req);
351 + var domain = checkUserIpAddress(req, res);
352 + if (domain == null) return;
353 // Check if the user is logged and we have all required parameters
354 if (!req.session || !req.session.userid || !req.body.apassword1 || (req.body.apassword1 != req.body.apassword2) || (req.session.domainid != domain.id)) { res.redirect(domain.url); return; }
355
@@ -359,7 +372,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
372
373 // Indicates that any request to "/" should render "default" or "login" depending on login state
374 function handleRootRequest(req, res) {
362 - if (checkUserIpAddress(req, res) == false) { return; }
375 + var domain = checkUserIpAddress(req, res);
376 + if (domain == null) return;
377 if (!obj.args) { res.sendStatus(500); return; }
378 var domain = getDomain(req);
379 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
@@ -412,7 +426,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
426 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: obj.certificates.CommonName, serverPublicPort: args.port, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, mpspass: args.mpspass });
427 } else {
428 // Send back the login application
415 - res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newAccounts, newAccountPass: (((domain.newAccountsPass == null) || (domain.newAccountsPass == ''))?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
429 + res.render(obj.path.join(__dirname, 'views/login'), { loginmode: req.session.loginmode, rootCertLink: getRootCertLink(), title: domain.title, title2: domain.title2, newAccount: domain.newaccounts, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == ''))?0:1), serverDnsName: obj.certificates.CommonName, serverPublicPort: obj.args.port });
430 }
431 }
432
@@ -425,8 +439,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
439
440 // Renter the terms of service.
441 function handleTermsRequest(req, res) {
428 - if (checkUserIpAddress(req, res) == false) { return; }
429 - var domain = getDomain(req);
442 + var domain = checkUserIpAddress(req, res);
443 + if (domain == null) return;
444 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
445 if (req.session && req.session.userid) {
446 if (req.session.domainid != domain.id) { req.session.destroy(function () { res.redirect(domain.url); }); return; } // Check is the session is for the correct domain
@@ -449,14 +463,14 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
463
464 // Returns the mesh server root certificate
465 function handleRootCertRequest(req, res) {
452 - if (checkUserIpAddress(req, res) == false) { return; }
466 + if (checkUserIpAddress(req, res, true) == false) { return; }
467 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + certificates.RootName + '.cer' });
468 res.send(new Buffer(getRootCertBase64(), 'base64'));
469 }
470
471 // Returns an mescript for Intel AMT configuration
472 function handleMeScriptRequest(req, res) {
459 - if (checkUserIpAddress(req, res) == false) { return; }
473 + if (checkUserIpAddress(req, res, true) == false) { return; }
474 if (req.query.type == 1) {
475 var filename = 'cira_setup.mescript';
476 res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0', 'Content-Type': 'application/octet-stream', 'Content-Disposition': 'attachment; filename=' + filename });
@@ -527,8 +541,9 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
541
542 // Handle user public file downloads
543 function handleDownloadUserFiles(req, res) {
530 - if (checkUserIpAddress(req, res) == false) { return; }
531 - var domain = getDomain(req), domainname = 'domain', spliturl = decodeURIComponent(req.path).split('/'), filename = '';
544 + var domain = checkUserIpAddress(req, res);
545 + if (domain == null) return;
546 + var domainname = 'domain', spliturl = decodeURIComponent(req.path).split('/'), filename = '';
547 if ((spliturl.length < 3) || (obj.common.IsFilenameValid(spliturl[2]) == false) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
548 if (domain.id != '') { domainname = 'domain-' + domain.id; }
549 var path = obj.path.join(obj.filespath, domainname + "/user-" + spliturl[2] + "/Public");
@@ -550,8 +565,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
565
566 // Download a file from the server
567 function handleDownloadFile(req, res) {
553 - if (checkUserIpAddress(req, res) == false) { return; }
554 - var domain = getDomain(req);
568 + var domain = checkUserIpAddress(req, res);
569 + if (domain == null) return;
570 if ((req.query.link == null) || (req.session == null) || (req.session.userid == null) || (domain == null) || (domain.userQuota == -1)) { res.sendStatus(404); return; }
571 var user = obj.users[req.session.userid];
572 if (user == null) { res.sendStatus(404); return; }
@@ -563,8 +578,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
578
579 // Upload a MeshCore.js file to the server
580 function handleUploadMeshCoreFile(req, res) {
566 - if (checkUserIpAddress(req, res) == false) { return; }
567 - var domain = getDomain(req);
581 + var domain = checkUserIpAddress(req, res);
582 + if (domain == null) return;
583 if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
584 var user = obj.users[req.session.userid];
585 if (user.siteadmin != 0xFFFFFFFF) { res.sendStatus(401); return; } // Check if we have mesh core upload rights (Full admin only)
@@ -588,8 +603,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
603
604 // Upload a file to the server
605 function handleUploadFile(req, res) {
591 - if (checkUserIpAddress(req, res) == false) { return; }
592 - var domain = getDomain(req);
606 + var domain = checkUserIpAddress(req, res);
607 + if (domain == null) return;
608 if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid) || (domain.userQuota == -1)) { res.sendStatus(401); return; }
609 var user = obj.users[req.session.userid];
610 if ((user.siteadmin & 8) == 0) { res.sendStatus(401); return; } // Check if we have file rights
@@ -650,8 +665,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
665
666 // Handle a web socket relay request
667 function handleRelayWebSocket(ws, req) {
653 - if (checkUserIpAddress(ws, req) == false) { return; }
654 - var node, domain = getDomain(req);
668 + var domain = checkUserIpAddress(ws, req);
669 + if (domain == null) return;
670 // Check if this is a logged in user
671 var user, peering = true;
672 if (req.query.auth == null) {
@@ -677,7 +692,7 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
692 // Fetch information about the target
693 obj.db.Get(req.query.host, function (err, docs) {
694 if (docs.length == 0) { console.log('ERR: Node not found'); return; }
680 - node = docs[0];
695 + var node = docs[0];
696 if (!node.intelamt) { console.log('ERR: Not AMT node'); return; }
697
698 // Check if this user has permission to manage this computer
@@ -915,7 +930,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
930
931 // Handle the web socket echo request, just echo back the data sent
932 function handleEchoWebSocket(ws, req) {
918 - if (checkUserIpAddress(ws, req) == false) { return; }
933 + var domain = checkUserIpAddress(ws, req);
934 + if (domain == null) return;
935
936 // When data is received from the web socket, echo it back
937 ws.on('message', function (data) {
@@ -968,8 +984,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
984
985 // Indicates we want to handle websocket requests on "/control.ashx".
986 function handleControlRequest(ws, req) {
971 - if (checkUserIpAddress(ws, req) == false) { return; }
972 - var domain = getDomain(req);
987 + var domain = checkUserIpAddress(ws, req);
988 + if (domain == null) return;
989 try {
990 // Check if the user is logged in
991 if ((!req.session) || (!req.session.userid) || (req.session.domainid != domain.id)) { try { ws.close(); } catch (e) { } return; }
@@ -1840,8 +1856,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1856
1857 // Handle a server backup request
1858 function handleBackupRequest(req, res) {
1843 - if (checkUserIpAddress(req, res) == false) { return; }
1844 - var domain = getDomain(req);
1859 + var domain = checkUserIpAddress(req, res);
1860 + if (domain == null) return;
1861 if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid) || (obj.parent.args.noserverbackup == 1)) { res.sendStatus(401); return; }
1862 var user = obj.users[req.session.userid];
1863 if ((user.siteadmin & 1) == 0) { res.sendStatus(401); return; } // Check if we have server backup rights
@@ -1873,8 +1889,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1889
1890 // Handle a server restore request
1891 function handleRestoreRequest(req, res) {
1876 - if (checkUserIpAddress(req, res) == false) { return; }
1877 - var domain = getDomain(req);
1892 + var domain = checkUserIpAddress(req, res);
1893 + if (domain == null) return;
1894 if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid) || (obj.parent.args.noserverbackup == 1)) { res.sendStatus(401); return; }
1895 var user = obj.users[req.session.userid];
1896 if ((user.siteadmin & 4) == 0) { res.sendStatus(401); return; } // Check if we have server restore rights
@@ -1918,8 +1934,8 @@ module.exports.CreateWebServer = function (parent, db, args, secret, certificate
1934
1935 // Handle a request to download a mesh settings
1936 obj.handleMeshSettingsRequest = function (req, res) {
1921 - if (checkUserIpAddress(req, res) == false) { return; }
1922 - var domain = getDomain(req);
1937 + var domain = checkUserIpAddress(req, res);
1938 + if (domain == null) return;
1939 //if ((domain.id !== '') || (!req.session) || (req.session == null) || (!req.session.userid)) { res.sendStatus(401); return; }
1940
1941 // Delete a mesh and all computers within it