mirror of
https://github.com/siderolabs/omni.git
synced 2025-08-06 17:46:59 +02:00
fix: add more strict security headers to the web page handler
Some checks are pending
default / default (push) Waiting to run
default / e2e-backups (push) Blocked by required conditions
default / e2e-forced-removal (push) Blocked by required conditions
default / e2e-scaling (push) Blocked by required conditions
default / e2e-short (push) Blocked by required conditions
default / e2e-short-secureboot (push) Blocked by required conditions
default / e2e-templates (push) Blocked by required conditions
default / e2e-upgrades (push) Blocked by required conditions
default / e2e-workload-proxy (push) Blocked by required conditions
Some checks are pending
default / default (push) Waiting to run
default / e2e-backups (push) Blocked by required conditions
default / e2e-forced-removal (push) Blocked by required conditions
default / e2e-scaling (push) Blocked by required conditions
default / e2e-short (push) Blocked by required conditions
default / e2e-short-secureboot (push) Blocked by required conditions
default / e2e-templates (push) Blocked by required conditions
default / e2e-upgrades (push) Blocked by required conditions
default / e2e-workload-proxy (push) Blocked by required conditions
Enable `CSP`, `Referrer-Policy`, `X-Frame-Options`, `X-Content-Type-Options`, `Permissions-Policy` headers. `CSP` has broken the monaco editor, so had to drop the monaco vite plugin for production builds. Signed-off-by: Artem Chernyshev <artem.chernyshev@talos-systems.com>
This commit is contained in:
parent
57c005e5d0
commit
b91b673a00
@ -10,51 +10,51 @@
|
||||
"lint": "eslint ./src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@auth0/auth0-vue": "^2.3.3",
|
||||
"@auth0/auth0-vue": "^2.4.0",
|
||||
"@headlessui/vue": "^1.7.23",
|
||||
"@jsonforms/vue": "^3.4.1",
|
||||
"@jsonforms/vue-vanilla": "^3.4.1",
|
||||
"@kubernetes/client-node": "^0.22.2",
|
||||
"@jsonforms/vue": "^3.5.1",
|
||||
"@jsonforms/vue-vanilla": "^3.5.1",
|
||||
"@kubernetes/client-node": "^0.22.3",
|
||||
"apexcharts": "3.45.2",
|
||||
"click-outside-vue3": "^4.0.1",
|
||||
"core-js": "^3.39.0",
|
||||
"core-js": "^3.41.0",
|
||||
"js-yaml": "^4.1.0",
|
||||
"long": "^5.2.3",
|
||||
"long": "^5.3.1",
|
||||
"luxon": "^3.5.0",
|
||||
"monaco-editor": "^0.41.0",
|
||||
"monaco-yaml": "^5.2.3",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"monaco-yaml": "^5.3.1",
|
||||
"pluralize": "^8.0.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"semver-parser": "^4.1.6",
|
||||
"rxjs": "^7.8.2",
|
||||
"semver-parser": "^4.1.8",
|
||||
"uuid": "^10.0.0",
|
||||
"vue": "^3.5.12",
|
||||
"vue-router": "^4.4.5",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0",
|
||||
"vue-virtual-scroller": "^2.0.0-beta.8",
|
||||
"vue-word-highlighter": "^1.2.5",
|
||||
"vue3-apexcharts": "^1.7.0",
|
||||
"vue3-apexcharts": "^1.8.0",
|
||||
"vue3-popper": "^1.5.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@heroicons/vue": "^2.1.5",
|
||||
"@heroicons/vue": "^2.2.0",
|
||||
"@types/luxon": "^3.4.2",
|
||||
"@types/node": "^20.17.6",
|
||||
"@types/node": "^20.17.24",
|
||||
"@types/pluralize": "^0.0.33",
|
||||
"@vitejs/plugin-vue": "^5.1.4",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"@vitejs/plugin-vue": "^5.2.3",
|
||||
"autoprefixer": "^10.4.21",
|
||||
"eslint-plugin-typescript": "^0.14.0",
|
||||
"eslint-plugin-vue": "^9.30.0",
|
||||
"eslint-plugin-vue": "^9.33.0",
|
||||
"fetch-intercept": "^2.4.0",
|
||||
"jsdom": "^25.0.1",
|
||||
"lodash": "^4.17.21",
|
||||
"openpgp": "^5.11.2",
|
||||
"postcss": "^8.4.47",
|
||||
"tailwindcss": "^3.4.14",
|
||||
"typescript": "^5.6.3",
|
||||
"typescript-eslint": "^8.13.0",
|
||||
"vite": "^5.4.10",
|
||||
"postcss": "^8.5.3",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript-eslint": "^8.26.1",
|
||||
"vite": "^5.4.14",
|
||||
"vite-plugin-monaco-editor": "^1.1.0",
|
||||
"vite-plugin-node-polyfills": "^0.22.0",
|
||||
"vue-tsc": "^2.1.10",
|
||||
"vue-tsc": "^2.2.8",
|
||||
"vue3-clipboard": "^1.0.0",
|
||||
"whatwg-fetch": "^3.6.20"
|
||||
}
|
||||
|
@ -201,4 +201,8 @@ monaco.editor.defineTheme("sidero", {
|
||||
.editor h4 {
|
||||
@apply font-bold;
|
||||
}
|
||||
|
||||
.monaco-editor {
|
||||
outline: 0;
|
||||
}
|
||||
</style>
|
||||
|
@ -10,6 +10,7 @@ import VueClipboard from 'vue3-clipboard';
|
||||
import AppUnavailable from '@/AppUnavailable.vue'
|
||||
import router from '@/router';
|
||||
|
||||
|
||||
import { initState, ResourceService, Resource } from "@/api/grpc";
|
||||
import { AuthConfigID, AuthConfigType, DefaultNamespace } from "@/api/resources";
|
||||
import { Runtime } from "@/api/common/omni.pb";
|
||||
@ -17,7 +18,21 @@ import { AuthConfigSpec } from "@/api/omni/specs/auth.pb";
|
||||
import { AuthType, authType, suspended } from "@/methods";
|
||||
import { createAuth0 } from "@auth0/auth0-vue";
|
||||
import { withRuntime } from "./api/options";
|
||||
import vClickOutside from "click-outside-vue3"
|
||||
import vClickOutside from "click-outside-vue3";
|
||||
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker';
|
||||
import yamlWorker from 'monaco-yaml/yaml.worker?worker';
|
||||
|
||||
if (process.env.NODE_ENV !== 'development') {
|
||||
(self as any).MonacoEnvironment = {
|
||||
getWorker(_: string, label: string) {
|
||||
if (label === 'yaml') {
|
||||
return new yamlWorker();
|
||||
}
|
||||
|
||||
return new editorWorker();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const setupApp = async () => {
|
||||
let authConfigSpec: AuthConfigSpec | undefined = undefined
|
||||
@ -68,4 +83,4 @@ const setupApp = async () => {
|
||||
|
||||
initState();
|
||||
|
||||
setupApp()
|
||||
setupApp();
|
||||
|
@ -75,7 +75,7 @@ export class LineDelimitedLogParser {
|
||||
}
|
||||
}
|
||||
|
||||
export const setupLogStream = <R extends Data, T>(logs: Ref<LogLine[]>, method: StreamingRequest<R, T>, params: T | ComputedRef<T> | Ref<T>, logParser: LogParser = new DefaultLogParser((l: string): LogLine => { return {msg: l} }), ...options: fetchOption[]): Ref<Stream<R, T> | undefined> => {
|
||||
export const setupLogStream = <R extends Data, T>(logs: Ref<LogLine[]>, method: StreamingRequest<R, T>, params: T | ComputedRef<T | undefined> | Ref<T>, logParser: LogParser = new DefaultLogParser((l: string): LogLine => { return {msg: l} }), ...options: fetchOption[]): Ref<Stream<R, T> | undefined> => {
|
||||
const stream: Ref<Stream<R, T> | undefined> = ref();
|
||||
let buffer: LogLine[] = [];
|
||||
let flush: NodeJS.Timeout | undefined;
|
||||
@ -97,6 +97,10 @@ export const setupLogStream = <R extends Data, T>(logs: Ref<LogLine[]>, method:
|
||||
|
||||
const p = isRef(params) ? params.value : params;
|
||||
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
|
||||
stream.value = subscribe(
|
||||
method,
|
||||
p,
|
||||
|
@ -108,7 +108,11 @@ const plainText = (line: string) => {
|
||||
};
|
||||
}
|
||||
|
||||
const params = computed<LogsRequest>(() => {
|
||||
const params = computed<LogsRequest | undefined>(() => {
|
||||
if (route.params.service === "machine") {
|
||||
return;
|
||||
}
|
||||
|
||||
return {
|
||||
namespace: "system",
|
||||
id: service.value,
|
||||
@ -134,7 +138,7 @@ watch(() => route.params.service, () => {
|
||||
|
||||
logParser.setLineParser(getLineParser(svc));
|
||||
service.value = svc;
|
||||
})
|
||||
});
|
||||
|
||||
const stream = setupLogStream(logs, MachineService.Logs, params, logParser, withRuntime(Runtime.Talos), withContext(context));
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
/// <reference types="vitest" />
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import { defineConfig, UserConfig } from 'vite'
|
||||
import { fileURLToPath, URL } from 'node:url'
|
||||
import { nodePolyfills } from 'vite-plugin-node-polyfills'
|
||||
import monacoEditorPlugin from 'vite-plugin-monaco-editor'
|
||||
@ -13,19 +13,11 @@ import monacoEditorPlugin from 'vite-plugin-monaco-editor'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
export default defineConfig(({ command }) => {
|
||||
const config: UserConfig = {
|
||||
plugins: [
|
||||
vue(),
|
||||
nodePolyfills({ include: ['stream'] }),
|
||||
monacoEditorPlugin({
|
||||
languageWorkers: ['editorWorkerService'],
|
||||
customWorkers: [
|
||||
{
|
||||
label: 'yaml',
|
||||
entry: 'monaco-yaml/yaml.worker'
|
||||
}
|
||||
]
|
||||
})
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
@ -36,7 +28,19 @@ export default defineConfig({
|
||||
port: 8121,
|
||||
host: "127.0.0.1"
|
||||
},
|
||||
test: {
|
||||
exclude: [],
|
||||
},
|
||||
};
|
||||
|
||||
if (command === 'serve') {
|
||||
config.plugins?.push(monacoEditorPlugin({
|
||||
languageWorkers: ['editorWorkerService'],
|
||||
customWorkers: [
|
||||
{
|
||||
label: 'yaml',
|
||||
entry: 'monaco-yaml/yaml.worker'
|
||||
}
|
||||
]
|
||||
}));
|
||||
}
|
||||
|
||||
return config;
|
||||
})
|
||||
|
@ -102,12 +102,29 @@ func (handler *StaticHandler) serveFile(w http.ResponseWriter, r *http.Request,
|
||||
return
|
||||
}
|
||||
|
||||
defer file.Close() //nolint:errcheck
|
||||
|
||||
if path != index {
|
||||
w.Header().Set("Vary", "Accept-Encoding, User-Agent")
|
||||
w.Header().Set("Cache-Control", fmt.Sprintf("public, max-age=%d, immutable", handler.maxAgeSec))
|
||||
}
|
||||
} else {
|
||||
w.Header().Set("Referrer-Policy", "strict-origin-when-cross-origin")
|
||||
|
||||
defer file.Close() //nolint:errcheck
|
||||
w.Header().Set("Content-Security-Policy", "default-src 'self'; img-src * data: ; "+
|
||||
";connect-src 'self' https://*.auth0.com ;font-src 'self' data: "+
|
||||
";style-src 'self' 'unsafe-inline' https://fonts.googleapis.com data: ;upgrade-insecure-requests;"+
|
||||
";frame-src https://*.auth0.com",
|
||||
)
|
||||
|
||||
w.Header().Set("X-Frame-Options", "SAMEORIGIN")
|
||||
w.Header().Set("X-Content-Type-Options", "nosniff")
|
||||
w.Header().Set("Permissions-Policy", "accelerometer=(), ambient-light-sensor=(), "+
|
||||
"autoplay=(self), battery=(), camera=(), cross-origin-isolated=(self), display-capture=(), "+
|
||||
"document-domain=(), encrypted-media=(), fullscreen=(self), geolocation=(), gyroscope=(), "+
|
||||
"magnetometer=(), microphone=(), midi=(), payment=(), picture-in-picture=(), publickey-credentials=(self),"+
|
||||
"screen-wake-lock=(), sync-xhr=(self), usb=(), web-share=(), xr-spatial-tracking=()",
|
||||
)
|
||||
}
|
||||
|
||||
http.ServeContent(w, r, file.Name(), handler.modTime, file)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user