use better dns proxying
This commit is contained in:
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2024-2026 Fabian Freund.
|
||||
*
|
||||
* This file is part of WebLibre
|
||||
* (see https://weblibre.eu).
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:weblibre/core/logger.dart';
|
||||
import 'package:weblibre/features/proxy/domain/repositories/singbox_proxy_runtime.dart';
|
||||
import 'package:weblibre/features/user/data/models/engine_settings.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/engine_settings.dart';
|
||||
|
||||
part 'browser_dns_leak_guard.g.dart';
|
||||
|
||||
/// Watches the proxy runtime and **disables** GeckoView's TRR (sets
|
||||
/// [DohSettingsMode.off]) while at least one profile is running.
|
||||
///
|
||||
/// Why "off" and not "max": TRR resolves URL hostnames over DoH directly via
|
||||
/// the system network, *before* any SOCKS connection is established — so a
|
||||
/// DoH lookup leaks the destination outside the proxy even when the data
|
||||
/// itself goes through it. `max` (TRR-only) keeps that leak. `off` disables
|
||||
/// TRR so GeckoView uses its native resolver, which — combined with
|
||||
/// `proxyDNS: true` on our SOCKS proxy settings — sends hostnames through the
|
||||
/// SOCKS inbound so sing-box can resolve them instead of GeckoView doing a
|
||||
/// direct DoH lookup first.
|
||||
///
|
||||
/// The previous TRR mode is captured on engage and restored when all
|
||||
/// profiles stop.
|
||||
///
|
||||
/// This is a side-effect-only provider: it must be `keepAlive: true` and is
|
||||
/// explicitly listened-to from main.dart so the side effect runs without any
|
||||
/// widget needing to depend on it.
|
||||
@Riverpod(keepAlive: true)
|
||||
class BrowserDnsLeakGuard extends _$BrowserDnsLeakGuard {
|
||||
DohSettingsMode? _savedMode;
|
||||
|
||||
@override
|
||||
Future<void> build() async {
|
||||
final runtime = ref.watch(singboxProxyRuntimeRepositoryProvider);
|
||||
|
||||
// Skip while a start/stop is in flight. `startProfiles` resets the runtime
|
||||
// state to `AsyncLoading` for the entire restart — `asData` is briefly
|
||||
// null, which would otherwise look like "no profiles running" and trigger
|
||||
// a premature DoH restore in the middle of e.g. starting a second profile
|
||||
// while one is already active, opening a leak window during the transition.
|
||||
if (runtime.isLoading) return;
|
||||
|
||||
final anyRunning = runtime.asData?.value.endpoints.isNotEmpty ?? false;
|
||||
if (anyRunning) {
|
||||
await _enforceOffMode();
|
||||
} else if (_savedMode != null) {
|
||||
await _restoreSavedMode();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _enforceOffMode() async {
|
||||
final engine = ref.read(engineSettingsRepositoryProvider.notifier);
|
||||
try {
|
||||
final current = await engine.fetchSettings();
|
||||
if (current.dohSettingsMode == DohSettingsMode.off) {
|
||||
// Already off — don't capture it as the "saved" value, otherwise we
|
||||
// would restore it back to off on disengage instead of the user's
|
||||
// real previous choice.
|
||||
return;
|
||||
}
|
||||
_savedMode = current.dohSettingsMode;
|
||||
await engine.updateSettings(
|
||||
(current) => current.copyWith.dohSettingsMode(DohSettingsMode.off),
|
||||
);
|
||||
} catch (error, stack) {
|
||||
logger.e(
|
||||
'browser DNS leak guard failed to disable TRR',
|
||||
error: error,
|
||||
stackTrace: stack,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _restoreSavedMode() async {
|
||||
final saved = _savedMode;
|
||||
_savedMode = null;
|
||||
if (saved == null) return;
|
||||
try {
|
||||
await ref
|
||||
.read(engineSettingsRepositoryProvider.notifier)
|
||||
.updateSettings((current) => current.copyWith.dohSettingsMode(saved));
|
||||
} catch (error, stack) {
|
||||
logger.e(
|
||||
'browser DNS leak guard failed to restore DoH mode',
|
||||
error: error,
|
||||
stackTrace: stack,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'browser_dns_leak_guard.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
// ignore_for_file: type=lint, type=warning
|
||||
/// Watches the proxy runtime and **disables** GeckoView's TRR (sets
|
||||
/// [DohSettingsMode.off]) while at least one profile is running.
|
||||
///
|
||||
/// Why "off" and not "max": TRR resolves URL hostnames over DoH directly via
|
||||
/// the system network, *before* any SOCKS connection is established — so a
|
||||
/// DoH lookup leaks the destination outside the proxy even when the data
|
||||
/// itself goes through it. `max` (TRR-only) keeps that leak. `off` disables
|
||||
/// TRR so GeckoView uses its native resolver, which — combined with
|
||||
/// `proxyDNS: true` on our SOCKS proxy settings — sends hostnames through the
|
||||
/// SOCKS inbound so sing-box can resolve them instead of GeckoView doing a
|
||||
/// direct DoH lookup first.
|
||||
///
|
||||
/// The previous TRR mode is captured on engage and restored when all
|
||||
/// profiles stop.
|
||||
///
|
||||
/// This is a side-effect-only provider: it must be `keepAlive: true` and is
|
||||
/// explicitly listened-to from main.dart so the side effect runs without any
|
||||
/// widget needing to depend on it.
|
||||
|
||||
@ProviderFor(BrowserDnsLeakGuard)
|
||||
final browserDnsLeakGuardProvider = BrowserDnsLeakGuardProvider._();
|
||||
|
||||
/// Watches the proxy runtime and **disables** GeckoView's TRR (sets
|
||||
/// [DohSettingsMode.off]) while at least one profile is running.
|
||||
///
|
||||
/// Why "off" and not "max": TRR resolves URL hostnames over DoH directly via
|
||||
/// the system network, *before* any SOCKS connection is established — so a
|
||||
/// DoH lookup leaks the destination outside the proxy even when the data
|
||||
/// itself goes through it. `max` (TRR-only) keeps that leak. `off` disables
|
||||
/// TRR so GeckoView uses its native resolver, which — combined with
|
||||
/// `proxyDNS: true` on our SOCKS proxy settings — sends hostnames through the
|
||||
/// SOCKS inbound so sing-box can resolve them instead of GeckoView doing a
|
||||
/// direct DoH lookup first.
|
||||
///
|
||||
/// The previous TRR mode is captured on engage and restored when all
|
||||
/// profiles stop.
|
||||
///
|
||||
/// This is a side-effect-only provider: it must be `keepAlive: true` and is
|
||||
/// explicitly listened-to from main.dart so the side effect runs without any
|
||||
/// widget needing to depend on it.
|
||||
final class BrowserDnsLeakGuardProvider
|
||||
extends $AsyncNotifierProvider<BrowserDnsLeakGuard, void> {
|
||||
/// Watches the proxy runtime and **disables** GeckoView's TRR (sets
|
||||
/// [DohSettingsMode.off]) while at least one profile is running.
|
||||
///
|
||||
/// Why "off" and not "max": TRR resolves URL hostnames over DoH directly via
|
||||
/// the system network, *before* any SOCKS connection is established — so a
|
||||
/// DoH lookup leaks the destination outside the proxy even when the data
|
||||
/// itself goes through it. `max` (TRR-only) keeps that leak. `off` disables
|
||||
/// TRR so GeckoView uses its native resolver, which — combined with
|
||||
/// `proxyDNS: true` on our SOCKS proxy settings — sends hostnames through the
|
||||
/// SOCKS inbound so sing-box can resolve them instead of GeckoView doing a
|
||||
/// direct DoH lookup first.
|
||||
///
|
||||
/// The previous TRR mode is captured on engage and restored when all
|
||||
/// profiles stop.
|
||||
///
|
||||
/// This is a side-effect-only provider: it must be `keepAlive: true` and is
|
||||
/// explicitly listened-to from main.dart so the side effect runs without any
|
||||
/// widget needing to depend on it.
|
||||
BrowserDnsLeakGuardProvider._()
|
||||
: super(
|
||||
from: null,
|
||||
argument: null,
|
||||
retry: null,
|
||||
name: r'browserDnsLeakGuardProvider',
|
||||
isAutoDispose: false,
|
||||
dependencies: null,
|
||||
$allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
@override
|
||||
String debugGetCreateSourceHash() => _$browserDnsLeakGuardHash();
|
||||
|
||||
@$internal
|
||||
@override
|
||||
BrowserDnsLeakGuard create() => BrowserDnsLeakGuard();
|
||||
}
|
||||
|
||||
String _$browserDnsLeakGuardHash() =>
|
||||
r'366aaa6ae8c163449dca50147be0451c766ba765';
|
||||
|
||||
/// Watches the proxy runtime and **disables** GeckoView's TRR (sets
|
||||
/// [DohSettingsMode.off]) while at least one profile is running.
|
||||
///
|
||||
/// Why "off" and not "max": TRR resolves URL hostnames over DoH directly via
|
||||
/// the system network, *before* any SOCKS connection is established — so a
|
||||
/// DoH lookup leaks the destination outside the proxy even when the data
|
||||
/// itself goes through it. `max` (TRR-only) keeps that leak. `off` disables
|
||||
/// TRR so GeckoView uses its native resolver, which — combined with
|
||||
/// `proxyDNS: true` on our SOCKS proxy settings — sends hostnames through the
|
||||
/// SOCKS inbound so sing-box can resolve them instead of GeckoView doing a
|
||||
/// direct DoH lookup first.
|
||||
///
|
||||
/// The previous TRR mode is captured on engage and restored when all
|
||||
/// profiles stop.
|
||||
///
|
||||
/// This is a side-effect-only provider: it must be `keepAlive: true` and is
|
||||
/// explicitly listened-to from main.dart so the side effect runs without any
|
||||
/// widget needing to depend on it.
|
||||
|
||||
abstract class _$BrowserDnsLeakGuard extends $AsyncNotifier<void> {
|
||||
FutureOr<void> build();
|
||||
@$mustCallSuper
|
||||
@override
|
||||
void runBuild() {
|
||||
final ref = this.ref as $Ref<AsyncValue<void>, void>;
|
||||
final element =
|
||||
ref.element
|
||||
as $ClassProviderElement<
|
||||
AnyNotifier<AsyncValue<void>, void>,
|
||||
AsyncValue<void>,
|
||||
Object?,
|
||||
Object?
|
||||
>;
|
||||
element.handleCreate(ref, build);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,6 @@ import 'package:weblibre/features/geckoview/features/preferences/data/repositori
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/services/local_index_pruner.dart';
|
||||
import 'package:weblibre/features/geckoview/features/tabs/domain/services/local_index_settings_sync.dart';
|
||||
import 'package:weblibre/features/proxy/domain/repositories/singbox_proxy_logs.dart';
|
||||
import 'package:weblibre/features/proxy/domain/services/browser_dns_leak_guard.dart';
|
||||
import 'package:weblibre/features/proxy/domain/services/singbox_proxy_endpoint_sync.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/engine_settings.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||
@@ -282,12 +281,6 @@ class _MainWidget extends HookConsumerWidget {
|
||||
// Activate account callback deep link handler
|
||||
ref.read(accountCallbackHandlerProvider);
|
||||
|
||||
// Activate the proxy DNS leak guard: when any sing-box profile is
|
||||
// running AND the user has opted in, GeckoView TRR is forced to
|
||||
// off so browser DNS follows the SOCKS proxyDNS path instead of
|
||||
// resolving outside the proxy.
|
||||
ref.read(browserDnsLeakGuardProvider);
|
||||
|
||||
// Mirror the sing-box runtime's SOCKS endpoints into Gecko's
|
||||
// container-proxy registry. Side-effect-only notifier.
|
||||
ref.read(singboxProxyEndpointSyncProvider);
|
||||
|
||||
+69
-61
@@ -10,6 +10,7 @@ import _OnBeforeRequestDetails = browser.webRequest._OnBeforeRequestDetails
|
||||
const localhosts = new Set(['localhost', '127.0.0.1', '[::1]'])
|
||||
|
||||
const containerIdentifier = 'firefox-container-'
|
||||
const defaultIdentifier = 'firefox-default'
|
||||
const privateIdentifier = 'firefox-private'
|
||||
|
||||
type DoNotProxy = never[]
|
||||
@@ -32,6 +33,35 @@ export default class BackgroundMain {
|
||||
this.store = store
|
||||
}
|
||||
|
||||
private async tabForRequest(tabId?: number): Promise<browser.tabs.Tab | null> {
|
||||
if (tabId === undefined || tabId <= -1) {
|
||||
return null
|
||||
}
|
||||
|
||||
try {
|
||||
return await browser.tabs.get(tabId)
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private contextIdFromCookieStoreId(cookieStoreId?: string): string | null {
|
||||
if (cookieStoreId === undefined || cookieStoreId.length === 0) {
|
||||
return null
|
||||
}
|
||||
if (cookieStoreId.startsWith(containerIdentifier)) {
|
||||
return cookieStoreId.substring(containerIdentifier.length)
|
||||
}
|
||||
if (cookieStoreId === privateIdentifier) {
|
||||
return 'private'
|
||||
}
|
||||
if (cookieStoreId === defaultIdentifier) {
|
||||
return 'general'
|
||||
}
|
||||
|
||||
return cookieStoreId
|
||||
}
|
||||
|
||||
/*
|
||||
initializeAuthListener(cookieStoreId: string, proxy: HttpProxySettings | HttpsProxySettings): void {
|
||||
const listener: (details: _OnAuthRequiredDetails) => BlockingResponse = (details) => {
|
||||
@@ -60,72 +90,50 @@ export default class BackgroundMain {
|
||||
*/
|
||||
|
||||
async onRequest(requestDetails: Pick<_OnRequestDetails, 'cookieStoreId' | 'url' | 'tabId'>): Promise<DoNotProxy | ProxyInfo[]> {
|
||||
const tab = (requestDetails.tabId > -1) ? (await browser.tabs.get(requestDetails.tabId)) : null
|
||||
try {
|
||||
const tab = await this.tabForRequest(requestDetails.tabId)
|
||||
const contextId = this.contextIdFromCookieStoreId(tab?.cookieStoreId ?? requestDetails.cookieStoreId)
|
||||
|
||||
if (this.store.hasGeneralRelation() ||
|
||||
tab === null ||
|
||||
tab.cookieStoreId?.startsWith(containerIdentifier) === true ||
|
||||
tab.cookieStoreId === privateIdentifier
|
||||
) {
|
||||
try {
|
||||
let cookieStoreId: string
|
||||
if (contextId === null) {
|
||||
return doNotProxy
|
||||
}
|
||||
|
||||
if (tab?.cookieStoreId?.startsWith(containerIdentifier) === true) {
|
||||
cookieStoreId = tab.cookieStoreId.substring(containerIdentifier.length)
|
||||
} else if (tab?.cookieStoreId === privateIdentifier) {
|
||||
// Handle private tabs - use 'private' as identifier
|
||||
cookieStoreId = 'private'
|
||||
} else {
|
||||
cookieStoreId = 'general'
|
||||
}
|
||||
|
||||
let proxies = this.store.getProxiesForContainer(cookieStoreId)
|
||||
if ((proxies?.length ?? 0) == 0 && tab === null) {
|
||||
//When no tab is specified and general relation doesnt exist, we get all proxies to avoid leakage
|
||||
proxies = this.store.getAllProxies()
|
||||
|
||||
if (proxies.length == 0) {
|
||||
return doNotProxy
|
||||
}
|
||||
} else if (proxies === null) {
|
||||
return doNotProxy
|
||||
}
|
||||
|
||||
if (proxies.length > 0) {
|
||||
// proxies.forEach(p => {
|
||||
// if (p.type === ProxyType.Http || p.type === ProxyType.Https) {
|
||||
// this.initializeAuthListener(cookieStoreId, p)
|
||||
// }
|
||||
// })
|
||||
|
||||
const result: ProxyInfo[] = proxies.filter((p: ProxySettings) => {
|
||||
try {
|
||||
const documentUrl = new URL(requestDetails.url)
|
||||
const isLocalhost = localhosts.has(documentUrl.hostname)
|
||||
if (isLocalhost && p.doNotProxyLocal) {
|
||||
return false
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
return true
|
||||
}).map(p => p.asProxyInfo())
|
||||
|
||||
if (result.length === 0) {
|
||||
return [emergencyBreak]
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
return [emergencyBreak]
|
||||
} catch (e: unknown) {
|
||||
console.error(`Error in onRequest listener: ${e as string}`)
|
||||
const proxies = this.store.getProxiesForContainer(contextId)
|
||||
if (proxies === null) {
|
||||
return doNotProxy
|
||||
}
|
||||
if (proxies.length === 0) {
|
||||
return [emergencyBreak]
|
||||
}
|
||||
}
|
||||
|
||||
return doNotProxy
|
||||
// proxies.forEach(p => {
|
||||
// if (p.type === ProxyType.Http || p.type === ProxyType.Https) {
|
||||
// this.initializeAuthListener(cookieStoreId, p)
|
||||
// }
|
||||
// })
|
||||
|
||||
const result: ProxyInfo[] = proxies.filter((p: ProxySettings) => {
|
||||
try {
|
||||
const documentUrl = new URL(requestDetails.url)
|
||||
const isLocalhost = localhosts.has(documentUrl.hostname)
|
||||
if (isLocalhost && p.doNotProxyLocal) {
|
||||
return false
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
|
||||
return true
|
||||
}).map(p => p.asProxyInfo())
|
||||
|
||||
if (result.length === 0) {
|
||||
return doNotProxy
|
||||
}
|
||||
return result
|
||||
} catch (e: unknown) {
|
||||
console.error(`Error in onRequest listener: ${e as string}`)
|
||||
return [emergencyBreak]
|
||||
}
|
||||
}
|
||||
|
||||
async onBeforeRequest(options: _OnBeforeRequestDetails, port: browser.runtime.Port): Promise<browser.webRequest.BlockingResponse> {
|
||||
|
||||
+42
-10
@@ -9,11 +9,14 @@ const tryFromDao = ProxySettings.tryFromDao
|
||||
|
||||
const chrome = require('sinon-chrome/extensions');
|
||||
|
||||
const store = new Store()
|
||||
let store: Store
|
||||
let backgroundMain: BackgroundMain
|
||||
|
||||
describe('BackgroundMain', function () {
|
||||
beforeEach(() => {
|
||||
global.browser = chrome
|
||||
store = new Store()
|
||||
backgroundMain = new BackgroundMain({ store })
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
@@ -21,10 +24,6 @@ describe('BackgroundMain', function () {
|
||||
delete global.browser
|
||||
})
|
||||
|
||||
const backgroundMain = new BackgroundMain({ store: store })
|
||||
|
||||
// TODO: Add test for proxyDNS property
|
||||
|
||||
describe('onRequest', function () {
|
||||
it('should return empty array if no proxy is set up', async () => {
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-default', url: 'https://google.com', tabId: 0 })
|
||||
@@ -33,7 +32,7 @@ describe('BackgroundMain', function () {
|
||||
})
|
||||
|
||||
it('should return proxy if proxy is set up', async () => {
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'firefox-default', host: undefined, doNotProxyLocal: undefined })
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'general', host: undefined, doNotProxyLocal: undefined })
|
||||
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-default', url: 'https://google.com', tabId: 0 })
|
||||
|
||||
@@ -41,6 +40,31 @@ describe('BackgroundMain', function () {
|
||||
expect(result).to.be.not.empty
|
||||
})
|
||||
|
||||
it('should not use an unrelated container proxy for default tabs', async () => {
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'container1', host: undefined, doNotProxyLocal: undefined })
|
||||
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-default', url: 'https://google.com', tabId: -1 })
|
||||
|
||||
expect(result).to.be.deep.equal(doNotProxy)
|
||||
})
|
||||
|
||||
it('should use request cookieStoreId when no tab is available', async () => {
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'container1', host: undefined, doNotProxyLocal: undefined })
|
||||
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-container-container1', url: 'https://google.com', tabId: -1 })
|
||||
|
||||
expect(result).to.be.an('array')
|
||||
expect(result).to.be.not.empty
|
||||
})
|
||||
|
||||
it('should return empty array for tabless requests without a cookie store', async () => {
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'container1', host: undefined, doNotProxyLocal: undefined })
|
||||
|
||||
const result = await backgroundMain.onRequest({ url: 'https://google.com', tabId: -1 })
|
||||
|
||||
expect(result).to.be.deep.equal(doNotProxy)
|
||||
})
|
||||
|
||||
it('should block if an assigned proxy no longer exists', async () => {
|
||||
const isolatedStore = new Store()
|
||||
const isolatedBackgroundMain = new BackgroundMain({ store: isolatedStore })
|
||||
@@ -52,16 +76,24 @@ describe('BackgroundMain', function () {
|
||||
})
|
||||
|
||||
it('should remove doNotProxyLocal flag from proxy settings if proxy is set up', async () => {
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'firefox-default', host: undefined, doNotProxyLocal: undefined })
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'general', host: undefined, doNotProxyLocal: undefined })
|
||||
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-default', url: 'https://google.com', tabId: 0 })
|
||||
|
||||
expect((result[0] as any).doNotProxyLocal).to.be.undefined
|
||||
})
|
||||
|
||||
it('should preserve proxyDNS on SOCKS proxy settings', async () => {
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'container1', host: undefined, doNotProxyLocal: undefined })
|
||||
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-container-container1', url: 'https://google.com', tabId: -1 })
|
||||
|
||||
expect((result[0] as any).proxyDNS).to.be.true
|
||||
})
|
||||
|
||||
it('should return proxy for the container if url is invalid', async () => {
|
||||
// To be more on a safe side
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'firefox-default', host: undefined, doNotProxyLocal: undefined })
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'general', host: undefined, doNotProxyLocal: undefined })
|
||||
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-default', url: 'np-protocol-url.com', tabId: 0 })
|
||||
|
||||
@@ -88,7 +120,7 @@ describe('BackgroundMain', function () {
|
||||
it(`should return empty array if the address is local: ${url}`, async () => {
|
||||
await givenSomeProxyIsSetUpForContainer({ containerId: 'container1', host: undefined, doNotProxyLocal: true })
|
||||
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'container1', url, tabId: 0 })
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-container-container1', url, tabId: -1 })
|
||||
|
||||
expect(result).to.be.deep.equal(doNotProxy)
|
||||
})
|
||||
@@ -101,7 +133,7 @@ describe('BackgroundMain', function () {
|
||||
const host = 'proxyX.example.com'
|
||||
await givenSomeProxyIsSetUpForContainer({ host, containerId: 'container1', doNotProxyLocal: false })
|
||||
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'container1', url, tabId: 0 })
|
||||
const result = await backgroundMain.onRequest({ cookieStoreId: 'firefox-container-container1', url, tabId: -1 })
|
||||
|
||||
expect(result[0].host).to.be.equal(host)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user