diff --git a/app/lib/domain/services/generic_website.g.dart b/app/lib/domain/services/generic_website.g.dart index a33fd476..1ac6b5ae 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'06ec407f4ed37b1b6370d48ad418b54131a08007'; + r'517304ca95e1ef8377d4c1a3bd06fef9c68c92cd'; /// See also [GenericWebsiteService]. @ProviderFor(GenericWebsiteService) diff --git a/app/lib/features/settings/data/models/settings.dart b/app/lib/features/settings/data/models/settings.dart index 4221b09b..c580b484 100644 --- a/app/lib/features/settings/data/models/settings.dart +++ b/app/lib/features/settings/data/models/settings.dart @@ -13,6 +13,7 @@ class Settings with FastEquatable { final bool enableJavascript; final bool launchUrlExternal; final bool enableContentBlocking; + final bool blockHttpProtocol; final Set enableHostList; final ThemeMode themeMode; @@ -23,6 +24,7 @@ class Settings with FastEquatable { required this.enableJavascript, required this.launchUrlExternal, required this.enableContentBlocking, + required this.blockHttpProtocol, required this.enableHostList, required this.themeMode, }); @@ -34,6 +36,7 @@ class Settings with FastEquatable { bool? enableJavascript, bool? launchUrlExternal, bool? enableContentBlocking, + bool? blockHttpProtocol, Set? enableHostList, ThemeMode? themeMode, }) : showEarlyAccessFeatures = showEarlyAccessFeatures ?? true, @@ -41,6 +44,7 @@ class Settings with FastEquatable { enableJavascript = enableJavascript ?? true, launchUrlExternal = launchUrlExternal ?? false, enableContentBlocking = enableContentBlocking ?? true, + blockHttpProtocol = blockHttpProtocol ?? false, enableHostList = enableHostList ?? {HostSource.stevenBlackUnified}, themeMode = themeMode ?? ThemeMode.dark; @@ -55,6 +59,7 @@ class Settings with FastEquatable { enableJavascript, launchUrlExternal, enableContentBlocking, + blockHttpProtocol, enableHostList, themeMode, ]; diff --git a/app/lib/features/settings/data/models/settings.g.dart b/app/lib/features/settings/data/models/settings.g.dart index 3089f359..fbe88864 100644 --- a/app/lib/features/settings/data/models/settings.g.dart +++ b/app/lib/features/settings/data/models/settings.g.dart @@ -19,6 +19,8 @@ abstract class _$SettingsCWProxy { Settings enableContentBlocking(bool enableContentBlocking); + Settings blockHttpProtocol(bool blockHttpProtocol); + Settings enableHostList(Set enableHostList); Settings themeMode(ThemeMode themeMode); @@ -36,6 +38,7 @@ abstract class _$SettingsCWProxy { bool? enableJavascript, bool? launchUrlExternal, bool? enableContentBlocking, + bool? blockHttpProtocol, Set? enableHostList, ThemeMode? themeMode, }); @@ -70,6 +73,10 @@ class _$SettingsCWProxyImpl implements _$SettingsCWProxy { Settings enableContentBlocking(bool enableContentBlocking) => this(enableContentBlocking: enableContentBlocking); + @override + Settings blockHttpProtocol(bool blockHttpProtocol) => + this(blockHttpProtocol: blockHttpProtocol); + @override Settings enableHostList(Set enableHostList) => this(enableHostList: enableHostList); @@ -92,6 +99,7 @@ class _$SettingsCWProxyImpl implements _$SettingsCWProxy { Object? enableJavascript = const $CopyWithPlaceholder(), Object? launchUrlExternal = const $CopyWithPlaceholder(), Object? enableContentBlocking = const $CopyWithPlaceholder(), + Object? blockHttpProtocol = const $CopyWithPlaceholder(), Object? enableHostList = const $CopyWithPlaceholder(), Object? themeMode = const $CopyWithPlaceholder(), }) { @@ -127,6 +135,11 @@ class _$SettingsCWProxyImpl implements _$SettingsCWProxy { ? _value.enableContentBlocking // ignore: cast_nullable_to_non_nullable : enableContentBlocking as bool, + blockHttpProtocol: blockHttpProtocol == const $CopyWithPlaceholder() || + blockHttpProtocol == null + ? _value.blockHttpProtocol + // ignore: cast_nullable_to_non_nullable + : blockHttpProtocol as bool, enableHostList: enableHostList == const $CopyWithPlaceholder() || enableHostList == null ? _value.enableHostList diff --git a/app/lib/features/settings/data/repositories/settings_repository.dart b/app/lib/features/settings/data/repositories/settings_repository.dart index d92d0671..73bada78 100644 --- a/app/lib/features/settings/data/repositories/settings_repository.dart +++ b/app/lib/features/settings/data/repositories/settings_repository.dart @@ -34,6 +34,7 @@ class SettingsRepository extends _$SettingsRepository { static const _javascriptStorageKey = 'b4ng_settings_js'; static const _launchExternalStorageKey = 'b4ng_settings_launch_external'; static const _contentBlockingStorageKey = 'b4ng_settings_content_blocking'; + static const _blockHttpProtocolStorageKey = 'b4ng_settings_block_http'; static const _enableHostListStorageKey = 'b4ng_settings_host_lists'; static const _themeModeStorageKey = 'b4ng_settings_theme_mode'; @@ -96,6 +97,13 @@ class SettingsRepository extends _$SettingsRepository { ); } + if (newSettings.blockHttpProtocol != oldSettings.blockHttpProtocol) { + await sharedPreferences.setBool( + _blockHttpProtocolStorageKey, + newSettings.blockHttpProtocol, + ); + } + if (!const DeepCollectionEquality.unordered().equals( newSettings.enableHostList, oldSettings.enableHostList, @@ -130,6 +138,8 @@ class SettingsRepository extends _$SettingsRepository { launchUrlExternal: sharedPreferences.getBool(_launchExternalStorageKey), enableContentBlocking: sharedPreferences.getBool(_contentBlockingStorageKey), + blockHttpProtocol: + sharedPreferences.getBool(_blockHttpProtocolStorageKey), enableHostList: _parseHostSources( sharedPreferences.getStringList(_enableHostListStorageKey), ), diff --git a/app/lib/features/settings/data/repositories/settings_repository.g.dart b/app/lib/features/settings/data/repositories/settings_repository.g.dart index acf5fc17..4470bc6f 100644 --- a/app/lib/features/settings/data/repositories/settings_repository.g.dart +++ b/app/lib/features/settings/data/repositories/settings_repository.g.dart @@ -7,7 +7,7 @@ part of 'settings_repository.dart'; // ************************************************************************** String _$settingsRepositoryHash() => - r'2fed76bdc3132729f1018f8e4c9d493ee11831a0'; + r'ac2b1ecddd82e45e901425e9e5fcb9b4b61855fa'; /// See also [SettingsRepository]. @ProviderFor(SettingsRepository) diff --git a/app/lib/features/settings/presentation/screens/settings.dart b/app/lib/features/settings/presentation/screens/settings.dart index 1a7ccea9..d533b640 100644 --- a/app/lib/features/settings/presentation/screens/settings.dart +++ b/app/lib/features/settings/presentation/screens/settings.dart @@ -214,6 +214,19 @@ class SettingsScreen extends HookConsumerWidget { ); }, ), + SwitchListTile.adaptive( + title: const Text('Block HTTP Protocol'), + subtitle: const Text( + 'Prevents loading of HTTP (unsecure) content entirely. When enabled, only HTTPS (secure) is allowed.', + ), + value: settings.blockHttpProtocol, + onChanged: (value) async { + await ref.read(saveSettingsControllerProvider.notifier).save( + (currentSettings) => + currentSettings.copyWith.blockHttpProtocol(value), + ); + }, + ), SwitchListTile.adaptive( title: const Text('Launch Links Externally'), subtitle: const Text( 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 365689ba..24745e99 100644 --- a/app/lib/features/web_view/presentation/widgets/web_view.dart +++ b/app/lib/features/web_view/presentation/widgets/web_view.dart @@ -312,6 +312,19 @@ class _WebViewState extends ConsumerState { } } + if (request.url.isScheme('http')) { + if ((ref.read(settingsRepositoryProvider).valueOrNull ?? + Settings.withDefaults()) + .blockHttpProtocol) { + return WebResourceResponse( + contentType: "text/plain", + data: utf8.encode("HTTP protocol is blocked"), + statusCode: 403, + reasonPhrase: "Forbidden", + ); + } + } + return null; }, onProgressChanged: (controller, progress) {