chore(desktop): remove leftover goosed string references (#10464)
Signed-off-by: Abhijay Jain <Abhijay007j@gmail.com>
This commit is contained in:
@@ -3,7 +3,7 @@ import { Switch } from '../../ui/switch';
|
||||
import { Input } from '../../ui/input';
|
||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '../../ui/card';
|
||||
import { AlertCircle } from 'lucide-react';
|
||||
import { ExternalGoosedConfig, defaultSettings } from '../../../utils/settings';
|
||||
import { ExternalBackendConfig, defaultSettings } from '../../../utils/settings';
|
||||
import { defineMessages, useIntl } from '../../../i18n';
|
||||
import { normalizeAcpHttpBaseUrl } from '../../../acp/url';
|
||||
|
||||
@@ -56,12 +56,12 @@ const i18n = defineMessages({
|
||||
},
|
||||
certFingerprintHelp: {
|
||||
id: 'externalBackendSection.certFingerprintHelp',
|
||||
defaultMessage: 'Pin a specific TLS certificate fingerprint. If omitted, the certificate is trusted on first use (TOFU).',
|
||||
defaultMessage:
|
||||
'Pin a specific TLS certificate fingerprint. If omitted, the certificate is trusted on first use (TOFU).',
|
||||
},
|
||||
restartNote: {
|
||||
id: 'externalBackendSection.restartNote',
|
||||
defaultMessage:
|
||||
'Changes apply to new chat windows. Restart Goose to update existing windows.',
|
||||
defaultMessage: 'Changes apply to new chat windows. Restart Goose to update existing windows.',
|
||||
},
|
||||
urlProtocolError: {
|
||||
id: 'externalBackendSection.urlProtocolError',
|
||||
@@ -77,13 +77,14 @@ const i18n = defineMessages({
|
||||
},
|
||||
urlBaseError: {
|
||||
id: 'externalBackendSection.urlBaseError',
|
||||
defaultMessage: 'URL must be the backend base URL before /acp, without query parameters or fragments',
|
||||
defaultMessage:
|
||||
'URL must be the backend base URL before /acp, without query parameters or fragments',
|
||||
},
|
||||
});
|
||||
|
||||
export default function ExternalBackendSection() {
|
||||
const intl = useIntl();
|
||||
const [config, setConfig] = useState<ExternalGoosedConfig>(defaultSettings.externalGoosed);
|
||||
const [config, setConfig] = useState<ExternalBackendConfig>(defaultSettings.externalGoosed);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [urlError, setUrlError] = useState<string | null>(null);
|
||||
|
||||
@@ -95,10 +96,7 @@ export default function ExternalBackendSection() {
|
||||
loadSettings();
|
||||
}, []);
|
||||
|
||||
const validateUrl = (
|
||||
value: string,
|
||||
certFingerprint = config.certFingerprint
|
||||
): boolean => {
|
||||
const validateUrl = (value: string, certFingerprint = config.certFingerprint): boolean => {
|
||||
if (!value) {
|
||||
setUrlError(null);
|
||||
return true;
|
||||
@@ -128,7 +126,7 @@ export default function ExternalBackendSection() {
|
||||
}
|
||||
};
|
||||
|
||||
const saveConfig = async (newConfig: ExternalGoosedConfig): Promise<void> => {
|
||||
const saveConfig = async (newConfig: ExternalBackendConfig): Promise<void> => {
|
||||
setIsSaving(true);
|
||||
try {
|
||||
await window.electron.setSetting('externalGoosed', newConfig);
|
||||
@@ -139,9 +137,9 @@ export default function ExternalBackendSection() {
|
||||
}
|
||||
};
|
||||
|
||||
const updateField = <K extends keyof ExternalGoosedConfig>(
|
||||
const updateField = <K extends keyof ExternalBackendConfig>(
|
||||
field: K,
|
||||
value: ExternalGoosedConfig[K]
|
||||
value: ExternalBackendConfig[K]
|
||||
) => {
|
||||
const newConfig = { ...config, [field]: value };
|
||||
setConfig(newConfig);
|
||||
@@ -175,14 +173,14 @@ export default function ExternalBackendSection() {
|
||||
<Card className="pb-2">
|
||||
<CardHeader className="pb-0">
|
||||
<CardTitle>{intl.formatMessage(i18n.title)}</CardTitle>
|
||||
<CardDescription>
|
||||
{intl.formatMessage(i18n.description)}
|
||||
</CardDescription>
|
||||
<CardDescription>{intl.formatMessage(i18n.description)}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-4 space-y-4 px-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h3 className="text-text-primary text-xs">{intl.formatMessage(i18n.useExternalServer)}</h3>
|
||||
<h3 className="text-text-primary text-xs">
|
||||
{intl.formatMessage(i18n.useExternalServer)}
|
||||
</h3>
|
||||
<p className="text-xs text-text-secondary max-w-md mt-[2px]">
|
||||
{intl.formatMessage(i18n.useExternalServerDescription)}
|
||||
</p>
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Geheimer Schlüssel"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "Der auf dem goosed-Server konfigurierte geheime Schlüssel (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "Der auf dem Goose-Server konfigurierte geheime Schlüssel (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Geben Sie den geheimen Schlüssel des Servers ein"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Secret Key"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "La secret key configurada en el servidor goosed (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "La clave secreta configurada en el servidor Goose (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Introduce la secret key del servidor"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Clé secrète"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "La clé secrète configurée sur le serveur goosed (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "La clé secrète configurée sur le serveur Goose (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Saisissez la clé secrète du serveur"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Kunci Rahasia"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "Kunci rahasia yang dikonfigurasi pada server goosed (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "Kunci rahasia yang dikonfigurasi pada server Goose (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Masukkan kunci rahasia server"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Chiave segreta"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "La chiave segreta configurata sul server goosed (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "La chiave segreta configurata sul server Goose (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Inserisci la chiave segreta del server"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "シークレットキー"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "goosed サーバーに設定されたシークレットキー(GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "Goose サーバーに設定されたシークレットキー(GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "サーバーのシークレットキーを入力"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "비밀 키"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "goosed 서버에 설정된 비밀 키 (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "Goose 서버에 설정된 비밀 키 (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "서버의 비밀 키를 입력하세요"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Kunci Rahsia"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "Kunci rahsia yang dikonfigurasikan pada pelayan goosed (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "Kunci rahsia yang dikonfigurasikan pada pelayan Goose (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Masukkan kunci rahsia pelayan"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Chave secreta"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "A chave secreta configurada no servidor goosed (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "A chave secreta configurada no servidor Goose (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Insira a chave secreta do servidor"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Секретный ключ"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "Секретный ключ, настроенный на сервере goosed (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "Секретный ключ, настроенный на сервере Goose (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Введите секретный ключ сервера"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Gizli Anahtar"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "goosed sunucusunda yapılandırılan gizli anahtar (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "Goose sunucusunda yapılandırılan gizli anahtar (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Sunucunun gizli anahtarını girin"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "Khóa bí mật"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "Khóa bí mật được cấu hình trên máy chủ goosed (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "Khóa bí mật được cấu hình trên máy chủ Goose (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "Nhập khóa bí mật của máy chủ"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "密钥"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "在 goosed 服务器上配置的密钥(GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "在 Goose 服务器上配置的密钥(GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "输入服务器的密钥"
|
||||
|
||||
@@ -1197,7 +1197,7 @@
|
||||
"defaultMessage": "密鑰"
|
||||
},
|
||||
"externalBackendSection.secretKeyHelp": {
|
||||
"defaultMessage": "在 goosed 伺服器上設定的密鑰 (GOOSE_SERVER__SECRET_KEY)"
|
||||
"defaultMessage": "在 Goose 伺服器上設定的密鑰 (GOOSE_SERVER__SECRET_KEY)"
|
||||
},
|
||||
"externalBackendSection.secretKeyPlaceholder": {
|
||||
"defaultMessage": "輸入伺服器的密鑰"
|
||||
|
||||
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
import { afterEach, describe, expect, it } from 'vitest';
|
||||
import { createGooseServeStartupDiagnostics, createStartupDiagnostics } from './startupDiagnostics';
|
||||
import { createGooseServeStartupDiagnostics } from './startupDiagnostics';
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
|
||||
@@ -22,36 +22,6 @@ describe('startup diagnostics', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('keeps goosed startup diagnostics shape and file prefix', () => {
|
||||
const diagnosticsDir = makeTempDir();
|
||||
const trace = createStartupDiagnostics(diagnosticsDir, '/tmp/project');
|
||||
const expectedKeys = [
|
||||
'attemptId',
|
||||
'startedAt',
|
||||
'goosedPath',
|
||||
'workingDir',
|
||||
'baseUrl',
|
||||
'pid',
|
||||
'certFingerprintSeen',
|
||||
'healthCheckSucceeded',
|
||||
'childExitCode',
|
||||
'childExitSignal',
|
||||
'stderrTail',
|
||||
'events',
|
||||
];
|
||||
|
||||
expect(trace).not.toBeNull();
|
||||
expect(path.basename(trace!.diagnosticsPath)).toMatch(/^goosed-startup-.*\.json$/);
|
||||
expect(Object.keys(trace!.diagnostics)).toEqual(expectedKeys);
|
||||
expect(trace!.diagnostics).toMatchObject({
|
||||
goosedPath: null,
|
||||
baseUrl: null,
|
||||
certFingerprintSeen: false,
|
||||
});
|
||||
const saved = JSON.parse(fs.readFileSync(trace!.diagnosticsPath, 'utf8'));
|
||||
expect(Object.keys(saved)).toEqual(expectedKeys);
|
||||
});
|
||||
|
||||
it('writes serve startup diagnostics with serve-specific fields', () => {
|
||||
const diagnosticsDir = makeTempDir();
|
||||
const trace = createGooseServeStartupDiagnostics(diagnosticsDir, '/tmp/project');
|
||||
|
||||
@@ -8,21 +8,6 @@ export interface StartupTraceEvent {
|
||||
details?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface StartupDiagnostics {
|
||||
attemptId: string;
|
||||
startedAt: string;
|
||||
goosedPath: string | null;
|
||||
workingDir: string;
|
||||
baseUrl: string | null;
|
||||
pid: number | null;
|
||||
certFingerprintSeen: boolean;
|
||||
healthCheckSucceeded: boolean;
|
||||
childExitCode: number | null;
|
||||
childExitSignal: string | null;
|
||||
stderrTail: string[];
|
||||
events: StartupTraceEvent[];
|
||||
}
|
||||
|
||||
export interface GooseServeStartupDiagnostics {
|
||||
attemptId: string;
|
||||
startedAt: string;
|
||||
@@ -41,13 +26,6 @@ export interface GooseServeStartupDiagnostics {
|
||||
events: StartupTraceEvent[];
|
||||
}
|
||||
|
||||
export interface StartupTrace {
|
||||
diagnosticsPath: string;
|
||||
diagnostics: StartupDiagnostics;
|
||||
record: (name: string, details?: Record<string, unknown>) => void;
|
||||
flush: () => void;
|
||||
}
|
||||
|
||||
export interface GooseServeStartupTrace {
|
||||
diagnosticsPath: string;
|
||||
diagnostics: GooseServeStartupDiagnostics;
|
||||
@@ -65,27 +43,6 @@ export const appendTail = (target: string[], lines: string[]) => {
|
||||
}
|
||||
};
|
||||
|
||||
const cleanupStartupDiagnostics = (diagnosticsDir: string) => {
|
||||
const startupLogs = fs
|
||||
.readdirSync(diagnosticsDir, { withFileTypes: true })
|
||||
.filter(
|
||||
(entry) =>
|
||||
entry.isFile() && entry.name.startsWith('goosed-startup-') && entry.name.endsWith('.json')
|
||||
)
|
||||
.map((entry) => {
|
||||
const filePath = path.join(diagnosticsDir, entry.name);
|
||||
return {
|
||||
filePath,
|
||||
modifiedMs: fs.statSync(filePath).mtimeMs,
|
||||
};
|
||||
})
|
||||
.sort((a, b) => b.modifiedMs - a.modifiedMs);
|
||||
|
||||
for (const startupLog of startupLogs.slice(STARTUP_LOGS_TO_KEEP)) {
|
||||
fs.unlinkSync(startupLog.filePath);
|
||||
}
|
||||
};
|
||||
|
||||
const cleanupGooseServeStartupDiagnostics = (diagnosticsDir: string) => {
|
||||
const startupLogs = fs
|
||||
.readdirSync(diagnosticsDir, { withFileTypes: true })
|
||||
@@ -109,63 +66,6 @@ const cleanupGooseServeStartupDiagnostics = (diagnosticsDir: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const createStartupDiagnostics = (
|
||||
diagnosticsDir: string | undefined,
|
||||
workingDir: string
|
||||
): StartupTrace | null => {
|
||||
if (!diagnosticsDir) {
|
||||
return null;
|
||||
}
|
||||
|
||||
fs.mkdirSync(diagnosticsDir, { recursive: true });
|
||||
cleanupStartupDiagnostics(diagnosticsDir);
|
||||
const startedAt = new Date();
|
||||
const attemptId = `goosed-startup-${startedAt.toISOString().replace(/:/g, '-')}-${process.pid}.json`;
|
||||
const diagnosticsPath = path.join(diagnosticsDir, attemptId);
|
||||
const monotonicStart = Date.now();
|
||||
|
||||
const diagnostics: StartupDiagnostics = {
|
||||
attemptId,
|
||||
startedAt: startedAt.toISOString(),
|
||||
goosedPath: null,
|
||||
workingDir,
|
||||
baseUrl: null,
|
||||
pid: null,
|
||||
certFingerprintSeen: false,
|
||||
healthCheckSucceeded: false,
|
||||
childExitCode: null,
|
||||
childExitSignal: null,
|
||||
stderrTail: [],
|
||||
events: [],
|
||||
};
|
||||
|
||||
const flush = () => {
|
||||
fs.writeFileSync(diagnosticsPath, `${JSON.stringify(diagnostics, null, 2)}\n`);
|
||||
};
|
||||
|
||||
const record = (name: string, details?: Record<string, unknown>) => {
|
||||
if (name === 'healthcheck_success') {
|
||||
diagnostics.healthCheckSucceeded = true;
|
||||
}
|
||||
diagnostics.events.push({
|
||||
name,
|
||||
at: new Date().toISOString(),
|
||||
elapsedMs: Date.now() - monotonicStart,
|
||||
...(details ? { details } : {}),
|
||||
});
|
||||
flush();
|
||||
};
|
||||
|
||||
flush();
|
||||
|
||||
return {
|
||||
diagnosticsPath,
|
||||
diagnostics,
|
||||
record,
|
||||
flush,
|
||||
};
|
||||
};
|
||||
|
||||
export const createGooseServeStartupDiagnostics = (
|
||||
diagnosticsDir: string | undefined,
|
||||
workingDir: string
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { buildConnectSrc, shouldUpgradeInsecureRequests, buildCSP } from '../csp';
|
||||
import type { ExternalGoosedConfig } from '../settings';
|
||||
import type { ExternalBackendConfig } from '../settings';
|
||||
|
||||
describe('buildConnectSrc', () => {
|
||||
it('includes default sources when no external backend is configured', () => {
|
||||
@@ -11,7 +11,7 @@ describe('buildConnectSrc', () => {
|
||||
});
|
||||
|
||||
it('includes external backend origin when enabled', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'http://dev.company.net:12604',
|
||||
secret: 'test',
|
||||
@@ -22,7 +22,7 @@ describe('buildConnectSrc', () => {
|
||||
});
|
||||
|
||||
it('includes external secure WebSocket origin for HTTPS backends', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'https://secure.company.net:12604',
|
||||
secret: 'test',
|
||||
@@ -33,7 +33,7 @@ describe('buildConnectSrc', () => {
|
||||
});
|
||||
|
||||
it('does not include external origin when disabled', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: false,
|
||||
url: 'http://dev.company.net:12604',
|
||||
secret: 'test',
|
||||
@@ -43,7 +43,7 @@ describe('buildConnectSrc', () => {
|
||||
});
|
||||
|
||||
it('handles invalid URLs gracefully', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'not-a-valid-url',
|
||||
secret: 'test',
|
||||
@@ -60,7 +60,7 @@ describe('shouldUpgradeInsecureRequests', () => {
|
||||
});
|
||||
|
||||
it('returns true when external backend is disabled', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: false,
|
||||
url: 'http://dev.company.net:12604',
|
||||
secret: 'test',
|
||||
@@ -69,7 +69,7 @@ describe('shouldUpgradeInsecureRequests', () => {
|
||||
});
|
||||
|
||||
it('returns false when external backend uses HTTP', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'http://dev.company.net:12604',
|
||||
secret: 'test',
|
||||
@@ -78,7 +78,7 @@ describe('shouldUpgradeInsecureRequests', () => {
|
||||
});
|
||||
|
||||
it('returns true when external backend uses HTTPS', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'https://dev.company.net:12604',
|
||||
secret: 'test',
|
||||
@@ -87,7 +87,7 @@ describe('shouldUpgradeInsecureRequests', () => {
|
||||
});
|
||||
|
||||
it('returns true for invalid URLs', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'not-a-url',
|
||||
secret: 'test',
|
||||
@@ -96,7 +96,7 @@ describe('shouldUpgradeInsecureRequests', () => {
|
||||
});
|
||||
|
||||
it('returns true when URL is empty', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: '',
|
||||
secret: 'test',
|
||||
@@ -112,7 +112,7 @@ describe('buildCSP', () => {
|
||||
});
|
||||
|
||||
it('includes upgrade-insecure-requests with HTTPS external backend', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'https://secure.company.net:12604',
|
||||
secret: 'test',
|
||||
@@ -123,7 +123,7 @@ describe('buildCSP', () => {
|
||||
});
|
||||
|
||||
it('excludes upgrade-insecure-requests with HTTP external backend', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'http://dev.company.net:12604',
|
||||
secret: 'test',
|
||||
@@ -134,7 +134,7 @@ describe('buildCSP', () => {
|
||||
});
|
||||
|
||||
it('always includes core directives', () => {
|
||||
const config: ExternalGoosedConfig = {
|
||||
const config: ExternalBackendConfig = {
|
||||
enabled: true,
|
||||
url: 'http://dev.company.net:12604',
|
||||
secret: 'test',
|
||||
|
||||
+11
-11
@@ -1,4 +1,4 @@
|
||||
import type { ExternalGoosedConfig } from './settings';
|
||||
import type { ExternalBackendConfig } from './settings';
|
||||
|
||||
const DEFAULT_CONNECT_SOURCES = [
|
||||
"'self'",
|
||||
@@ -15,17 +15,17 @@ const DEFAULT_CONNECT_SOURCES = [
|
||||
'https://objects.githubusercontent.com',
|
||||
];
|
||||
|
||||
export function buildConnectSrc(externalGoosed?: ExternalGoosedConfig): string {
|
||||
export function buildConnectSrc(externalBackend?: ExternalBackendConfig): string {
|
||||
const sources = [...DEFAULT_CONNECT_SOURCES];
|
||||
|
||||
if (externalGoosed?.enabled && externalGoosed.url) {
|
||||
if (externalBackend?.enabled && externalBackend.url) {
|
||||
try {
|
||||
const externalUrl = new URL(externalGoosed.url);
|
||||
const externalUrl = new URL(externalBackend.url);
|
||||
sources.push(externalUrl.origin);
|
||||
externalUrl.protocol = externalUrl.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
sources.push(externalUrl.origin);
|
||||
} catch {
|
||||
console.warn('Invalid external goosed URL in settings, skipping CSP entry');
|
||||
console.warn('Invalid external backend URL in settings, skipping CSP entry');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,22 +43,22 @@ export function buildConnectSrc(externalGoosed?: ExternalGoosedConfig): string {
|
||||
* 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) {
|
||||
export function shouldUpgradeInsecureRequests(externalBackend?: ExternalBackendConfig): boolean {
|
||||
if (!externalBackend?.enabled || !externalBackend.url) {
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = new URL(externalGoosed.url);
|
||||
const parsed = new URL(externalBackend.url);
|
||||
return parsed.protocol !== 'http:';
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function buildCSP(externalGoosed?: ExternalGoosedConfig): string {
|
||||
const connectSrc = buildConnectSrc(externalGoosed);
|
||||
const upgradeDirective = shouldUpgradeInsecureRequests(externalGoosed)
|
||||
export function buildCSP(externalBackend?: ExternalBackendConfig): string {
|
||||
const connectSrc = buildConnectSrc(externalBackend);
|
||||
const upgradeDirective = shouldUpgradeInsecureRequests(externalBackend)
|
||||
? 'upgrade-insecure-requests;'
|
||||
: '';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export interface ExternalGoosedConfig {
|
||||
export interface ExternalBackendConfig {
|
||||
enabled: boolean;
|
||||
url: string;
|
||||
secret: string;
|
||||
@@ -36,7 +36,8 @@ export interface Settings {
|
||||
enableWakelock: boolean;
|
||||
enableNotifications: boolean;
|
||||
spellcheckEnabled: boolean;
|
||||
externalGoosed: ExternalGoosedConfig;
|
||||
// Key is kept as `externalGoosed` for backward compat with persisted user settings.
|
||||
externalGoosed: ExternalBackendConfig;
|
||||
globalShortcut?: string | null;
|
||||
keyboardShortcuts: KeyboardShortcuts;
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export async function ensureWinShims(): Promise<void> {
|
||||
try {
|
||||
await fs.promises.mkdir(tgtDir, { recursive: true });
|
||||
|
||||
// Copy command-line tools, NOT goosed.exe (which should always be used locally)
|
||||
// Copy command-line tools only; the goose binary is never shimmed
|
||||
const shims = ['uvx.exe', 'uv.exe', 'npx.cmd'];
|
||||
|
||||
await Promise.all(
|
||||
|
||||
Reference in New Issue
Block a user