Files
tkmind_go/ui/desktop/src/utils/csp.ts
T

76 lines
2.2 KiB
TypeScript

import type { ExternalGoosedConfig } from './settings';
const DEFAULT_CONNECT_SOURCES = [
"'self'",
'http://127.0.0.1:*',
'https://127.0.0.1:*',
'http://localhost:*',
'https://localhost:*',
'https://api.github.com',
'https://github.com',
'https://objects.githubusercontent.com',
];
export function buildConnectSrc(externalGoosed?: ExternalGoosedConfig): string {
const sources = [...DEFAULT_CONNECT_SOURCES];
if (externalGoosed?.enabled && externalGoosed.url) {
try {
const externalUrl = new URL(externalGoosed.url);
sources.push(externalUrl.origin);
} catch {
console.warn('Invalid external goosed URL in settings, skipping CSP entry');
}
}
return sources.join(' ');
}
/**
* Returns true when upgrade-insecure-requests should be included in the CSP.
*
* The directive is omitted when the user has configured an external backend
* that uses plain HTTP, because Chromium would silently rewrite those
* requests to HTTPS. The remote server typically does not speak TLS, so the
* upgraded requests fail with "Failed to fetch".
*
* Loopback addresses (127.0.0.1 / localhost) are exempt from the upgrade
* per the CSP spec, which is why the built-in local backend is unaffected.
*/
export function shouldUpgradeInsecureRequests(externalGoosed?: ExternalGoosedConfig): boolean {
if (!externalGoosed?.enabled || !externalGoosed.url) {
return true;
}
try {
const parsed = new URL(externalGoosed.url);
return parsed.protocol !== 'http:';
} catch {
return true;
}
}
export function buildCSP(externalGoosed?: ExternalGoosedConfig): string {
const connectSrc = buildConnectSrc(externalGoosed);
const upgradeDirective = shouldUpgradeInsecureRequests(externalGoosed)
? 'upgrade-insecure-requests;'
: '';
return (
"default-src 'self';" +
"style-src 'self' 'unsafe-inline';" +
"script-src 'self' 'unsafe-inline';" +
"img-src 'self' data: https:;" +
`connect-src ${connectSrc};` +
"object-src 'none';" +
"frame-src 'self' https: http:;" +
"font-src 'self' data: https:;" +
"media-src 'self' mediastream:;" +
"form-action 'none';" +
"base-uri 'self';" +
"manifest-src 'self';" +
"worker-src 'self';" +
upgradeDirective
);
}