Skip to content

Commit 660399d

Browse files
authored
fix: Cloud sign-in fails when user is behind a network proxy (#756)
1 parent b35b9ea commit 660399d

File tree

8 files changed

+81
-0
lines changed

8 files changed

+81
-0
lines changed

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@
138138
"tiny-invariant": "^1.3.3",
139139
"tree-kill": "^1.2.2",
140140
"typescript": "^5.4.5",
141+
"undici": "^7.10.0",
141142
"update-electron-app": "^3.0.0",
142143
"use-konami": "^1.0.1",
143144
"webextension-polyfill": "^0.12.0",

src/main.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { getSettings, initSettings } from './main/settings'
1919
import { closeWatcher, configureWatcher } from './main/watcher'
2020
import { showWindow, trackWindowState } from './main/window'
2121
import { BrowserServer } from './services/browser/server'
22+
import { configureSystemProxy } from './services/http'
2223
import { ProxyStatus } from './types'
2324
import { sendReport } from './usageReport'
2425
import { getAppIcon, getPlatform } from './utils/electron'
@@ -136,6 +137,9 @@ const createWindow = async () => {
136137
mainWindow.webContents.send(ProxyHandler.ChangeStatus, status)
137138
})
138139

140+
// Configure proxy settings for `fetch`.
141+
await configureSystemProxy()
142+
139143
// Start proxy
140144
k6StudioState.currentProxyProcess =
141145
await launchProxyAndAttachEmitter(mainWindow)

src/main/settings.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { existsSync, readFileSync } from 'fs'
44
import { writeFile, open } from 'fs/promises'
55
import path from 'node:path'
66

7+
import { configureSystemProxy } from '@/services/http'
8+
79
import { AppSettingsSchema } from '../schemas/settings'
810
import { AppSettings } from '../types/settings'
911
import { getPlatform } from '../utils/electron'
@@ -177,16 +179,22 @@ export async function applySettings(
177179
) {
178180
if (modifiedSettings.proxy) {
179181
await stopProxyProcess()
182+
180183
k6StudioState.appSettings.proxy = modifiedSettings.proxy
181184
k6StudioState.currentProxyProcess =
182185
await launchProxyAndAttachEmitter(browserWindow)
186+
187+
await configureSystemProxy()
183188
}
189+
184190
if (modifiedSettings.recorder) {
185191
k6StudioState.appSettings.recorder = modifiedSettings.recorder
186192
}
193+
187194
if (modifiedSettings.telemetry) {
188195
k6StudioState.appSettings.telemetry = modifiedSettings.telemetry
189196
}
197+
190198
if (modifiedSettings.appearance) {
191199
k6StudioState.appSettings.appearance = modifiedSettings.appearance
192200
nativeTheme.themeSource = k6StudioState.appSettings.appearance.theme

src/schemas/settings/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ export {
3333
RecorderSettingsSchema,
3434
TelemetrySchema,
3535
WindowStateSchema,
36+
type UpstreamProxySettings,
3637
} from './v3'

src/schemas/settings/v1/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,4 +125,5 @@ export function migrate(
125125
}
126126
}
127127

128+
export type UpstreamProxySettings = z.infer<typeof UpstreamProxySettingsSchema>
128129
export type AppSettings = z.infer<typeof AppSettingsSchema>

src/schemas/settings/v3/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
ProxySettingsSchema,
66
RecorderSettingsSchema,
77
WindowStateSchema,
8+
type UpstreamProxySettings,
89
} from '../v1'
910

1011
const TelemetrySchema = z.object({
@@ -18,6 +19,7 @@ export {
1819
RecorderSettingsSchema,
1920
TelemetrySchema,
2021
WindowStateSchema,
22+
type UpstreamProxySettings,
2123
}
2224

2325
export const AppSettingsSchema = z.object({

src/services/http.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import log from 'electron-log/main'
2+
import { readFile } from 'node:fs/promises'
3+
import { getGlobalDispatcher, ProxyAgent, setGlobalDispatcher } from 'undici'
4+
5+
import { UpstreamProxySettings } from '@/schemas/settings'
6+
7+
const DEFAULT_DISPATCHER = getGlobalDispatcher()
8+
9+
async function readCertificate(path: string | undefined) {
10+
if (path === undefined || path.trim() === '') {
11+
return undefined
12+
}
13+
14+
try {
15+
return await readFile(path, 'utf-8')
16+
} catch (error) {
17+
log.error('Failed to read proxy certificate.', error)
18+
19+
return undefined
20+
}
21+
}
22+
23+
function getAuthorizationHeader({ username, password }: UpstreamProxySettings) {
24+
if (username === undefined || password === undefined) {
25+
return undefined
26+
}
27+
28+
return {
29+
'Proxy-Authorization': `Basic ${Buffer.from(`${username}:${password}`).toString('base64')}`,
30+
}
31+
}
32+
33+
export async function configureSystemProxy() {
34+
const proxy = k6StudioState.appSettings.proxy
35+
36+
if (proxy.mode === 'regular') {
37+
setGlobalDispatcher(DEFAULT_DISPATCHER)
38+
39+
return
40+
}
41+
42+
const certificate = await readCertificate(proxy.certificatePath)
43+
44+
const agent = new ProxyAgent({
45+
uri: proxy.url,
46+
headers: getAuthorizationHeader(proxy),
47+
requestTls: {
48+
ca: certificate,
49+
rejectUnauthorized: !proxy.sslInsecure,
50+
},
51+
})
52+
53+
setGlobalDispatcher(agent)
54+
}

0 commit comments

Comments
 (0)