mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-11-02 02:18:49 +03:00
parent
30469ae2dc
commit
124a9c687e
7 changed files with 81 additions and 9 deletions
|
|
@ -16,12 +16,14 @@ const
|
|||
toggle(div);
|
||||
},
|
||||
|
||||
loadScript = src => src ? new Promise((resolve, reject) => {
|
||||
loadScript = (src, integrity) => src ? new Promise((resolve, reject) => {
|
||||
const script = doc.createElement('script');
|
||||
script.onload = () => resolve();
|
||||
script.onerror = () => reject('Failed loading ' + src);
|
||||
script.src = src;
|
||||
// script.async = true;
|
||||
// script.crossorigin = ''; // same as 'anonymous'
|
||||
if (integrity) { script.integrity = integrity; }
|
||||
doc.head.append(script);
|
||||
}) : Promise.reject('src is empty');
|
||||
|
||||
|
|
@ -146,8 +148,8 @@ if (!navigator.cookieEnabled) {
|
|||
RL_APP_DATA = appData;
|
||||
const url = appData.StaticLibsJs,
|
||||
cb = () => rl.app.bootstart();
|
||||
loadScript(url)
|
||||
.then(() => loadScript(url.replace('/libs.', `/${admin?'admin':'app'}.`)))
|
||||
loadScript(url, appData.StaticLibsJsSri)
|
||||
.then(() => loadScript(url.replace('/libs.', `/${admin?'admin':'app'}.`), appData.StaticAppJsSri))
|
||||
.then(() => appData.PluginsLink ? loadScript(qUri(appData.PluginsLink)) : Promise.resolve())
|
||||
.then(() => rl.app
|
||||
? cb()
|
||||
|
|
|
|||
|
|
@ -5,17 +5,19 @@ const { cleanStatic } = require('./tasks/common');
|
|||
const { js, jsLint } = require('./tasks/js');
|
||||
const { css, cssLint } = require('./tasks/css');
|
||||
const { vendors } = require('./tasks/vendors');
|
||||
const { sri } = require('./tasks/sri');
|
||||
|
||||
const clean = gulp.series(cleanStatic);
|
||||
|
||||
const lint = gulp.parallel(jsLint, cssLint);
|
||||
|
||||
const buildState1 = gulp.parallel(js, css, vendors);
|
||||
const buildState2 = gulp.series(clean, buildState1);
|
||||
const buildState2 = gulp.series(clean, buildState1, sri);
|
||||
|
||||
const build = gulp.parallel(lint, buildState2);
|
||||
|
||||
exports.css = css;
|
||||
exports.lint = lint;
|
||||
exports.sri = sri;
|
||||
exports.build = build;
|
||||
exports.default = build;
|
||||
|
|
|
|||
|
|
@ -779,6 +779,12 @@ class Actions
|
|||
$aResult['StaticLibsJs'] = Utils::WebStaticPath('js/' . ($bAppJsDebug ? '' : 'min/') .
|
||||
'libs' . ($bAppJsDebug ? '' : '.min') . '.js');
|
||||
|
||||
if (!$bAppJsDebug) {
|
||||
$aSri = \SnappyMail\Integrity::loadSriHashes();
|
||||
$aResult['StaticLibsJsSri'] = $aSri['libs.min.js'] ?? '';
|
||||
$aResult['StaticAppJsSri'] = $aSri[($bAdmin ? 'admin' : 'app') . '.min.js'] ?? '';
|
||||
}
|
||||
|
||||
$this->oPlugins->InitAppData($bAdmin, $aResult, $oAccount);
|
||||
|
||||
return $aResult;
|
||||
|
|
|
|||
|
|
@ -207,9 +207,12 @@ abstract class Service
|
|||
if ($sResult) {
|
||||
$sResult .= '<!--cached-->';
|
||||
} else {
|
||||
$aSri = $sAppCssMin ? \SnappyMail\Integrity::loadSriHashes() : [];
|
||||
$sCssFile = ($bAdmin ? 'admin' : 'app').$sAppCssMin.'.css';
|
||||
$aTemplateParameters['{{BaseAppBootCss}}'] = \file_get_contents(APP_VERSION_ROOT_PATH.'static/css/boot'.$sAppCssMin.'.css');
|
||||
$aTemplateParameters['{{BaseAppBootScript}}'] = \file_get_contents(APP_VERSION_ROOT_PATH.'static/js'.($sAppJsMin ? '/min' : '').'/boot'.$sAppJsMin.'.js');
|
||||
$aTemplateParameters['{{BaseAppMainCssLink}}'] = Utils::WebStaticPath('css/'.($bAdmin ? 'admin' : 'app').$sAppCssMin.'.css');
|
||||
$aTemplateParameters['{{BaseAppMainCssLink}}'] = Utils::WebStaticPath('css/'.$sCssFile);
|
||||
$aTemplateParameters['{{BaseAppMainCssSri}}'] = empty($aSri[$sCssFile]) ? '' : ' integrity="'.$aSri[$sCssFile].'"';
|
||||
$aTemplateParameters['{{BaseAppThemeCss}}'] = \preg_replace('/\\s*([:;{},]+)\\s*/s', '$1', $oActions->compileCss($sThemeName, $bAdmin));
|
||||
$aTemplateParameters['{{BaseLanguage}}'] = $oActions->compileLanguage($sLanguage, $bAdmin);
|
||||
$aTemplateParameters['{{BaseTemplates}}'] = Utils::ClearHtmlOutput($oServiceActions->compileTemplates($bAdmin));
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ abstract class Integrity
|
|||
/**
|
||||
* Called by https://webmail.tld/?/Test
|
||||
*/
|
||||
public static function test()
|
||||
public static function test(): void
|
||||
{
|
||||
$result = static::phpVersion();
|
||||
if ($result) {
|
||||
|
|
@ -89,14 +89,15 @@ abstract class Integrity
|
|||
}
|
||||
}
|
||||
|
||||
public static function phpVersion()
|
||||
public static function phpVersion(): ?string
|
||||
{
|
||||
if (PHP_VERSION_ID < 80200) {
|
||||
return 'Your PHP version ('.PHP_VERSION.') is lower than the minimal required 8.2.0!';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function phpExtensions()
|
||||
public static function phpExtensions(): array
|
||||
{
|
||||
$aRequirements = array(
|
||||
'openssl' => extension_loaded('openssl'),
|
||||
|
|
@ -123,4 +124,23 @@ abstract class Integrity
|
|||
return $aMissing;
|
||||
}
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity
|
||||
private static $aSri;
|
||||
public static function loadSriHashes(): array
|
||||
{
|
||||
if (!\is_array($aSri)) {
|
||||
$sSriPath = APP_VERSION_ROOT_PATH . 'static/sri.json';
|
||||
$aSri = \is_readable($sSriPath) ? \json_decode(\file_get_contents($sSriPath), true) : [];
|
||||
if (!$aSri) {
|
||||
$aSri = [
|
||||
'libs.min.js' => \hash_file('sha384', APP_VERSION_ROOT_PATH . 'static/js/min/libs.min.js'),
|
||||
'admin.min.js' => \hash_file('sha384', APP_VERSION_ROOT_PATH . 'static/js/min/admin.min.js'),
|
||||
'app.min.js' => \hash_file('sha384', APP_VERSION_ROOT_PATH . 'static/js/min/app.min.js'),
|
||||
'admin.min.css' => \hash_file('sha384', APP_VERSION_ROOT_PATH . 'static/css/admin.min.css'),
|
||||
'app.min.css' => \hash_file('sha384', APP_VERSION_ROOT_PATH . 'static/css/app.min.css'),
|
||||
];
|
||||
}
|
||||
}
|
||||
return $aSri;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
<meta name="theme-color" content="black">
|
||||
<title></title>
|
||||
<style id="app-boot-css">{{BaseAppBootCss}}</style>
|
||||
<link type="text/css" rel="stylesheet" href="{{BaseAppMainCssLink}}">
|
||||
<link type="text/css" rel="stylesheet" href="{{BaseAppMainCssLink}}{{BaseAppMainCssSri}}">
|
||||
<link rel="manifest" href="{{BaseAppManifestLink}}">
|
||||
<link rel="icon" href="{{BaseFavIconSvg}}" type="image/svg+xml">
|
||||
<style id="app-theme-style" data-name="{{BaseAppThemeName}}">{{BaseAppThemeCss}}</style>
|
||||
|
|
|
|||
39
tasks/sri.js
Normal file
39
tasks/sri.js
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* Tachyon Webmail (c) Tachyon | Licensed under AGPL v3 */
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const path = require('path');
|
||||
|
||||
const { config } = require('./config');
|
||||
|
||||
function sriHash(filePath) {
|
||||
const data = fs.readFileSync(filePath);
|
||||
const hash = crypto.createHash('sha384').update(data).digest('base64');
|
||||
return 'sha384-' + hash;
|
||||
}
|
||||
|
||||
function sri(done) {
|
||||
const jsMinDir = config.paths.staticMinJS;
|
||||
const cssDir = config.paths.staticCSS;
|
||||
|
||||
const files = [
|
||||
['libs.min.js', jsMinDir + 'libs.min.js'],
|
||||
['app.min.js', jsMinDir + 'app.min.js'],
|
||||
['admin.min.js', jsMinDir + 'admin.min.js'],
|
||||
['app.min.css', cssDir + 'app.min.css'],
|
||||
['admin.min.css',cssDir + 'admin.min.css'],
|
||||
];
|
||||
|
||||
const hashes = {};
|
||||
for (const [key, filePath] of files) {
|
||||
if (fs.existsSync(filePath)) {
|
||||
hashes[key] = sriHash(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
const outPath = path.join('snappymail/v/' + config.devVersion, 'static/sri.json');
|
||||
fs.writeFileSync(outPath, JSON.stringify(hashes, null, '\t') + '\n');
|
||||
console.log('[sri] wrote ' + outPath);
|
||||
done();
|
||||
}
|
||||
|
||||
exports.sri = sri;
|
||||
Loading…
Add table
Add a link
Reference in a new issue