Merge claude/2
This commit is contained in:
commit
1cead7fc89
45
containers/libreportal/backend/package-lock.json
generated
45
containers/libreportal/backend/package-lock.json
generated
@ -9,6 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^2.4.3",
|
||||
"compression": "^1.8.1",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"express": "^4.17.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
@ -130,6 +131,42 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/compressible": {
|
||||
"version": "2.0.18",
|
||||
"resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
|
||||
"integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
|
||||
"dependencies": {
|
||||
"mime-db": ">= 1.43.0 < 2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/compression": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz",
|
||||
"integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"compressible": "~2.0.18",
|
||||
"debug": "2.6.9",
|
||||
"negotiator": "~0.6.4",
|
||||
"on-headers": "~1.1.0",
|
||||
"safe-buffer": "5.2.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/compression/node_modules/negotiator": {
|
||||
"version": "0.6.4",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.4.tgz",
|
||||
"integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
@ -647,6 +684,14 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/on-headers": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
|
||||
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
"main": "server.js",
|
||||
"dependencies": {
|
||||
"bcryptjs": "^2.4.3",
|
||||
"compression": "^1.8.1",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"express": "^4.17.1",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
|
||||
@ -4,6 +4,15 @@ const cookieParser = require('cookie-parser');
|
||||
const config = require('./config.js');
|
||||
const { verifyToken } = require('./auth.js');
|
||||
|
||||
// compression is a new dependency (added to package.json). The Docker image
|
||||
// bakes node_modules at build time and routes/utils/server.js are bind-mounted
|
||||
// in compose.yml — but node_modules is NOT bind-mounted, so a "quick" deploy
|
||||
// (cp + restart) hits the old image without compression installed. We require
|
||||
// it defensively: present after the next image rebuild → ~70 % wire-size
|
||||
// reduction; absent → degrade silently to the previous uncompressed behaviour.
|
||||
let compression = null;
|
||||
try { compression = require('compression'); } catch (_) {}
|
||||
|
||||
function requireAuth(req, res, next) {
|
||||
const token = req.cookies?.libreportal_token;
|
||||
if (!token) return res.status(401).json({ error: 'Unauthorized' });
|
||||
@ -20,7 +29,32 @@ function noStore(req, res, next) {
|
||||
next();
|
||||
}
|
||||
|
||||
// Static-asset options:
|
||||
// - 1h maxAge + ETag on JS/CSS/icons so repeated nav skips a network
|
||||
// round-trip per file. ~25 script tags × ~5ms RTT each adds up otherwise.
|
||||
// - HTML files get Cache-Control: no-cache (still uses ETag, so revalidation
|
||||
// is cheap, but new deploys land immediately without waiting for cache
|
||||
// expiry — the SPA shell is the file most likely to change between deploys).
|
||||
// - dotfiles='ignore' so .auth.json is never served.
|
||||
const staticOptions = {
|
||||
maxAge: '1h',
|
||||
etag: true,
|
||||
dotfiles: 'ignore',
|
||||
setHeaders: (res, filePath) => {
|
||||
if (filePath.endsWith('.html')) {
|
||||
res.setHeader('Cache-Control', 'no-cache');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function setup(app) {
|
||||
// Gzip-compress responses. JS/CSS/HTML/JSON typically shrink ~70 %, so the
|
||||
// 1.7 MB of static assets the SPA loads on a cold cache drop to ~500 KB on
|
||||
// the wire. compression defaults skip already-compressed types (images,
|
||||
// gzipped tarballs) and small responses (<1 KB). Defensive — no-op if the
|
||||
// module isn't installed (image not yet rebuilt with the new dep).
|
||||
if (compression) app.use(compression());
|
||||
|
||||
app.use(express.json());
|
||||
app.use(cookieParser());
|
||||
|
||||
@ -31,12 +65,13 @@ function setup(app) {
|
||||
});
|
||||
|
||||
// /data/* requires auth. express.static doesn't generate directory listings,
|
||||
// so the only way to read anything is to know an exact path.
|
||||
// so the only way to read anything is to know an exact path. noStore wins
|
||||
// over staticOptions' maxAge for this prefix — auth-sensitive content
|
||||
// should never be cached.
|
||||
app.use('/data', requireAuth, noStore, express.static(path.join(config.FRONTEND_PATH, 'data')));
|
||||
|
||||
// All other static assets (js, css, icons, html partials, index.html) remain public.
|
||||
// dotfiles='ignore' by default so .auth.json is never served.
|
||||
app.use(express.static(config.FRONTEND_PATH));
|
||||
app.use(express.static(config.FRONTEND_PATH, staticOptions));
|
||||
}
|
||||
|
||||
module.exports = { setup, requireAuth };
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user