Skip to content

Commit ead6d39

Browse files
committed
fix(browser): reject partial fetch proxy
1 parent daba405 commit ead6d39

2 files changed

Lines changed: 28 additions & 6 deletions

File tree

packages/bcode-browser/src/fetch-use.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,25 @@ export class Service extends Context.Service<Service, {
2828
readonly fetch: (url: string, opts: { timeoutMs: number }) => Effect.Effect<FetchResult, Error>
2929
}>()("@browser-use/FetchUse") {}
3030

31-
export const makeLayer = (options: { endpoint: string; apiKey: string; proxyToken: string }) =>
31+
export const makeLayer = (options: { proxyUrl: string; apiKey: string; proxyToken: string }) =>
3232
Layer.effect(
3333
Service,
3434
Effect.gen(function* () {
3535
const http = yield* HttpClient.HttpClient
36+
const hasProxySetting = options.proxyUrl.length > 0 || options.proxyToken.length > 0
37+
const proxyEnabled = options.proxyUrl.length > 0 && options.proxyToken.length > 0
38+
const directEnabled = !hasProxySetting && options.apiKey.length > 0
3639
return Service.of({
37-
enabled: options.proxyToken.length > 0 || options.apiKey.length > 0,
40+
enabled: proxyEnabled || directEnabled,
3841
fetch: (url, { timeoutMs }) =>
3942
Effect.gen(function* () {
40-
const auth = options.proxyToken
43+
if (!proxyEnabled && !directEnabled) {
44+
return yield* Effect.fail(new Error("fetch-use credentials are missing or partially configured"))
45+
}
46+
const auth = proxyEnabled
4147
? { Authorization: `Bearer ${options.proxyToken}` }
4248
: { "X-Browser-Use-API-Key": options.apiKey }
43-
const request = yield* HttpClientRequest.post(options.endpoint).pipe(
49+
const request = yield* HttpClientRequest.post(proxyEnabled ? options.proxyUrl : DEFAULT_ENDPOINT).pipe(
4450
HttpClientRequest.setHeaders({ "Content-Type": "application/json", ...auth }),
4551
HttpClientRequest.bodyJson({ url, timeout_ms: timeoutMs }),
4652
)
@@ -62,7 +68,7 @@ export const makeLayer = (options: { endpoint: string; apiKey: string; proxyToke
6268
)
6369

6470
export const layer = makeLayer({
65-
endpoint: process.env.BROWSER_USE_FETCH_URL ?? DEFAULT_ENDPOINT,
71+
proxyUrl: process.env.BROWSER_USE_FETCH_URL ?? "",
6672
apiKey: process.env.BROWSER_USE_API_KEY ?? "",
6773
proxyToken: process.env.BROWSER_USE_FETCH_TOKEN ?? "",
6874
})

packages/bcode-browser/test/fetch-use.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ test("scoped proxy token uses bearer auth instead of the API-key header", async
5353
}).pipe(
5454
Effect.provide(
5555
FetchUse.makeLayer({
56-
endpoint: server.url.toString(),
56+
proxyUrl: server.url.toString(),
5757
apiKey: "",
5858
proxyToken: "v4rt_test",
5959
}).pipe(Layer.provide(FetchHttpClient.layer)),
@@ -69,3 +69,19 @@ test("scoped proxy token uses bearer auth instead of the API-key header", async
6969
server.stop(true)
7070
}
7171
})
72+
73+
test.each([
74+
{ proxyUrl: "https://proxy.example/fetch", proxyToken: "", apiKey: "bu_secret" },
75+
{ proxyUrl: "", proxyToken: "v4rt_secret", apiKey: "bu_secret" },
76+
])("partial proxy configuration fails closed", async (options) => {
77+
const result = await Effect.gen(function* () {
78+
const service = yield* FetchUse.Service
79+
expect(service.enabled).toBe(false)
80+
return yield* Effect.flip(service.fetch("https://example.com", { timeoutMs: 1_000 }))
81+
}).pipe(
82+
Effect.provide(FetchUse.makeLayer(options).pipe(Layer.provide(FetchHttpClient.layer))),
83+
Effect.runPromise,
84+
)
85+
86+
expect(result.message).toContain("partially configured")
87+
})

0 commit comments

Comments
 (0)