diff --git a/app/lib/domain/services/generic_website.dart b/app/lib/domain/services/generic_website.dart index 837c0ba0..755a7d16 100644 --- a/app/lib/domain/services/generic_website.dart +++ b/app/lib/domain/services/generic_website.dart @@ -9,12 +9,16 @@ import 'package:html/dom.dart'; import 'package:html/parser.dart' as html_parser; import 'package:http/http.dart' as http; import 'package:riverpod_annotation/riverpod_annotation.dart'; +import 'package:universal_io/io.dart'; part 'generic_website.g.dart'; @Riverpod(keepAlive: true) class GenericWebsiteService extends _$GenericWebsiteService { late http.Client _client; + final Map _httpsCache; + + GenericWebsiteService() : _httpsCache = {}; @override void build() { @@ -101,4 +105,42 @@ class GenericWebsiteService extends _$GenericWebsiteService { ), ); } + + Future tryUpgradeToHttps(Uri httpUri) async { + if (httpUri.isScheme('https')) { + return httpUri; + } else if (httpUri.isScheme('http')) { + final cached = _httpsCache[httpUri.host]; + if (cached != null) { + return cached ? httpUri.replace(scheme: 'https') : null; + } + + var sslAvailable = false; + + try { + final context = SecurityContext.defaultContext; + + final socket = await SecureSocket.connect( + httpUri.host, + 443, + context: context, + timeout: const Duration(seconds: 3), + ); + + await socket.close(); + + sslAvailable = true; + } catch (_) { + sslAvailable = false; + } + + _httpsCache[httpUri.host] = sslAvailable; + + if (sslAvailable) { + return httpUri.replace(scheme: 'https'); + } + } + + return null; + } } diff --git a/app/lib/features/web_view/presentation/widgets/web_view.dart b/app/lib/features/web_view/presentation/widgets/web_view.dart index 53acc867..365689ba 100644 --- a/app/lib/features/web_view/presentation/widgets/web_view.dart +++ b/app/lib/features/web_view/presentation/widgets/web_view.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:bang_navigator/core/logger.dart'; +import 'package:bang_navigator/domain/services/generic_website.dart'; import 'package:bang_navigator/features/bangs/domain/providers.dart'; import 'package:bang_navigator/features/chat_archive/domain/entities/chat_entity.dart'; import 'package:bang_navigator/features/chat_archive/domain/repositories/archive.dart'; @@ -289,6 +290,28 @@ class _WebViewState extends ConsumerState { reasonPhrase: "Forbidden", ); } + + //Check if main page aka main frame is upgradeable + if (request.url.isScheme('http') && + request.isForMainFrame == true) { + final upgradedUri = await ref + .read(genericWebsiteServiceProvider.notifier) + .tryUpgradeToHttps(request.url); + + if (upgradedUri != null) { + unawaited( + controller.loadUrl( + urlRequest: URLRequest(url: WebUri.uri(upgradedUri)), + ), + ); + + return WebResourceResponse( + statusCode: 200, + reasonPhrase: "Redirecting...", + ); + } + } + return null; }, onProgressChanged: (controller, progress) {