Added support for per-domain web folder.
Ylian Saint-Hilaire committed
Mar 25, 2020 at 13:21 UTC
5a418b615b8198f61ea24110e7fb524a70d2c003
3 files changed
+96
-42
meshcentral.js
+11
-2
@@ -178,7 +178,7 @@ function CreateMeshCentralServer(config, args) {
178
didSomething = true;
179
}
180
181
- // Check is "meshcentral-web" exists, if so, translate all pages in that folder.
181
+ // Check if "meshcentral-web" exists, if so, translate all pages in that folder.
182
if (obj.webViewsOverridePath != null) {
183
didSomething = true;
184
var files = obj.fs.readdirSync(obj.webViewsOverridePath);
@@ -972,6 +972,15 @@ function CreateMeshCentralServer(config, args) {
972
obj.config.domains[i].newaccountsrights = newAccRights;
973
}
974
if (obj.config.domains[i].newaccountsrights && (typeof (obj.config.domains[i].newaccountsrights) != 'number')) { delete obj.config.domains[i].newaccountsrights; }
975
+
976
+ // Check if there is a web views path and/or web public path for this domain
977
+ if ((__dirname.endsWith('/node_modules/meshcentral')) || (__dirname.endsWith('\\node_modules\\meshcentral')) || (__dirname.endsWith('/node_modules/meshcentral/')) || (__dirname.endsWith('\\node_modules\\meshcentral\\'))) {
978
+ if ((obj.config.domains[i].webviewspath == null) && (obj.fs.existsSync(obj.path.join(__dirname, '../../meshcentral-web-' + i + '/views')))) { obj.config.domains[i].webviewspath = obj.path.join(__dirname, '../../meshcentral-web-' + i + '/views'); }
979
+ if ((obj.config.domains[i].webpublicpath == null) && (obj.fs.existsSync(obj.path.join(__dirname, '../../meshcentral-web-' + i + '/public')))) { obj.config.domains[i].webpublicpath = obj.path.join(__dirname, '../../meshcentral-web-' + i + '/public'); }
980
+ } else {
981
+ if ((obj.config.domains[i].webviewspath == null) && (obj.fs.existsSync(obj.path.join(__dirname, '../meshcentral-web-' + i + '/views')))) { obj.config.domains[i].webviewspath = obj.path.join(__dirname, '../meshcentral-web-' + i + '/views'); }
982
+ if ((obj.config.domains[i].webpublicpath == null) && (obj.fs.existsSync(obj.path.join(__dirname, '../meshcentral-web-' + i + '/public')))) { obj.config.domains[i].webpublicpath = obj.path.join(__dirname, '../meshcentral-web-' + i + '/public'); }
983
+ }
984
}
985
986
// Log passed arguments into Windows Service Log
@@ -2395,7 +2404,7 @@ function mainStart() {
2404
// Lowercase the auth value if present
2405
for (var i in config.domains) { if (typeof config.domains[i].auth == 'string') { config.domains[i].auth = config.domains[i].auth.toLowerCase(); } }
2406
2398
- // Check is Windows SSPI and YubiKey OTP will be used
2407
+ // Check if Windows SSPI and YubiKey OTP will be used
2408
var sspi = false;
2409
var ldap = false;
2410
var allsspi = true;
meshuser.js
+9
-3
@@ -2415,6 +2415,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
2415
break;
2416
}
2417
2418
+ // Convert user names to userid's
2419
+ if (command.userids == null) {
2420
+ command.userids = [];
2421
+ for (var i in command.usernames) { command.userids.push('user/' + domain.id + '/' + command.usernames[i].toLowerCase()); }
2422
+ }
2423
+
2424
// TODO
2425
//console.log(command);
2426
@@ -3192,7 +3198,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3198
}
3199
case 'otp-hkey-remove':
3200
{
3195
- // Check is 2-step login is supported
3201
+ // Check if 2-step login is supported
3202
const twoStepLoginSupported = ((parent.parent.config.settings.no2factorauth !== true) && (domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.nousers !== true));
3203
if (twoStepLoginSupported == false || command.index == null) break;
3204
@@ -3218,7 +3224,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3224
var yubikeyotp = null;
3225
try { yubikeyotp = require('yubikeyotp'); } catch (ex) { }
3226
3221
- // Check is 2-step login is supported
3227
+ // Check if 2-step login is supported
3228
const twoStepLoginSupported = ((parent.parent.config.settings.no2factorauth !== true) && (domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.nousers !== true));
3229
if ((yubikeyotp == null) || (twoStepLoginSupported == false) || (typeof command.otp != 'string')) {
3230
ws.send(JSON.stringify({ action: 'otp-hkey-yubikey-add', result: false, name: command.name }));
@@ -3267,7 +3273,7 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
3273
}
3274
case 'webauthn-startregister':
3275
{
3270
- // Check is 2-step login is supported
3276
+ // Check if 2-step login is supported
3277
const twoStepLoginSupported = ((parent.parent.config.settings.no2factorauth !== true) && (domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.nousers !== true));
3278
if ((twoStepLoginSupported == false) || (command.name == null)) break;
3279
webserver.js
+76
-37
@@ -1173,28 +1173,28 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1173
var idsplit = cookie.u.split('/');
1174
if ((idsplit.length != 2) || (idsplit[0] != domain.id)) {
1175
parent.debug('web', 'handleCheckMailRequest: Invalid domain.');
1176
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid domain. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1176
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid domain. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1177
} else {
1178
obj.db.Get('user/' + cookie.u.toLowerCase(), function (err, docs) {
1179
if (docs.length == 0) {
1180
parent.debug('web', 'handleCheckMailRequest: Invalid username.');
1181
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid username \"' + EscapeHtml(idsplit[1]) + '\". <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1181
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid username \"' + EscapeHtml(idsplit[1]) + '\". <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1182
} else {
1183
var user = docs[0];
1184
if (user.email != cookie.e) {
1185
parent.debug('web', 'handleCheckMailRequest: Invalid e-mail.');
1186
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid e-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1186
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid e-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\". <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1187
} else {
1188
if (cookie.a == 1) {
1189
// Account email verification
1190
if (user.emailVerified == true) {
1191
parent.debug('web', 'handleCheckMailRequest: email already verified.');
1192
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" already verified. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1192
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" already verified. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1193
} else {
1194
obj.db.GetUserWithVerifiedEmail(domain.id, user.email, function (err, docs) {
1195
if (docs.length > 0) {
1196
parent.debug('web', 'handleCheckMailRequest: email already in use.');
1197
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" already in use on a different account. Change the email address and try again. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1197
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" already in use on a different account. Change the email address and try again. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1198
} else {
1199
parent.debug('web', 'handleCheckMailRequest: email verification success.');
1200
@@ -1209,7 +1209,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1209
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
1210
1211
// Send the confirmation page
1212
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1212
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'Verified email <b>' + EscapeHtml(user.email) + '</b> for user account <b>' + EscapeHtml(user.name) + '</b>. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1213
1214
// Send a notification
1215
obj.parent.DispatchEvent([user._id], obj, { action: 'notify', value: 'Email verified:<br /><b>' + EscapeHtml(user.email) + '</b>.', nolog: 1, id: Math.random() });
@@ -1220,7 +1220,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1220
// Account reset
1221
if (user.emailVerified != true) {
1222
parent.debug('web', 'handleCheckMailRequest: email not verified.');
1223
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" not verified. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1223
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'E-mail \"' + EscapeHtml(user.email) + '\" for user \"' + EscapeHtml(user.name) + '\" not verified. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1224
} else {
1225
// Set a temporary password
1226
obj.crypto.randomBytes(16, function (err, buf) {
@@ -1245,20 +1245,20 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1245
obj.parent.DispatchEvent(['*', 'server-users', user._id], obj, event);
1246
1247
// Send the new password
1248
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: '<div>Password for account <b>' + EscapeHtml(user.name) + '</b> has been reset to:</div><div style=padding:14px;font-size:18px><b>' + EscapeHtml(newpass) + '</b></div>Login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1248
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: '<div>Password for account <b>' + EscapeHtml(user.name) + '</b> has been reset to:</div><div style=padding:14px;font-size:18px><b>' + EscapeHtml(newpass) + '</b></div>Login and go to the \"My Account\" tab to update your password. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1249
parent.debug('web', 'handleCheckMailRequest: send temporary password.');
1250
}, 0);
1251
});
1252
}
1253
} else {
1254
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid account check. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1254
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid account check. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1255
}
1256
}
1257
}
1258
});
1259
}
1260
} else {
1261
- render(req, res, getRenderPage('message', req), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid account check, verification url is only valid for 30 minutes. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1261
+ render(req, res, getRenderPage('message', req, domain), getRenderArgs({ title3: 'Account Verification', message: 'ERROR: Invalid account check, verification url is only valid for 30 minutes. <a href="' + domain.url + '">Go to login page</a>.' }, domain));
1262
}
1263
}
1264
}
@@ -1268,7 +1268,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1268
const domain = getDomain(req);
1269
if (domain == null) { parent.debug('web', 'handleInviteRequest: failed checks.'); res.sendStatus(404); return; }
1270
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
1271
- if ((req.body.inviteCode == null) || (req.body.inviteCode == '')) { render(req, res, getRenderPage('invite', req), getRenderArgs({ messageid: 0 }, domain)); return; } // No invitation code
1271
+ if ((req.body.inviteCode == null) || (req.body.inviteCode == '')) { render(req, res, getRenderPage('invite', req, domain), getRenderArgs({ messageid: 0 }, domain)); return; } // No invitation code
1272
1273
// Each for a device group that has this invite code.
1274
for (var i in obj.meshes) {
@@ -1279,7 +1279,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1279
}
1280
}
1281
1282
- render(req, res, getRenderPage('invite', req), getRenderArgs({ messageid: 100 }, domain)); // Bad invitation code
1282
+ render(req, res, getRenderPage('invite', req, domain), getRenderArgs({ messageid: 100 }, domain)); // Bad invitation code
1283
}
1284
1285
// Called to process an agent invite request
@@ -1297,7 +1297,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1297
var installflags = cookie.f;
1298
if (typeof installflags != 'number') { installflags = 0; }
1299
parent.debug('web', 'handleAgentInviteRequest using cookie.');
1300
- render(req, res, getRenderPage('agentinvite', req), getRenderArgs({ meshid: mesh._id.split('/')[2], serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name), installflags: installflags }, domain));
1300
+ render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: mesh._id.split('/')[2], serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name), installflags: installflags }, domain));
1301
} else if (req.query.m != null) {
1302
// The MeshId is specified in the query string, use that
1303
var mesh = obj.meshes['mesh/' + domain.id + '/' + req.query.m.toLowerCase()];
@@ -1306,7 +1306,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1306
if (req.query.f) { installflags = parseInt(req.query.f); }
1307
if (typeof installflags != 'number') { installflags = 0; }
1308
parent.debug('web', 'handleAgentInviteRequest using meshid.');
1309
- render(req, res, getRenderPage('agentinvite', req), getRenderArgs({ meshid: mesh._id.split('/')[2], serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name), installflags: installflags }, domain));
1309
+ render(req, res, getRenderPage('agentinvite', req, domain), getRenderArgs({ meshid: mesh._id.split('/')[2], serverport: ((args.aliasport != null) ? args.aliasport : args.port), serverhttps: ((args.notls == true) ? '0' : '1'), servernoproxy: ((domain.agentnoproxy === true) ? '1' : '0'), meshname: encodeURIComponent(mesh.name), installflags: installflags }, domain));
1310
}
1311
}
1312
@@ -1573,7 +1573,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1573
// If a user exists and is logged in, serve the default app, otherwise server the login app.
1574
if (req.session && req.session.userid && obj.users[req.session.userid]) {
1575
var user = obj.users[req.session.userid];
1576
- if (req.session.domainid != domain.id) { // Check is the session is for the correct domain
1576
+ if (req.session.domainid != domain.id) { // Check if the session is for the correct domain
1577
parent.debug('web', 'handleRootRequestEx: incorrect domain.');
1578
req.session = null;
1579
res.redirect(domain.url + getQueryPortion(req)); // BAD***
@@ -1674,7 +1674,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1674
for (var i in domain.forceduserwebstate) { webstate2[i] = domain.forceduserwebstate[i]; }
1675
webstate = JSON.stringify(webstate2);
1676
}
1677
- render(req, res, getRenderPage('default', req), getRenderArgs({ authCookie: authCookie, authRelayCookie: authRelayCookie, viewmode: viewmode, currentNode: currentNode, logoutControls: JSON.stringify(logoutcontrols), domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate), pluginHandler: (parent.pluginHandler == null) ? 'null' : parent.pluginHandler.prepExports(), StartGeoLocation: StartGeoLocation, EndGeoLocation: EndGeoLocation, StartGeoLocationJS: StartGeoLocationJS, EndGeoLocationJS: EndGeoLocationJS }, domain));
1677
+ render(req, res, getRenderPage('default', req, domain), getRenderArgs({ authCookie: authCookie, authRelayCookie: authRelayCookie, viewmode: viewmode, currentNode: currentNode, logoutControls: JSON.stringify(logoutcontrols), domain: domain.id, debuglevel: parent.debugLevel, serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, noServerBackup: (args.noserverbackup == 1 ? 1 : 0), features: features, sessiontime: args.sessiontime, mpspass: args.mpspass, passRequirements: passRequirements, webcerthash: Buffer.from(obj.webCertificateFullHashs[domain.id], 'binary').toString('base64').replace(/\+/g, '@').replace(/\//g, '$'), footer: (domain.footer == null) ? '' : domain.footer, webstate: encodeURIComponent(webstate), pluginHandler: (parent.pluginHandler == null) ? 'null' : parent.pluginHandler.prepExports(), StartGeoLocation: StartGeoLocation, EndGeoLocation: EndGeoLocation, StartGeoLocationJS: StartGeoLocationJS, EndGeoLocationJS: EndGeoLocationJS }, domain));
1678
});
1679
} else {
1680
// Send back the login application
@@ -1745,7 +1745,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1745
if ((typeof domain.passwordrequirements == 'object') && (domain.passwordrequirements.email2factor == false)) { otpemail = false; }
1746
1747
// Render the login page
1748
- render(req, res, getRenderPage('login', req), getRenderArgs({ loginmode: loginmode, rootCertLink: getRootCertLink(), newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail }, domain));
1748
+ render(req, res, getRenderPage('login', req, domain), getRenderArgs({ loginmode: loginmode, rootCertLink: getRootCertLink(), newAccount: newAccountsAllowed, newAccountPass: (((domain.newaccountspass == null) || (domain.newaccountspass == '')) ? 0 : 1), serverDnsName: obj.getWebServerName(domain), serverPublicPort: httpsPort, emailcheck: emailcheck, features: features, sessiontime: args.sessiontime, passRequirements: passRequirements, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail }, domain));
1749
}
1750
1751
// Handle a post request on the root
@@ -1817,7 +1817,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1817
const authCookie = obj.parent.encodeCookie({ userid: user._id, domainid: domain.id, ip: cleanRemoteAddr(req.ip) }, obj.parent.loginCookieEncryptionKey);
1818
const authRelayCookie = obj.parent.encodeCookie({ ruserid: user._id, domainid: domain.id }, obj.parent.loginCookieEncryptionKey);
1819
var httpsPort = ((obj.args.aliasport == null) ? obj.args.port : obj.args.aliasport); // Use HTTPS alias port is specified
1820
- render(req, res, getRenderPage('xterm', req), getRenderArgs({ serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, authCookie: authCookie, authRelayCookie: authRelayCookie, logoutControls: JSON.stringify(logoutcontrols), name: EscapeHtml(node.name) }, domain));
1820
+ render(req, res, getRenderPage('xterm', req, domain), getRenderArgs({ serverDnsName: obj.getWebServerName(domain), serverRedirPort: args.redirport, serverPublicPort: httpsPort, authCookie: authCookie, authRelayCookie: authRelayCookie, logoutControls: JSON.stringify(logoutcontrols), name: EscapeHtml(node.name) }, domain));
1821
});
1822
} else {
1823
res.redirect(domain.url + getQueryPortion(req));
@@ -1836,14 +1836,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1836
// Send the terms from the database
1837
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
1838
if (req.session && req.session.userid) {
1839
- if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
1839
+ if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
1840
var user = obj.users[req.session.userid];
1841
var logoutcontrols = { name: user.name };
1842
var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
1843
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrols.logoutUrl = (domain.url + 'logout?' + Math.random() + extras); } // If a default user is in use or no user mode, don't display the logout button
1844
- render(req, res, getRenderPage('terms', req), getRenderArgs({ terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()).split('\'').join('\\\''), logoutControls: JSON.stringify(logoutcontrols) }, domain));
1844
+ render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()).split('\'').join('\\\''), logoutControls: JSON.stringify(logoutcontrols) }, domain));
1845
} else {
1846
- render(req, res, getRenderPage('terms', req), getRenderArgs({ terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()).split('\'').join('\\\''), logoutControls: '{}' }, domain));
1846
+ render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ terms: encodeURIComponent(parent.configurationFiles['terms.txt'].toString()).split('\'').join('\\\''), logoutControls: '{}' }, domain));
1847
}
1848
} else {
1849
// See if there is a terms.txt file in meshcentral-data
@@ -1855,14 +1855,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1855
// Send the terms from terms.txt
1856
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
1857
if (req.session && req.session.userid) {
1858
- if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
1858
+ if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
1859
var user = obj.users[req.session.userid];
1860
var logoutcontrols = { name: user.name };
1861
var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
1862
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrols.logoutUrl = (domain.url + 'logout?' + Math.random() + extras); } // If a default user is in use or no user mode, don't display the logout button
1863
- render(req, res, getRenderPage('terms', req), getRenderArgs({ terms: encodeURIComponent(data).split('\'').join('\\\''), logoutControls: JSON.stringify(logoutcontrols) }, domain));
1863
+ render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ terms: encodeURIComponent(data).split('\'').join('\\\''), logoutControls: JSON.stringify(logoutcontrols) }, domain));
1864
} else {
1865
- render(req, res, getRenderPage('terms', req), getRenderArgs({ terms: encodeURIComponent(data).split('\'').join('\\\''), logoutControls: '{}' }, domain));
1865
+ render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ terms: encodeURIComponent(data).split('\'').join('\\\''), logoutControls: '{}' }, domain));
1866
}
1867
});
1868
} else {
@@ -1870,14 +1870,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1870
parent.debug('web', 'handleTermsRequest: sending default terms');
1871
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
1872
if (req.session && req.session.userid) {
1873
- if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check is the session is for the correct domain
1873
+ if (req.session.domainid != domain.id) { req.session = null; res.redirect(domain.url + getQueryPortion(req)); return; } // Check if the session is for the correct domain
1874
var user = obj.users[req.session.userid];
1875
var logoutcontrols = { name: user.name };
1876
var extras = (req.query.key != null) ? ('&key=' + req.query.key) : '';
1877
if ((domain.ldap == null) && (domain.sspi == null) && (obj.args.user == null) && (obj.args.nousers != true)) { logoutcontrols.logoutUrl = (domain.url + 'logout?' + Math.random() + extras); } // If a default user is in use or no user mode, don't display the logout button
1878
- render(req, res, getRenderPage('terms', req), getRenderArgs({ logoutControls: JSON.stringify(logoutcontrols) }, domain));
1878
+ render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ logoutControls: JSON.stringify(logoutcontrols) }, domain));
1879
} else {
1880
- render(req, res, getRenderPage('terms', req), getRenderArgs({ logoutControls: '{}' }, domain));
1880
+ render(req, res, getRenderPage('terms', req, domain), getRenderArgs({ logoutControls: '{}' }, domain));
1881
}
1882
}
1883
}
@@ -1892,7 +1892,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
1892
var webRtcConfig = null;
1893
if (obj.parent.config.settings && obj.parent.config.settings.webrtconfig && (typeof obj.parent.config.settings.webrtconfig == 'object')) { webRtcConfig = encodeURIComponent(JSON.stringify(obj.parent.config.settings.webrtconfig)); }
1894
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
1895
- render(req, res, getRenderPage('messenger', req), getRenderArgs({ webrtconfig: webRtcConfig }, domain));
1895
+ render(req, res, getRenderPage('messenger', req, domain), getRenderArgs({ webrtconfig: webRtcConfig }, domain));
1896
}
1897
1898
// Returns the server root certificate encoded in base64
@@ -2053,10 +2053,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2053
}
2054
try { res.sendFile(obj.path.resolve(__dirname, path)); } catch (e) { res.sendStatus(404); }
2055
} else {
2056
- render(req, res, getRenderPage('download', req), getRenderArgs({ rootCertLink: getRootCertLink(), message: "<a href='" + req.path + "?download=1'>" + filename + "</a>, " + stat.size + " byte" + ((stat.size < 2) ? '' : 's') + "." }, domain));
2056
+ render(req, res, getRenderPage('download', req, domain), getRenderArgs({ rootCertLink: getRootCertLink(), message: "<a href='" + req.path + "?download=1'>" + filename + "</a>, " + stat.size + " byte" + ((stat.size < 2) ? '' : 's') + "." }, domain));
2057
}
2058
} else {
2059
- render(req, res, getRenderPage('download', req), getRenderArgs({ rootCertLink: getRootCertLink(), message: "Invalid file link, please check the URL again." }, domain));
2059
+ render(req, res, getRenderPage('download', req, domain), getRenderArgs({ rootCertLink: getRootCertLink(), message: "Invalid file link, please check the URL again." }, domain));
2060
}
2061
}
2062
@@ -2077,7 +2077,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2077
}
2078
}
2079
2080
- if (parent.webPublicOverridePath && obj.fs.existsSync(obj.path.join(obj.parent.webPublicOverridePath, 'images/logoback.png'))) {
2080
+ if ((domain != null) && (domain.webpublicpath != null) && (obj.fs.existsSync(obj.path.join(domain.webpublicpath, 'images/logoback.png')))) {
2081
+ // Use the domain logo picture
2082
+ try { res.sendFile(obj.path.join(domain.webpublicpath, 'images/logoback.png')); } catch (ex) { res.sendStatus(404); }
2083
+ } else if (parent.webPublicOverridePath && obj.fs.existsSync(obj.path.join(obj.parent.webPublicOverridePath, 'images/logoback.png'))) {
2084
// Use the override logo picture
2085
try { res.sendFile(obj.path.join(obj.parent.webPublicOverridePath, 'images/logoback.png')); } catch (ex) { res.sendStatus(404); }
2086
} else {
@@ -2166,7 +2169,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2169
try { res.sendFile(obj.path.join(obj.parent.datapath, domain.welcomepicture)); return; } catch (ex) { }
2170
}
2171
2169
- if (parent.webPublicOverridePath) {
2172
+ if ((domain != null) && (domain.webpublicpath != null)) {
2173
+ obj.fs.exists(obj.path.join(domain.webpublicpath, 'images/mainwelcome.jpg'), function (exists) {
2174
+ if (exists) {
2175
+ // Use the domain logo picture
2176
+ try { res.sendFile(obj.path.join(domain.webpublicpath, 'images/mainwelcome.jpg')); } catch (ex) { res.sendStatus(404); }
2177
+ } else {
2178
+ // Use the default logo picture
2179
+ try { res.sendFile(obj.path.join(obj.parent.webPublicPath, 'images/mainwelcome.jpg')); } catch (ex) { res.sendStatus(404); }
2180
+ }
2181
+ });
2182
+ } else if (parent.webPublicOverridePath) {
2183
obj.fs.exists(obj.path.join(obj.parent.webPublicOverridePath, 'images/mainwelcome.jpg'), function (exists) {
2184
if (exists) {
2185
// Use the override logo picture
@@ -2189,7 +2202,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
2202
2203
parent.debug('web', 'handlePlayerRequest: sending player');
2204
res.set({ 'Cache-Control': 'no-cache, no-store, must-revalidate', 'Pragma': 'no-cache', 'Expires': '0' });
2192
- render(req, res, getRenderPage('player', req), getRenderArgs({}, domain));
2205
+ render(req, res, getRenderPage('player', req, domain), getRenderArgs({}, domain));
2206
}
2207
2208
// Handle domain redirection
@@ -3663,7 +3676,11 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3676
// Use the data folder server picture
3677
try { res.sendFile(p); } catch (ex) { res.sendStatus(404); }
3678
} else {
3666
- if (parent.webPublicOverridePath && obj.fs.existsSync(obj.path.join(obj.parent.webPublicOverridePath, 'images/server-256.png'))) {
3679
+ var domain = getDomain(req);
3680
+ if ((domain != null) && (domain.webpublicpath != null) && (obj.fs.existsSync(obj.path.join(domain.webpublicpath, 'images/server-256.png')))) {
3681
+ // Use the domain server picture
3682
+ try { res.sendFile(obj.path.join(domain.webpublicpath, 'images/server-256.png')); } catch (ex) { res.sendStatus(404); }
3683
+ } else if (parent.webPublicOverridePath && obj.fs.existsSync(obj.path.join(obj.parent.webPublicOverridePath, 'images/server-256.png'))) {
3684
// Use the override server picture
3685
try { res.sendFile(obj.path.join(obj.parent.webPublicOverridePath, 'images/server-256.png')); } catch (ex) { res.sendStatus(404); }
3686
} else {
@@ -3732,7 +3749,13 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3749
//obj.app.get(url + 'stop', function (req, res) { res.send('Stopping Server, <a href="' + url + '">click here to login</a>.'); setTimeout(function () { parent.Stop(); }, 500); });
3750
3751
// Indicates to ExpressJS that the override public folder should be used to serve static files.
3735
- if (obj.parent.webPublicOverridePath != null) { obj.app.use(url, obj.express.static(obj.parent.webPublicOverridePath)); }
3752
+ if (parent.config.domains[i].webpublicpath != null) {
3753
+ // Use domain public path
3754
+ obj.app.use(url, obj.express.static(parent.config.domains[i].webpublicpath));
3755
+ } else if (obj.parent.webPublicOverridePath != null) {
3756
+ // Use override path
3757
+ obj.app.use(url, obj.express.static(obj.parent.webPublicOverridePath));
3758
+ }
3759
3760
// Indicates to ExpressJS that the default public folder should be used to serve static files.
3761
obj.app.use(url, obj.express.static(obj.parent.webPublicPath));
@@ -3748,7 +3771,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
3771
var domain = getDomain(req);
3772
if ((domain == null) || (domain.auth == 'sspi')) { res.sendStatus(404); return; }
3773
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key
3751
- res.status(404).render(getRenderPage('error404', req), getRenderArgs({}, domain));
3774
+ res.status(404).render(getRenderPage('error404', req, domain), getRenderArgs({}, domain));
3775
});
3776
}
3777
@@ -4384,9 +4407,17 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4407
}
4408
4409
// Return the correct render page given mobile, minify and override path.
4387
- function getRenderPage(pagename, req) {
4410
+ function getRenderPage(pagename, req, domain) {
4411
var mobile = isMobileBrowser(req), minify = obj.args.minify && !req.query.nominify, p;
4412
if (mobile) {
4413
+ if ((domain != null) && (domain.webviewspath != null)) { // If the domain has a web views path, use that first
4414
+ if (minify) {
4415
+ p = obj.path.join(domain.webviewspath, pagename + '-mobile-min');
4416
+ if (obj.fs.existsSync(p + '.handlebars')) { return p; } // Mobile + Minify + Override document
4417
+ }
4418
+ p = obj.path.join(domain.webviewspath, pagename + '-mobile');
4419
+ if (obj.fs.existsSync(p + '.handlebars')) { return p; } // Mobile + Override document
4420
+ }
4421
if (obj.parent.webViewsOverridePath != null) {
4422
if (minify) {
4423
p = obj.path.join(obj.parent.webViewsOverridePath, pagename + '-mobile-min');
@@ -4402,6 +4433,14 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
4433
p = obj.path.join(obj.parent.webViewsPath, pagename + '-mobile');
4434
if (obj.fs.existsSync(p + '.handlebars')) { return p; } // Mobile document
4435
}
4436
+ if ((domain != null) && (domain.webviewspath != null)) { // If the domain has a web views path, use that first
4437
+ if (minify) {
4438
+ p = obj.path.join(domain.webviewspath, pagename + '-min');
4439
+ if (obj.fs.existsSync(p + '.handlebars')) { return p; } // Minify + Override document
4440
+ }
4441
+ p = obj.path.join(domain.webviewspath, pagename);
4442
+ if (obj.fs.existsSync(p + '.handlebars')) { return p; } // Override document
4443
+ }
4444
if (obj.parent.webViewsOverridePath != null) {
4445
if (minify) {
4446
p = obj.path.join(obj.parent.webViewsOverridePath, pagename + '-min');