server/server.js — added helmet with CSP configured to allow Google Fonts
Dockerfile — creates a non-root app user and runs the process under it server/routes.js — tailscale_ip validated against IPv4 regex (empty string still allowed) index.html — sql.js CDN script tag already removed earlier in this session
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
"permissions": {
|
||||
"allow": [
|
||||
"Bash(npm test:*)",
|
||||
"Bash(npm install:*)"
|
||||
"Bash(npm install:*)",
|
||||
"Bash(find /c/Users/josh1/Documents/Code/Catalyst -type f \\\\\\(-name *.test.js -o -name *.spec.js -o -name .env* -o -name *.config.js \\\\\\))"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
FROM node:lts-alpine
|
||||
RUN addgroup -S app && adduser -S app -G app
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
COPY package*.json ./
|
||||
@@ -8,5 +10,8 @@ COPY . .
|
||||
RUN awk -F'"' '/"version"/{printf "const VERSION = \"%s\";\n", $4; exit}' \
|
||||
package.json > js/version.js
|
||||
|
||||
RUN chown -R app:app /app
|
||||
USER app
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["node", "server/server.js"]
|
||||
|
||||
@@ -176,7 +176,6 @@
|
||||
<span id="toast-msg"></span>
|
||||
</div>
|
||||
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/sql.js/1.10.2/sql-wasm.js"></script>
|
||||
<script src="js/version.js" onerror="window.VERSION=null"></script>
|
||||
<script src="js/config.js"></script>
|
||||
<script src="js/db.js"></script>
|
||||
|
||||
16
package-lock.json
generated
16
package-lock.json
generated
@@ -1,14 +1,15 @@
|
||||
{
|
||||
"name": "catalyst",
|
||||
"version": "1.0.3",
|
||||
"version": "1.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "catalyst",
|
||||
"version": "1.0.3",
|
||||
"version": "1.1.0",
|
||||
"dependencies": {
|
||||
"express": "^4.18.0"
|
||||
"express": "^4.18.0",
|
||||
"helmet": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jsdom": "^25.0.0",
|
||||
@@ -1958,6 +1959,15 @@
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/helmet": {
|
||||
"version": "8.1.0",
|
||||
"resolved": "https://registry.npmjs.org/helmet/-/helmet-8.1.0.tgz",
|
||||
"integrity": "sha512-jOiHyAZsmnr8LqoPGmCjYAaiuWwjAPLgY8ZX2XrmHawt99/u1y6RgrZMTeoPfpUbV96HOalYgz1qzkRbw54Pmg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/html-encoding-sniffer": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "catalyst",
|
||||
"version": "1.1.0",
|
||||
"version": "1.1.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node server/server.js",
|
||||
@@ -9,7 +9,8 @@
|
||||
"version:write": "node -e \"const {version}=JSON.parse(require('fs').readFileSync('package.json','utf8'));require('fs').writeFileSync('js/version.js','const VERSION = \\\"'+version+'\\\";\\n');\""
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.0"
|
||||
"express": "^4.18.0",
|
||||
"helmet": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jsdom": "^25.0.0",
|
||||
|
||||
@@ -22,6 +22,9 @@ function validate(body) {
|
||||
errors.push(`state must be one of: ${VALID_STATES.join(', ')}`);
|
||||
if (!VALID_STACKS.includes(body.stack))
|
||||
errors.push(`stack must be one of: ${VALID_STACKS.join(', ')}`);
|
||||
const ip = (body.tailscale_ip ?? '').trim();
|
||||
if (ip && !/^(\d{1,3}\.){3}\d{1,3}$/.test(ip))
|
||||
errors.push('tailscale_ip must be a valid IPv4 address or empty');
|
||||
return errors;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import express from 'express';
|
||||
import helmet from 'helmet';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { dirname, join } from 'path';
|
||||
import { router } from './routes.js';
|
||||
@@ -8,6 +9,15 @@ const PORT = process.env.PORT ?? 3000;
|
||||
|
||||
export const app = express();
|
||||
|
||||
app.use(helmet({
|
||||
contentSecurityPolicy: {
|
||||
directives: {
|
||||
...helmet.contentSecurityPolicy.getDefaultDirectives(),
|
||||
'style-src': ["'self'", 'https://fonts.googleapis.com'],
|
||||
'font-src': ["'self'", 'https://fonts.gstatic.com'],
|
||||
},
|
||||
},
|
||||
}));
|
||||
app.use(express.json());
|
||||
|
||||
// API
|
||||
|
||||
Reference in New Issue
Block a user