mirror of
https://github.com/Ylianst/MeshCentral.git
synced 2024-09-11 08:55:32 +03:00
Improved login page customization, improved Chinese.
This commit is contained in:
parent
df4c302470
commit
64efc47129
@ -15,7 +15,7 @@
|
||||
<p>服务器上的使用者[[[USERNAME]]] <a href="[[[SERVERURL]]]">[[[SERVERNAME]]]</a> 正在要求您安装软件以启动远程控制会话。</p>
|
||||
<area-msg>
|
||||
<p>
|
||||
讯息: <b notrans="1">[[[MSG]]]</b>
|
||||
消息: <b notrans="1">[[[MSG]]]</b>
|
||||
</p>
|
||||
</area-msg>
|
||||
<area-windows>
|
||||
@ -34,7 +34,7 @@
|
||||
</area-linux>
|
||||
<area-link>
|
||||
<p>
|
||||
要安裝軟體, <a href="[[[SERVERURL]]][[[LINKURL]]]">点击这里</a> 并按照说明进行操作。
|
||||
要安装软件, <a href="[[[SERVERURL]]][[[LINKURL]]]">点击这里</a> 并按照说明进行操作。
|
||||
</p>
|
||||
</area-link>
|
||||
<p>如果您没有发起此请求,请不理此邮件。</p>
|
||||
|
@ -5,7 +5,7 @@
|
||||
服务器[[[SERVERNAME]]]([[[SERVERURL]]]/)上的用户[[[USERNAME]]]请求您安装软件以启动远程控制。
|
||||
~<area-msg>
|
||||
~
|
||||
讯息:[[[MSG]]]
|
||||
消息:[[[MSG]]]
|
||||
~
|
||||
~</area-msg>
|
||||
~<area-windows>
|
||||
|
@ -141,10 +141,11 @@
|
||||
"items": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"siteStyle": { "type": "integer", "default": 1, "description": "Valid numbers are 1 and 2, changes the style of the login page and some secondary pages." }
|
||||
"title": { "type": "string" },
|
||||
"title2": { "type": "string" },
|
||||
"titlePicture": { "type": "string" },
|
||||
"siteStyle": { "type": "integer", "default": 1, "description": "Valid numbers are 1 and 2, changes the style of the login page and some secondary pages." },
|
||||
"title": { "type": "string", "default": "MeshCentral", "description": "The title of this web site. All web pages will have this title." },
|
||||
"title2": { "type": "string", "default": null, "description": "Secondary title text that is placed on the upper right on the title on many web pages." },
|
||||
"titlePicture": { "type": "string", "default": null, "description": "Web site .png logo file that is 450x66 in size placed in meshcentral-data that is used on the top of many pages." },
|
||||
"loginPicture": { "type": "string", "default": null, "description": "Web site .png logo file placed in meshcentral-data that used on the login page when sitestyle is 2." },
|
||||
"userQuota": { "type": "integer" },
|
||||
"meshQuota": { "type": "integer" },
|
||||
"minify": { "type": "boolean", "default": false, "description": "When enabled, the server will send reduced sided web pages." },
|
||||
@ -154,7 +155,7 @@
|
||||
"newAccountEmailDomains": { "type": "array", "uniqueItems": true, "items": { "type": "string" } },
|
||||
"newAccountsRights": { "type": "array", "uniqueItems": true, "items": { "type": "string" } },
|
||||
"welcomeText": { "type": "string", "description": "Text that will be shown on the login screen." },
|
||||
"welcomePicture": { "type": "string", "description": "Name of the JPG file that will be shown on the login screen. Put this file in the meshcentral-data folder and place the name here." },
|
||||
"welcomePicture": { "type": "string", "description": "Name of the PNG or JPEG file that will be shown on the login screen. Put this file in the meshcentral-data folder and place the file name here." },
|
||||
"hide": { "type": "integer" },
|
||||
"footer": { "type": "string" },
|
||||
"certUrl": { "type": "string", "format": "uri", "description": "https url when to get the TLS certificate that MeshAgent's will see when connecting to this server. This setting is used when a reverse proxy like NGINX is used in front of MeshCentral." },
|
||||
|
@ -118,6 +118,7 @@
|
||||
"title": "MyServer",
|
||||
"title2": "Servername",
|
||||
"_titlePicture": "title-sample.png",
|
||||
"_loginPicture": "title-sample.png",
|
||||
"_userQuota": 1048576,
|
||||
"_meshQuota": 248576,
|
||||
"minify": true,
|
||||
|
@ -440,7 +440,7 @@ function startEx(argv) {
|
||||
function totext(source, target, lang) {
|
||||
// Load the source language file
|
||||
var sourceLangFileData = null;
|
||||
try { sourceLangFileData = JSON.parse(fs.readFileSync(source)); } catch (ex) { }
|
||||
try { sourceLangFileData = JSON.parse(fs.readFileSync(source)); } catch (ex) { console.log(ex); }
|
||||
if ((sourceLangFileData == null) || (sourceLangFileData.strings == null)) { log("Invalid source language file."); process.exit(); return; }
|
||||
|
||||
log('Writing ' + lang + '...');
|
||||
@ -485,7 +485,7 @@ function totext(source, target, lang) {
|
||||
function fromtext(source, target, lang) {
|
||||
// Load the source language file
|
||||
var sourceLangFileData = null;
|
||||
try { sourceLangFileData = JSON.parse(fs.readFileSync(source)); } catch (ex) { }
|
||||
try { sourceLangFileData = JSON.parse(fs.readFileSync(source)); } catch (ex) { console.log(ex); }
|
||||
if ((sourceLangFileData == null) || (sourceLangFileData.strings == null)) { log("Invalid source language file."); process.exit(); return; }
|
||||
|
||||
log('Updating ' + lang + '...');
|
||||
@ -514,12 +514,12 @@ function fromtext(source, target, lang) {
|
||||
function merge(source, target, lang) {
|
||||
// Load the source language file
|
||||
var sourceLangFileData = null;
|
||||
try { sourceLangFileData = JSON.parse(fs.readFileSync(source)); } catch (ex) { }
|
||||
try { sourceLangFileData = JSON.parse(fs.readFileSync(source)); } catch (ex) { console.log(ex); }
|
||||
if ((sourceLangFileData == null) || (sourceLangFileData.strings == null)) { log("Invalid source language file."); process.exit(); return; }
|
||||
|
||||
// Load the target language file
|
||||
var targetLangFileData = null;
|
||||
try { targetLangFileData = JSON.parse(fs.readFileSync(target)); } catch (ex) { }
|
||||
try { targetLangFileData = JSON.parse(fs.readFileSync(target)); } catch (ex) { console.log(ex); }
|
||||
if ((targetLangFileData == null) || (targetLangFileData.strings == null)) { log("Invalid target language file."); process.exit(); return; }
|
||||
|
||||
log('Merging ' + lang + '...');
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,11 +25,13 @@
|
||||
</style>
|
||||
</head>
|
||||
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" class="arg_hide login">
|
||||
<img style="position:absolute;left:0;bottom:0;z-index:-1;height:60%;opacity:0.1" src="images/login/back.png" />
|
||||
<img style="position:absolute;left:0;bottom:0;z-index:-1;height:60%;opacity:0.1" src="welcome.png" />
|
||||
<table id="centralTable" class="container" style="height:100%;z-index:1">
|
||||
<tr>
|
||||
<td id="logincell">
|
||||
<div style="font-size:46px;font-family:Arial,Helvetica,sans-serif;font-weight:bold;padding-bottom:10px;color:#c8c8c8;text-shadow: 2px 2px 2px #000;">{{{title1}}}</div>
|
||||
{{{titlehtml}}}
|
||||
<img id="loginPicture" />
|
||||
<div style="font-size:46px;font-family:Arial,Helvetica,sans-serif;font-weight:bold;padding-bottom:10px;color:#c8c8c8;text-shadow: 2px 2px 2px #000;">{{{title1}}}<sup style="font-size:20px"> {{{title2}}}</sup></div>
|
||||
<div id=loginpanel style="display:none;box-shadow:1px 1px 4px #000">
|
||||
<form method=post>
|
||||
<input type=hidden name=action value=login />
|
||||
@ -37,22 +39,22 @@
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<td>
|
||||
<input id=username title="Username" style="width:250px;border:0;border-radius:8px;padding:8px;background-color:#FFF8CC" autocomplete="username" placeholder="Username" type=text maxlength=64 name=username onchange=validateLogin(1) onkeyup=validateLogin(1,event) />
|
||||
<input id=username title="Username" style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:8px;background-color:#FFF8CC" autocomplete="username" placeholder="Username" type=text maxlength=64 name=username onchange=validateLogin(1) onkeyup=validateLogin(1,event) />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input id=password title="Password" style="width:250px;border:0;border-radius:8px;padding:8px;background-color:#FFF8CC" autocomplete="current-password" placeholder="Password" type=password maxlength=256 name=password onchange=validateLogin(2) onkeyup=validateLogin(2,event) />
|
||||
<input id=password title="Password" style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:8px;background-color:#FFF8CC" autocomplete="current-password" placeholder="Password" type=password maxlength=256 name=password onchange=validateLogin(2) onkeyup=validateLogin(2,event) />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div id=showPassHintLink title="Password Hint" style="width:250px;border:0;border-radius:8px;padding:8px;background-color:#FFF8CC;display:none"><a onclick="return showPassHint(event);" href="#" style="cursor:pointer">Show Hint</a></div>
|
||||
<div id=showPassHintLink title="Password Hint" style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:8px;background-color:#FFF8CC;display:none"><a onclick="return showPassHint(event);" href="#" style="cursor:pointer">Show Hint</a></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input id=loginButton style="width:250px;border:0;border-radius:4px;padding:6px" type=submit value="Log In" disabled="disabled" />
|
||||
<input id=loginButton style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:6px" type=submit value="Log In" disabled="disabled" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -132,12 +134,12 @@
|
||||
<table style="width:100%;margin-top:4px;margin-bottom:4px">
|
||||
<tr>
|
||||
<td>
|
||||
<input id=remail title="Email" style="width:250px;border:0;border-radius:8px;padding:8px;background-color:#FFF8CC" autocomplete="username" placeholder="Email" type=text maxlength=256 name=email onchange=validateReset() onkeyup=validateReset(event) />
|
||||
<input id=remail title="Email" style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:8px;background-color:#FFF8CC" autocomplete="username" placeholder="Email" type=text maxlength=256 name=email onchange=validateReset() onkeyup=validateReset(event) />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<input id=eresetButton style="width:250px;border:0;border-radius:4px;padding:6px" type=submit value="Reset Account" disabled="disabled" />
|
||||
<input id=eresetButton style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:6px" type=submit value="Reset Account" disabled="disabled" />
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@ -153,14 +155,14 @@
|
||||
<table style="width:100%">
|
||||
<tr>
|
||||
<td>
|
||||
<input id=tokenInput autocomplete="one-time-code" title="Token" style="width:250px;border:0;border-radius:8px;padding:8px;background-color:#FFF8CC" placeholder="Token" type=text maxlength=50 name=token onchange=checkToken(event) onpaste=resetCheckToken(event) onkeyup=checkToken(event) onkeydown=checkToken(event) /><br />
|
||||
<input id=tokenInput autocomplete="one-time-code" title="Token" style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:8px;background-color:#FFF8CC" placeholder="Token" type=text maxlength=50 name=token onchange=checkToken(event) onpaste=resetCheckToken(event) onkeyup=checkToken(event) onkeydown=checkToken(event) /><br />
|
||||
<input id=hwtokenInput type=text name=hwtoken style="display:none" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div>
|
||||
<input id=tokenOkButton style="width:250px;border:0;border-radius:4px;padding:6px" type=submit value="Log In" disabled="disabled" />
|
||||
<input id=tokenOkButton style="box-sizing:border-box;width:280px;border:0;border-radius:4px;padding:6px" type=submit value="Log In" disabled="disabled" />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -265,8 +267,8 @@
|
||||
<tr style="height:20px">
|
||||
<td>
|
||||
<div>
|
||||
<div id="flink" style="margin-left:4px">{{{footer}}}</div>
|
||||
<div id="flink" style="float:right;margin-right:4px">{{{rootCertLink}}} <a href=terms>Terms & Privacy</a></div>
|
||||
<div id="flink" style="margin-left:4px">{{{footer}}}</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -311,6 +313,8 @@
|
||||
var authStrategies = '{{{authStrategies}}}'.split(',');
|
||||
|
||||
function startup() {
|
||||
if (decodeURIComponent('{{{loginpicture}}}') == 'true') { Q('loginPicture').src = "loginlogo.png"; }
|
||||
|
||||
// Display the right server message
|
||||
var i;
|
||||
var messageid = parseInt('{{{messageid}}}');
|
||||
|
43
webserver.js
43
webserver.js
@ -2459,7 +2459,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (domain.customui != null) { customui = encodeURIComponent(JSON.stringify(domain.customui)); }
|
||||
|
||||
// Render the login page
|
||||
render(req, res, getRenderPage((domain.sitestyle == 2)?'login2':'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, customui: customui, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge).replace(/'/g, '%27'), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail, otpsms: otpsms, twoFactorCookieDays: twoFactorCookieDays, authStrategies: authStrategies.join(',') }, req, domain));
|
||||
render(req, res, getRenderPage((domain.sitestyle == 2) ? 'login2' : '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, customui: customui, footer: (domain.footer == null) ? '' : domain.footer, hkey: encodeURIComponent(hardwareKeyChallenge).replace(/'/g, '%27'), messageid: msgid, passhint: passhint, welcometext: domain.welcometext ? encodeURIComponent(domain.welcometext).split('\'').join('\\\'') : null, hwstate: hwstate, otpemail: otpemail, otpsms: otpsms, twoFactorCookieDays: twoFactorCookieDays, authStrategies: authStrategies.join(','), loginpicture: (typeof domain.loginpicture == 'string') }, req, domain));
|
||||
}
|
||||
|
||||
// Handle a post request on the root
|
||||
@ -2822,7 +2822,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (domain.titlepicture) {
|
||||
if ((parent.configurationFiles != null) && (parent.configurationFiles[domain.titlepicture] != null)) {
|
||||
// Use the logo in the database
|
||||
res.set({ 'Content-Type': 'image/jpeg' });
|
||||
res.set({ 'Content-Type': domain.titlepicture.toLowerCase().endsWith('.png')?'image/png':'image/jpeg' });
|
||||
res.send(parent.configurationFiles[domain.titlepicture]);
|
||||
return;
|
||||
} else {
|
||||
@ -2843,6 +2843,25 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
}
|
||||
}
|
||||
|
||||
// Handle login logo request
|
||||
function handleLoginLogoRequest(req, res) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
if (domain == null) { return; }
|
||||
|
||||
//res.set({ 'Cache-Control': 'max-age=86400' }); // 1 day
|
||||
if (domain.loginpicture) {
|
||||
if ((parent.configurationFiles != null) && (parent.configurationFiles[domain.loginpicture] != null)) {
|
||||
// Use the logo in the database
|
||||
res.set({ 'Content-Type': domain.loginpicture.toLowerCase().endsWith('.png') ? 'image/png' : 'image/jpeg' });
|
||||
res.send(parent.configurationFiles[domain.loginpicture]);
|
||||
return;
|
||||
} else {
|
||||
// Use the logo on file
|
||||
try { res.sendFile(obj.path.join(obj.parent.datapath, domain.loginpicture)); return; } catch (ex) { res.sendStatus(404); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle translation request
|
||||
function handleTranslationsRequest(req, res) {
|
||||
const domain = checkUserIpAddress(req, res);
|
||||
@ -2916,7 +2935,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
if (domain.welcomepicture) {
|
||||
if ((parent.configurationFiles != null) && (parent.configurationFiles[domain.welcomepicture] != null)) {
|
||||
// Use the welcome image in the database
|
||||
res.set({ 'Content-Type': 'image/jpeg' });
|
||||
res.set({ 'Content-Type': domain.welcomepicture.toLowerCase().endsWith('.png')?'image/png':'image/jpeg' });
|
||||
res.send(parent.configurationFiles[domain.welcomepicture]);
|
||||
return;
|
||||
}
|
||||
@ -2925,29 +2944,31 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
try { res.sendFile(obj.path.join(obj.parent.datapath, domain.welcomepicture)); return; } catch (ex) { }
|
||||
}
|
||||
|
||||
var imagefile = 'images/mainwelcome.jpg';
|
||||
if (domain.sitestyle == 2) { imagefile = 'images/login/back.png'; }
|
||||
if (domain.webpublicpath != null) {
|
||||
obj.fs.exists(obj.path.join(domain.webpublicpath, 'images/mainwelcome.jpg'), function (exists) {
|
||||
obj.fs.exists(obj.path.join(domain.webpublicpath, imagefile), function (exists) {
|
||||
if (exists) {
|
||||
// Use the domain logo picture
|
||||
try { res.sendFile(obj.path.join(domain.webpublicpath, 'images/mainwelcome.jpg')); } catch (ex) { res.sendStatus(404); }
|
||||
try { res.sendFile(obj.path.join(domain.webpublicpath, imagefile)); } catch (ex) { res.sendStatus(404); }
|
||||
} else {
|
||||
// Use the default logo picture
|
||||
try { res.sendFile(obj.path.join(obj.parent.webPublicPath, 'images/mainwelcome.jpg')); } catch (ex) { res.sendStatus(404); }
|
||||
try { res.sendFile(obj.path.join(obj.parent.webPublicPath, imagefile)); } catch (ex) { res.sendStatus(404); }
|
||||
}
|
||||
});
|
||||
} else if (parent.webPublicOverridePath) {
|
||||
obj.fs.exists(obj.path.join(obj.parent.webPublicOverridePath, 'images/mainwelcome.jpg'), function (exists) {
|
||||
obj.fs.exists(obj.path.join(obj.parent.webPublicOverridePath, imagefile), function (exists) {
|
||||
if (exists) {
|
||||
// Use the override logo picture
|
||||
try { res.sendFile(obj.path.join(obj.parent.webPublicOverridePath, 'images/mainwelcome.jpg')); } catch (ex) { res.sendStatus(404); }
|
||||
try { res.sendFile(obj.path.join(obj.parent.webPublicOverridePath, imagefile)); } catch (ex) { res.sendStatus(404); }
|
||||
} else {
|
||||
// Use the default logo picture
|
||||
try { res.sendFile(obj.path.join(obj.parent.webPublicPath, 'images/mainwelcome.jpg')); } catch (ex) { res.sendStatus(404); }
|
||||
try { res.sendFile(obj.path.join(obj.parent.webPublicPath, imagefile)); } catch (ex) { res.sendStatus(404); }
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Use the default logo picture
|
||||
try { res.sendFile(obj.path.join(obj.parent.webPublicPath, 'images/mainwelcome.jpg')); } catch (ex) { res.sendStatus(404); }
|
||||
try { res.sendFile(obj.path.join(obj.parent.webPublicPath, imagefile)); } catch (ex) { res.sendStatus(404); }
|
||||
}
|
||||
}
|
||||
|
||||
@ -4707,8 +4728,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
|
||||
obj.app.ws(url + 'devicefile.ashx', function (ws, req) { obj.meshDeviceFileHandler.CreateMeshDeviceFile(obj, ws, null, req, domain); });
|
||||
obj.app.get(url + 'devicefile.ashx', handleDeviceFile);
|
||||
obj.app.get(url + 'logo.png', handleLogoRequest);
|
||||
obj.app.get(url + 'loginlogo.png', handleLoginLogoRequest);
|
||||
obj.app.post(url + 'translations', handleTranslationsRequest);
|
||||
obj.app.get(url + 'welcome.jpg', handleWelcomeImageRequest);
|
||||
obj.app.get(url + 'welcome.png', handleWelcomeImageRequest);
|
||||
obj.app.get(url + 'recordings.ashx', handleGetRecordings);
|
||||
obj.app.get(url + 'player.htm', handlePlayerRequest);
|
||||
obj.app.get(url + 'player', handlePlayerRequest);
|
||||
|
Loading…
Reference in New Issue
Block a user