1
0
Fork 0
mirror of https://github.com/Ylianst/MeshCentral.git synced 2025-02-12 11:01:52 +00:00

Improved 404 pages to support tight Content-Security-Policy HTTP headers.

This commit is contained in:
Ylian Saint-Hilaire 2022-01-10 01:26:45 -08:00
parent fe60c49f5d
commit ccd04ed573
5 changed files with 296 additions and 75 deletions

View file

@ -9,7 +9,11 @@
<meta name="robots" content="noindex,nofollow" /> <meta name="robots" content="noindex,nofollow" />
<link rel="apple-touch-icon" href="/favicon-303x303.png" /> <link rel="apple-touch-icon" href="/favicon-303x303.png" />
<title>{{{title}}}</title> <title>{{{title}}}</title>
<style type="text/css"> <style nonce="{{{cspNonce}}}">
body {
overflow-y:hidden;max-width:100%;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif
}
a { a {
color: #036; color: #036;
text-decoration: underline; text-decoration: underline;
@ -20,35 +24,95 @@
text-decoration: underline; text-decoration: underline;
} }
#footer a:hover { #footer a:hover {
color: #fff; color: #fff;
text-decoration: none; text-decoration: none;
} }
#masthead {
background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden
}
#title1 {
float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:4px
}
#title1a {
font-size:36px;font-family:Arial,Helvetica,sans-serif
}
#title2 {
float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:7px
}
#title2a {
font-size:12px;font-family:Arial,Helvetica,sans-serif
}
#page_content {
overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%
}
#column_l {
padding-left:10px;padding-right:10px
}
#text1 {
text-align:center;padding-top:30px;font-size:100px;font-family:Arial;color:#bbb
}
#text2 {
text-align:center;font-size:16px;font-family:Arial;color:#999
}
#text3 {
text-align:center;padding-top:16px;font-size:20px;font-family:Arial;color:#999
}
#text3l {
text-decoration:none
}
#footer {
height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px
}
#footertable {
width:100%
}
#footerLeft {
text-align:left;color:white
}
#footerRight {
text-align:right
}
</style> </style>
</head> </head>
<body onload="if (typeof(startup) !== 'undefined') startup();" style="overflow-y:hidden;max-width:100%;margin:0;padding:0;border:0;color:black;font-size:13px;font-family:\'Trebuchet MS\', Arial, Helvetica, sans-serif"> <body>
<div id="container"> <div id="container">
<!-- Begin Masthead --> <!-- Begin Masthead -->
<div id=masthead style="background:url(logo.png) 0px 0px;background-size:341px 50px;background-color:#036;background-repeat:no-repeat;height:50px;width:100%;overflow:hidden"> <div id=masthead>
<div style="float:left;height:66px;color:#c8c8c8;padding-left:10px;padding-top:4px"> <div id="title1">
<strong><font style="font-size:36px;font-family:Arial,Helvetica,sans-serif">{{{title}}}</font></strong> <strong><font id="title1a">{{{title}}}</font></strong>
</div> </div>
<div style="float:left;height:66px;color:#c8c8c8;padding-left:5px;padding-top:7px"> <div id="title2">
<strong><font style="font-size:12px;font-family:Arial,Helvetica,sans-serif">{{{title2}}}</font></strong> <strong><font id="title2a">{{{title2}}}</font></strong>
</div> </div>
</div> </div>
<div id=page_content style="overflow-y:scroll;position:absolute;bottom:32px;top:50px;width:100%"> <div id=page_content>
<div id="column_l" style="padding-left:10px;padding-right:10px"> <div id="column_l">
<div style="text-align:center;padding-top:30px;font-size:100px;font-family:Arial;color:#bbb"><b>404</b></div> <div id="text1"><b>404</b></div>
<div style="text-align:center;font-size:16px;font-family:Arial;color:#999">This page does not exist</div> <div id="text2">This page does not exist</div>
<div style="text-align:center;padding-top:16px;font-size:20px;font-family:Arial;color:#999"><a href="/" style="text-decoration:none"><b>Go to main site</b></a></div> <div id="text3"><a id="text3l "href="/"><b>Go to main site</b></a></div>
</div> </div>
</div> </div>
<div id=footer style="height:32px;width:100%;text-align:center;background-color:#113962;position:absolute;bottom:0px"> <div id=footer>
<table cellpadding=0 cellspacing=6 style=width:100%> <table id=footertable cellpadding=0 cellspacing=6>
<tr> <tr>
<td style=text-align:left;color:white>{{{footer}}}</td> <td id="footerLeft">{{{footer}}}</td>
<td style=text-align:right>{{{rootCertLink}}}&nbsp;<a href="/">Back</a></td> <td id="footerRight">{{{rootCertLink}}}&nbsp;<a href="/">Back</a></td>
</tr> </tr>
</table> </table>
</div> </div>

View file

@ -10,53 +10,128 @@
<link type="text/css" href="/styles/style.css" media="screen" rel="stylesheet" title="CSS" /> <link type="text/css" href="/styles/style.css" media="screen" rel="stylesheet" title="CSS" />
<link rel="apple-touch-icon" href="/favicon-303x303.png" /> <link rel="apple-touch-icon" href="/favicon-303x303.png" />
<title>{{{title}}}</title> <title>{{{title}}}</title>
<style nonce="{{{cspNonce}}}">
#xbody {
overflow:hidden;
}
#masthead {
background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden;
}
#title1 {
float:left;text-shadow: 1px 1px 2px #000
}
#title2 {
float:left; height: 66px; color:#c8c8c8; padding-left:16px; padding-top:7px
}
#title2a {
font-size:46px; font-family: Arial, Helvetica, sans-serif;text-shadow: 1px 1px 2px #000
}
#title3 {
float:left; height: 66px; color:#c8c8c8; padding-left:5px; padding-top:14px
}
#title3a {
font-size:14px; font-family: Arial, Helvetica, sans-serif;text-shadow: 1px 1px 2px #000
}
#footerLeft {
text-align:left
}
#footerRight {
text-align:right
}
#topbar {
height:24px;position:relative
}
#page_leftbar_div {
height:16px
}
#uiMenu {
}
#text1 {
text-align:center;padding-top:30px;font-size:200px;font-family:Arial;color:#bbb
}
#text2 {
text-align:center;font-size:20px;font-family:Arial;color:#999
}
#text3 {
text-align:center;padding-top:20px;font-size:20px;font-family:Arial;color:#999
}
#column_l {
max-height:calc(100vh - 135px);overflow-y:auto
}
</style>
</head> </head>
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" style="display:none;overflow:hidden"> <body id="xbody">
<div id="container"> <div id="container">
<!-- Begin Masthead --> <!-- Begin Masthead -->
<div id="masthead" class=noselect style="background:url(logo.png) 0px 0px;background-color:#036;background-repeat:no-repeat;height:66px;width:100%;overflow:hidden;"> <div id="masthead" class=noselect>
<div style="float:left;text-shadow: 1px 1px 2px #000">{{{titlehtml}}}</div> <div id="title1">{{{titlehtml}}}</div>
<div style="float:left; height: 66px; color:#c8c8c8; padding-left:16px; padding-top:7px"> <div id="title2">
<strong><font style="font-size:46px; font-family: Arial, Helvetica, sans-serif;text-shadow: 1px 1px 2px #000">{{{title1}}}</font></strong> <strong><font id="title2a">{{{title1}}}</font></strong>
</div> </div>
<div style="float:left; height: 66px; color:#c8c8c8; padding-left:5px; padding-top:14px"> <div id="title3">
<strong><font style="font-size:14px; font-family: Arial, Helvetica, sans-serif;text-shadow: 1px 1px 2px #000">{{{title2}}}</font></strong> <strong><font id="title3a">{{{title2}}}</font></strong>
</div> </div>
</div> </div>
<div id="page_leftbar"> <div id="page_leftbar">
<div style="height:16px"></div> <div id="page_leftbar_div"></div>
</div> </div>
<div id=topbar class="noselect style3" style="height:24px;position:relative"> <div id=topbar class="noselect style3">
<div id=uiMenuButton title="User interface selection" onclick="showUserInterfaceSelectMenu()"> <div id=uiMenuButton title="User interface selection">
&diams; &diams;
<div id=uiMenu style="display:none"> <div id=uiMenu>
<div id=uiViewButton1 class=uiSelector onclick=userInterfaceSelectMenu(1) title="Left bar interface"><div class="uiSelector1"></div></div> <div id=uiViewButton1 class=uiSelector title="Left bar interface"><div class="uiSelector1"></div></div>
<div id=uiViewButton2 class=uiSelector onclick=userInterfaceSelectMenu(2) title="Top bar interface"><div class="uiSelector2"></div></div> <div id=uiViewButton2 class=uiSelector title="Top bar interface"><div class="uiSelector2"></div></div>
<div id=uiViewButton3 class=uiSelector onclick=userInterfaceSelectMenu(3) title="Fixed width interface"><div class="uiSelector3"></div></div> <div id=uiViewButton3 class=uiSelector title="Fixed width interface"><div class="uiSelector3"></div></div>
<div id=uiViewButton4 class=uiSelector onclick=toggleNightMode() title="Toggle night mode"><div class="uiSelector4"></div></div> <div id=uiViewButton4 class=uiSelector title="Toggle night mode"><div class="uiSelector4"></div></div>
</div> </div>
</div> </div>
</div> </div>
<div id="column_l" style="max-height:calc(100vh - 135px);overflow-y:auto"> <div id="column_l">
<div style="text-align:center;padding-top:30px;font-size:200px;font-family:Arial;color:#bbb"><b>404</b></div> <div id="text1"><b>404</b></div>
<div style="text-align:center;font-size:20px;font-family:Arial;color:#999">This page does not exist</div> <div id="text2">This page does not exist</div>
<div style="text-align:center;padding-top:20px;font-size:20px;font-family:Arial;color:#999"><a href="/" style="text-decoration:none"><b>Go to main site</b></a></div> <div id="text3"><a href="/" style="text-decoration:none"><b>Go to main site</b></a></div>
</div> </div>
<div id="footer"> <div id="footer">
<table cellpadding="0" cellspacing="10" style="width: 100%"> <table cellpadding="0" cellspacing="10" style="width: 100%">
<tr> <tr>
<td style="text-align:left"></td> <td id="footerLeft"></td>
<td style="text-align:right"><a href="/">Back</a></td> <td id="footerRight"><a href="/">Back</a></td>
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>
<script> <script nonce="{{{cspNonce}}}">
'use strict'; 'use strict';
var uiMode = parseInt(getstore('uiMode', 1)); var uiMode = parseInt(getstore('uiMode', 1));
var webPageStackMenu = false; var webPageStackMenu = false;
var webPageFullScreen = true; var webPageFullScreen = true;
var nightMode = (getstore('_nightMode', '0') == '1'); var nightMode = (getstore('_nightMode', '0') == '1');
var menuVisible = false;
QV('uiMenu', menuVisible);
if (nightMode) { QC('xbody').add('night'); } else { QC('xbody').remove('night'); }
// Setup handlers
Q('uiMenuButton').onclick = showUserInterfaceSelectMenu;
Q('uiViewButton1').onclick = function () { userInterfaceSelectMenu(1); }
Q('uiViewButton2').onclick = function () { userInterfaceSelectMenu(2); }
Q('uiViewButton3').onclick = function () { userInterfaceSelectMenu(3); }
Q('uiViewButton4').onclick = toggleNightMode;
var terms = '{{{terms}}}'; var terms = '{{{terms}}}';
if (terms != '') { QH('column_l', decodeURIComponent(terms)); } if (terms != '') { QH('column_l', decodeURIComponent(terms)); }
@ -70,7 +145,8 @@
Q('uiViewButton3').classList.remove('uiSelectorSel'); Q('uiViewButton3').classList.remove('uiSelectorSel');
Q('uiViewButton4').classList.remove('uiSelectorSel'); Q('uiViewButton4').classList.remove('uiSelectorSel');
try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { } try { Q('uiViewButton' + uiMode).classList.add('uiSelectorSel'); } catch (ex) { }
QV('uiMenu', (QS('uiMenu').display == 'none')); menuVisible = !menuVisible;
QV('uiMenu', menuVisible);
if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); } if (nightMode) { Q('uiViewButton4').classList.add('uiSelectorSel'); }
} }
@ -85,7 +161,7 @@
function toggleNightMode() { function toggleNightMode() {
nightMode = !nightMode; nightMode = !nightMode;
if (nightMode) { QC('body').add('night'); } else { QC('body').remove('night'); } if (nightMode) { QC('xbody').add('night'); } else { QC('xbody').remove('night'); }
putstore('_nightMode', nightMode ? '1' : '0'); putstore('_nightMode', nightMode ? '1' : '0');
} }
@ -95,19 +171,19 @@
var hide = 0; var hide = 0;
//if (args.hide) { hide = parseInt(args.hide); } //if (args.hide) { hide = parseInt(args.hide); }
if (webPageFullScreen == false) { if (webPageFullScreen == false) {
QC('body').remove('menu_stack'); QC('xbody').remove('menu_stack');
QC('body').remove('fullscreen'); QC('xbody').remove('fullscreen');
QC('body').remove('arg_hide'); QC('xbody').remove('arg_hide');
//if (xxcurrentView >= 10) QC('column_l').add('room4submenu'); //if (xxcurrentView >= 10) QC('column_l').add('room4submenu');
//QV('UserDummyMenuSpan', false); //QV('UserDummyMenuSpan', false);
//QV('page_leftbar', false); //QV('page_leftbar', false);
} else { } else {
QC('body').add('fullscreen'); QC('xbody').add('fullscreen');
if (hide & 16) QC('body').add('arg_hide'); // This is replacement for QV('page_leftbar', !(hide & 16)); if (hide & 16) QC('xbody').add('arg_hide'); // This is replacement for QV('page_leftbar', !(hide & 16));
//QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen); //QV('UserDummyMenuSpan', (xxcurrentView < 10) && webPageFullScreen);
//QV('page_leftbar', true); //QV('page_leftbar', true);
} }
QV('body', true); QV('xbody', true);
} }
// If FullScreen, toggle menu to be horisontal or vertical // If FullScreen, toggle menu to be horisontal or vertical
@ -118,9 +194,9 @@
putstore('webPageStackMenu', webPageStackMenu); putstore('webPageStackMenu', webPageStackMenu);
} }
if (webPageStackMenu == false) { if (webPageStackMenu == false) {
QC('body').remove('menu_stack'); QC('xbody').remove('menu_stack');
} else { } else {
QC('body').add('menu_stack'); QC('xbody').add('menu_stack');
//if (xxcurrentView >= 10) QC('column_l').remove('room4submenu'); //if (xxcurrentView >= 10) QC('column_l').remove('room4submenu');
} }
} }
@ -130,7 +206,7 @@
function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } } function getstore(name, val) { try { if (typeof (localStorage) === 'undefined') return val; var v = localStorage.getItem(name); if ((v == null) || (v == null)) return val; return v; } catch (e) { return val; } }
function Q(x) { return document.getElementById(x); } // "Q" function Q(x) { return document.getElementById(x); } // "Q"
function QS(x) { try { return Q(x).style; } catch (x) { } } // "Q" style function QS(x) { try { return Q(x).style; } catch (x) { } } // "Q" style
function QV(x, y) { try { QS(x).display = (y ? '' : 'none'); } catch (x) { } } // "Q" visible function QV(x, y) { try { QS(x).display = (y ? '' : 'none'); } catch (ex) { console.log(ex); } } // "Q" visible
function QH(x, y) { Q(x).innerHTML = y; } // "Q" html function QH(x, y) { Q(x).innerHTML = y; } // "Q" html
function QC(x) { try { return Q(x).classList; } catch (x) { } } // "Q" class function QC(x) { try { return Q(x).classList; } catch (x) { } } // "Q" class
</script> </script>

View file

@ -10,7 +10,7 @@
<link type=text/css href="/styles/style.css" media="screen" rel="stylesheet" title="CSS" /> <link type=text/css href="/styles/style.css" media="screen" rel="stylesheet" title="CSS" />
<link rel="apple-touch-icon" href="/favicon-303x303.png" /> <link rel="apple-touch-icon" href="/favicon-303x303.png" />
<title>{{{title1}}} - Download</title> <title>{{{title1}}} - Download</title>
<style> <style nonce="{{{cspNonce}}}">
body { body {
background-color: cadetblue; background-color: cadetblue;
background: linear-gradient(to bottom right, #369, #036); background: linear-gradient(to bottom right, #369, #036);
@ -18,27 +18,84 @@
overflow: hidden; overflow: hidden;
} }
a:link { color: #c8c8c8; } a:link {
a:visited { color: #c8c8c8; } color: #c8c8c8;
a:hover { color: #c8c8c8; } }
a:active { color: #c8c8c8; }
a:visited {
color: #c8c8c8;
}
a:hover {
color: #c8c8c8;
}
a:active {
color: #c8c8c8;
}
#backImage {
position: absolute;
left: 0;
bottom: 0;
z-index: -1;
height: 60%;
opacity: 0.1;
}
#centralTable {
height: 100%;
z-index: 1;
}
#text1 {
text-align: center;
padding-top: 30px;
font-size: 160px;
font-family: Arial;
color: #bbb;
}
#text2 {
text-align: center;
font-size: 20px;
font-family: Arial;
color: #999;
}
#text3 {
text-align: center;
padding-top: 20px;
font-size: 20px;
font-family: Arial;
color: #999;
}
#flink1 {
margin-left: 4px;
}
#flink2 {
float: right;
margin-right: 4px;
}
</style> </style>
</head> </head>
<body> <body>
<img style="position:absolute;left:0;bottom:0;z-index:-1;height:60%;opacity:0.1" src="../../images/login/back.png" /> <img id="backImage" src="../../images/login/back.png" />
<table id="centralTable" class="container" style="height:100%;z-index:1"> <table id="centralTable" class="container">
<tr> <tr>
<td style="width:100%;text-align:center"> <td style="width:100%;text-align:center">
<div style="text-align:center;padding-top:30px;font-size:160px;font-family:Arial;color:#bbb"><b>404</b></div> <div id="text1"><b>404</b></div>
<div style="text-align:center;font-size:20px;font-family:Arial;color:#999">This page does not exist</div> <div id="text2">This page does not exist</div>
<div style="text-align:center;padding-top:20px;font-size:20px;font-family:Arial;color:#999"><a href="/"><b>Go to main site</b></a></div> <div id="text3"><a href="/"><b>Go to main site</b></a></div>
</td> </td>
</tr> </tr>
<tr style="height:20px"> <tr style="height:20px">
<td> <td>
<div> <div>
<div id="flink" style="margin-left:4px">{{{footer}}}</div> <div id="flink1">{{{footer}}}</div>
<div id="flink" style="float:right;margin-right:4px">{{{rootCertLink}}}&nbsp;<a href=../../terms>Terms &amp; Privacy</a></div> <div id="flink2">{{{rootCertLink}}}&nbsp;<a href=../../terms>Terms &amp; Privacy</a></div>
</div> </div>
</td> </td>
</tr> </tr>

View file

@ -19,15 +19,37 @@
background: linear-gradient(to bottom right, #369, #036); background: linear-gradient(to bottom right, #369, #036);
} }
#flink a:link { color: #c8c8c8; } #flink a:link {
#flink a:visited { color: #c8c8c8; } color: #c8c8c8;
#flink a:hover { color: #c8c8c8; } }
#flink a:active { color: #c8c8c8; }
#welcomeText a:link { color: #FFF; } #flink a:visited {
#welcomeText a:visited { color: #FFF; } color: #c8c8c8;
#welcomeText a:hover { color: #FFF; } }
#welcomeText a:active { color: #FFF; }
#flink a:hover {
color: #c8c8c8;
}
#flink a:active {
color: #c8c8c8;
}
#welcomeText a:link {
color: #FFF;
}
#welcomeText a:visited {
color: #FFF;
}
#welcomeText a:hover {
color: #FFF;
}
#welcomeText a:active {
color: #FFF;
}
</style> </style>
</head> </head>
<body id="body" onload="if (typeof(startup) !== 'undefined') startup();" class="arg_hide login"> <body id="body" onload="if (typeof(startup) !== 'undefined') startup();" class="arg_hide login">

View file

@ -6359,8 +6359,10 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
parent.debug('web', '404 Error ' + req.url); parent.debug('web', '404 Error ' + req.url);
var domain = getDomain(req); var domain = getDomain(req);
if ((domain == null) || (domain.auth == 'sspi')) { res.sendStatus(404); return; } if ((domain == null) || (domain.auth == 'sspi')) { res.sendStatus(404); return; }
if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL key if ((domain.loginkey != null) && (domain.loginkey.indexOf(req.query.key) == -1)) { res.sendStatus(404); return; } // Check 3FA URL
res.status(404).render(getRenderPage((domain.sitestyle == 2) ? 'error4042' : 'error404', req, domain), getRenderArgs({}, req, domain)); const cspNonce = obj.crypto.randomBytes(15).toString('base64');
res.set({ 'Content-Security-Policy': "default-src 'none'; script-src 'self' 'nonce-" + cspNonce + "'; img-src 'self'; style-src 'self' 'nonce-" + cspNonce + "';" });
res.status(404).render(getRenderPage((domain.sitestyle == 2) ? 'error4042' : 'error404', req, domain), getRenderArgs({ cspNonce: cspNonce }, req, domain));
}); });
} }