From 3c1176bf79ff0d84322d2b19194594954206dcb5 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Fri, 27 Jun 2025 11:51:16 +0200 Subject: [PATCH] proxy website query requests --- app/lib/domain/services/generic_website.dart | 23 +++++++++--- .../domain/services/generic_website.g.dart | 2 +- .../controllers/website_title.dart | 36 +++++++++++++++++-- .../controllers/website_title.g.dart | 2 +- app/pubspec.yaml | 4 +++ 5 files changed, 58 insertions(+), 9 deletions(-) diff --git a/app/lib/domain/services/generic_website.dart b/app/lib/domain/services/generic_website.dart index 402b4982..799594bf 100644 --- a/app/lib/domain/services/generic_website.dart +++ b/app/lib/domain/services/generic_website.dart @@ -6,9 +6,11 @@ import 'package:flutter/foundation.dart'; import 'package:flutter_mozilla_components/flutter_mozilla_components.dart'; import 'package:html/dom.dart'; import 'package:html/parser.dart' as html_parser; -import 'package:http/http.dart' as http; +import 'package:http/io_client.dart'; import 'package:nullability/nullability.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:socks5_proxy/socks_client.dart'; +import 'package:universal_io/io.dart'; import 'package:weblibre/core/http_error_handler.dart'; import 'package:weblibre/data/models/web_page_info.dart'; import 'package:weblibre/features/geckoview/domain/entities/browser_icon.dart'; @@ -186,12 +188,23 @@ class GenericWebsiteService extends _$GenericWebsiteService { return icons; } - Future> fetchPageInfo(Uri url, bool isImageRequest) { + Future> fetchPageInfo({ + required Uri url, + required bool isImageRequest, + required int? proxyPort, + }) { return Result.fromAsync(() async { final result = await compute((args) async { - final [String urlString, bool isImageRequest] = args; + final [String urlString, bool isImageRequest, int? proxyPort] = args; - final client = http.Client(); + final httpClient = HttpClient(); + if (proxyPort != null) { + SocksTCPClient.assignToHttpClient(httpClient, [ + ProxySettings(InternetAddress.loopbackIPv4, proxyPort), + ]); + } + + final client = IOClient(httpClient); try { final baseUri = Uri.parse(urlString); final response = await client @@ -225,7 +238,7 @@ class GenericWebsiteService extends _$GenericWebsiteService { } finally { client.close(); } - }, [url.toString(), isImageRequest]); + }, [url.toString(), isImageRequest, proxyPort]); if (result['imageBytes'] case final Uint8List imageBytes) { return WebPageInfo( diff --git a/app/lib/domain/services/generic_website.g.dart b/app/lib/domain/services/generic_website.g.dart index 91e9ea70..7d56be38 100644 --- a/app/lib/domain/services/generic_website.g.dart +++ b/app/lib/domain/services/generic_website.g.dart @@ -7,7 +7,7 @@ part of 'generic_website.dart'; // ************************************************************************** String _$genericWebsiteServiceHash() => - r'9c8020d3c8d85342972db8934b37c53b31064b64'; + r'19ce8c27e316d9220152f6ad9cfa8024d191c0f0'; /// See also [GenericWebsiteService]. @ProviderFor(GenericWebsiteService) diff --git a/app/lib/presentation/controllers/website_title.dart b/app/lib/presentation/controllers/website_title.dart index bd08fc81..24e0a9a4 100644 --- a/app/lib/presentation/controllers/website_title.dart +++ b/app/lib/presentation/controllers/website_title.dart @@ -1,8 +1,13 @@ +import 'package:nullability/nullability.dart'; import 'package:riverpod/riverpod.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:weblibre/core/logger.dart'; import 'package:weblibre/data/models/web_page_info.dart'; import 'package:weblibre/domain/services/generic_website.dart'; +import 'package:weblibre/features/geckoview/domain/providers/selected_tab.dart'; +import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/container.dart'; +import 'package:weblibre/features/geckoview/features/tabs/domain/repositories/tab.dart'; +import 'package:weblibre/features/tor/domain/services/tor_proxy.dart'; part 'website_title.g.dart'; @@ -51,9 +56,36 @@ Future pageInfo( Uri url, { required bool isImageRequest, }) async { - final websiteService = ref.watch(genericWebsiteServiceProvider.notifier); + final tabId = ref.read(selectedTabProvider); - final result = await websiteService.fetchPageInfo(url, isImageRequest); + int? proxyPort; + if (tabId != null) { + final containerId = await ref + .read(tabDataRepositoryProvider.notifier) + .containerTabId(tabId); + + final containerData = await containerId.mapNotNull( + (containerId) => ref + .read(containerRepositoryProvider.notifier) + .getContainerData(containerId), + ); + + if (containerData?.metadata.useProxy == true) { + proxyPort = await ref.read(torProxyServiceProvider.future); + + if (proxyPort == null) { + throw Exception('Could not proxy request'); + } + } + } + + final result = await ref + .watch(genericWebsiteServiceProvider.notifier) + .fetchPageInfo( + url: url, + isImageRequest: isImageRequest, + proxyPort: proxyPort, + ); if (result.isSuccess) { ref.keepAlive(); diff --git a/app/lib/presentation/controllers/website_title.g.dart b/app/lib/presentation/controllers/website_title.g.dart index 8d3b338d..2802baab 100644 --- a/app/lib/presentation/controllers/website_title.g.dart +++ b/app/lib/presentation/controllers/website_title.g.dart @@ -6,7 +6,7 @@ part of 'website_title.dart'; // RiverpodGenerator // ************************************************************************** -String _$pageInfoHash() => r'dd5644057e4ba7280275105de4788eb4046592d4'; +String _$pageInfoHash() => r'32527f7803e3eb33f74ce58d0773a9386df2546d'; /// Copied from Dart SDK class _SystemHash { diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 69acd4a9..2de39a19 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -60,6 +60,10 @@ dependencies: skeletonizer: ^2.0.1 sliver_tools: ^0.2.12 smooth_page_indicator: ^1.2.1 + socks5_proxy: + git: + url: https://github.com/sylvieon/socks_dart.git + ref: 04550bc08f42cc1a35f1e870f651b93a4f9aceab speech_to_text_google_dialog: git: url: https://github.com/FaFre/speech_to_text_google_dialog.git