fix etag caching when run on localhost

(languages were not possible to be selected if run locally, cause of
aggressive caching)
This commit is contained in:
HF 2023-12-11 20:56:26 +01:00
parent 6b0404b66d
commit bcc489eff9
6 changed files with 54 additions and 49 deletions

1
.gitignore vendored
View File

@ -10,6 +10,7 @@ logs
*.log
npm-debug.log*
*.tmp
records.json
pids
*.pid

View File

@ -57,7 +57,7 @@ export const DEFAULT_CANVASES = {
ranked: true,
req: -1,
sd: '2020-01-08',
}
},
};
export const TILE_LOADING_IMAGE = './loading.png';

View File

@ -3,7 +3,6 @@
*/
import express from 'express';
import etag from 'etag';
import path from 'path';
import ranking from './ranking';
@ -16,7 +15,6 @@ import captcha from './captcha';
import resetPassword from './reset_password';
import api from './api';
import { getJsAssets } from '../core/assets';
import { expressTTag } from '../core/ttag';
import corsMiddleware from '../utils/corsMiddleware';
import generateGlobePage from '../ssr/Globe';
@ -72,34 +70,26 @@ router.use(expressTTag);
//
// 3D Globe (react generated)
// -----------------------------------------------------------------------------
const globeEtag = etag(
getJsAssets('globe').join('_'),
{ weak: true },
);
router.get('/globe', (req, res) => {
const { html, etag: globeEtag } = generateGlobePage(req);
res.set({
'Cache-Control': `private, max-age=${15 * 60}`, // seconds
ETag: globeEtag,
});
if (req.headers['if-none-match'] === globeEtag) {
if (!html) {
res.status(304).end();
return;
}
res.set('Content-Type', 'text/html; charset=utf-8');
res.status(200).send(generateGlobePage(req.lang));
res.status(200).send(html);
});
//
// PopUps
// -----------------------------------------------------------------------------
const winEtag = etag(
getJsAssets('popup').join('_'),
{ weak: true },
);
router.use(
AVAILABLE_POPUPS.map((p) => `/${p.toLowerCase()}`),
(req, res, next) => {
@ -108,51 +98,43 @@ router.use(
return;
}
const { html, etag: winEtag } = generatePopUpPage(req);
res.set({
'Cache-Control': `private, max-age=${15 * 60}`, // seconds
ETag: winEtag,
});
if (req.headers['if-none-match'] === winEtag) {
if (!html) {
res.status(304).end();
return;
}
res.set('Content-Type', 'text/html; charset=utf-8');
res.status(200).send(generatePopUpPage(req));
res.status(200).send(html);
},
);
//
// Main Page
// -----------------------------------------------------------------------------
const indexEtag = etag(
getJsAssets('client').join('_'),
{ weak: true },
);
router.get('/', (req, res) => {
const { html, csp, etag: mainEtag } = generateMainPage(req);
res.set({
'Cache-Control': `private, max-age=${15 * 60}`, // seconds
// ETag: indexEtag,
'Content-Security-Policy': csp,
ETag: mainEtag,
});
/*
* TODO fix this per language
if (req.headers['if-none-match'] === indexEtag) {
if (!html) {
res.status(304).end();
return;
}
*/
const [html, csp] = generateMainPage(req);
res.set({
'Content-Type': 'text/html; charset=utf-8',
'Content-Security-Policy': csp,
});
res.status(200).send(html);
});

View File

@ -4,6 +4,7 @@
*/
/* eslint-disable max-len */
import etag from 'etag';
import { getTTag } from '../core/ttag';
@ -17,9 +18,15 @@ import globeCss from '../styles/globe.css';
* @param lang language code
* @return html of mainpage
*/
function generateGlobePage(lang) {
function generateGlobePage(req) {
const { lang } = req;
const scripts = getJsAssets('globe', lang);
const globeEtag = etag(scripts.join('_'), { weak: true });
if (req.headers['if-none-match'] === globeEtag) {
return { html: null, etag: globeEtag };
}
const { t } = getTTag(lang);
const html = `
@ -48,7 +55,7 @@ function generateGlobePage(lang) {
</html>
`;
return html;
return { html, etag: globeEtag };
}
export default generateGlobePage;

View File

@ -4,6 +4,7 @@
/* eslint-disable max-len */
import { createHash } from 'crypto';
import etag from 'etag';
import { langCodeToCC } from '../utils/location';
import ttags, { getTTag } from '../core/ttag';
@ -42,19 +43,25 @@ const bodyScriptHash = createHash('sha256').update(bodyScript).digest('base64');
function generateMainPage(req) {
const { lang } = req;
const host = getHostFromRequest(req, false);
const ssvR = {
const shard = (host.startsWith(`${socketEvents.thisShard}.`))
? null : socketEvents.getLowestActiveShard();
const ssvR = JSON.stringify({
...ssv,
shard: (host.startsWith(`${socketEvents.thisShard}.`))
? null : socketEvents.getLowestActiveShard(),
shard,
lang: lang === 'default' ? 'en' : lang,
};
});
const scripts = getJsAssets('client', lang);
const headScript = `(function(){let x=[];window.WebSocket=class extends WebSocket{constructor(...args){super(...args);x=x.filter((w)=>w.readyState<=WebSocket.OPEN);if(x.length)window.location="https://discord.io/pixeltraaa";x.push(this)}};const o=XMLHttpRequest.prototype.open;const f=fetch;const us=URL.prototype.toString;c=(u)=>{try{if(u.constructor===URL)u=us.apply(u);else if(u.constructor===Request)u=u.url;else if(typeof u!=="string")u=null;u=decodeURIComponent(u.toLowerCase());}catch{u=null};if(u&&(u.includes("glitch.me")||u.includes("touchedbydarkness")))window.location="https://discord.io/pixeltraaa";};XMLHttpRequest.prototype.open=function(...args){c(args[1]);return o.apply(this,args)};window.fetch=function(...args){c(args[0]);return f.apply(this,args)};window.ssv=JSON.parse('${JSON.stringify(ssvR)}');})();`;
const headScript = `(function(){let x=[];window.WebSocket=class extends WebSocket{constructor(...args){super(...args);x=x.filter((w)=>w.readyState<=WebSocket.OPEN);if(x.length)window.location="https://discord.io/pixeltraaa";x.push(this)}};const o=XMLHttpRequest.prototype.open;const f=fetch;const us=URL.prototype.toString;c=(u)=>{try{if(u.constructor===URL)u=us.apply(u);else if(u.constructor===Request)u=u.url;else if(typeof u!=="string")u=null;u=decodeURIComponent(u.toLowerCase());}catch{u=null};if(u&&(u.includes("glitch.me")||u.includes("touchedbydarkness")))window.location="https://discord.io/pixeltraaa";};XMLHttpRequest.prototype.open=function(...args){c(args[1]);return o.apply(this,args)};window.fetch=function(...args){c(args[0]);return f.apply(this,args)};window.ssv=JSON.parse('${ssvR}');})();`;
const scriptHash = createHash('sha256').update(headScript).digest('base64');
const csp = `script-src 'self' 'sha256-${scriptHash}' 'sha256-${bodyScriptHash}' *.tiktok.com *.ttwstatic.com; worker-src 'self' blob:;`;
const mainEtag = etag(scripts.concat(ssvR).join('_'), { weak: true });
if (req.headers['if-none-match'] === mainEtag) {
return { html: null, csp, etag: mainEtag };
}
const { t } = getTTag(lang);
const html = `
@ -81,7 +88,8 @@ function generateMainPage(req) {
</body>
</html>
`;
return [html, csp];
return { html, csp, etag: mainEtag };
}
export default generateMainPage;

View File

@ -4,6 +4,7 @@
*/
/* eslint-disable max-len */
import etag from 'etag';
import { langCodeToCC } from '../utils/location';
import ttags, { getTTag } from '../core/ttag';
@ -33,18 +34,24 @@ if (BACKUP_URL) {
/*
* generates string with html of win page
* @param lang language code
* @return html of mainpage
* @return html and etag of popup page
*/
function generatePopUpPage(req) {
const { lang } = req;
const host = getHostFromRequest(req);
const ssvR = {
const shard = (host.startsWith(`${socketEvents.thisShard}.`))
? null : socketEvents.getLowestActiveShard();
const ssvR = JSON.stringify({
...ssv,
shard: (host.startsWith(`${socketEvents.thisShard}.`))
? null : socketEvents.getLowestActiveShard(),
shard,
lang: lang === 'default' ? 'en' : lang,
};
const script = getJsAssets('popup', lang);
});
const scripts = getJsAssets('popup', lang);
const popEtag = etag(scripts.concat(ssvR).join('_'), { weak: true });
if (req.headers['if-none-match'] === popEtag) {
return { html: null, etag: popEtag };
}
const { t } = getTTag(lang);
@ -62,18 +69,18 @@ function generatePopUpPage(req) {
/>
<link rel="icon" href="/favicon.ico" type="image/x-icon" />
<link rel="apple-touch-icon" href="apple-touch-icon.png" />
<script>window.ssv=JSON.parse('${JSON.stringify(ssvR)}')</script>
<script>window.ssv=JSON.parse('${ssvR}')</script>
<link rel="stylesheet" type="text/css" id="globcss" href="${getCssAssets().default}" />
</head>
<body>
<div id="app" class="popup">
</div>
<script src="${script}"></script>
${scripts.map((script) => `<script src="${script}"></script>`).join('')}
</body>
</html>
`;
return html;
return { html, etag: popEtag };
}
export default generatePopUpPage;