proxy private tabs
This commit is contained in:
+29
-9
@@ -1,8 +1,10 @@
|
|||||||
import 'package:fast_equatable/fast_equatable.dart';
|
import 'package:fast_equatable/fast_equatable.dart';
|
||||||
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
import 'package:flutter_mozilla_components/flutter_mozilla_components.dart';
|
||||||
|
import 'package:nullability/nullability.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
import 'package:weblibre/features/geckoview/features/tabs/domain/providers.dart';
|
||||||
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
|
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
|
|
||||||
part 'proxy_settings_replication.g.dart';
|
part 'proxy_settings_replication.g.dart';
|
||||||
|
|
||||||
@@ -25,21 +27,39 @@ class ProxySettingsReplication extends _$ProxySettingsReplication {
|
|||||||
ref.listen(
|
ref.listen(
|
||||||
fireImmediately: true,
|
fireImmediately: true,
|
||||||
containersWithCountProvider.select(
|
containersWithCountProvider.select(
|
||||||
(value) => EquatableValue(
|
(value) => EquatableValue(value.valueOrNull),
|
||||||
value.valueOrNull
|
|
||||||
?.where((container) => container.metadata.useProxy)
|
|
||||||
.map((container) => container.metadata.contextualIdentity)
|
|
||||||
.nonNulls
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
(previous, next) async {
|
(previous, next) async {
|
||||||
if (next.value != null) {
|
if (next.value != null) {
|
||||||
for (final contextId in next.value!) {
|
for (final container in next.value!) {
|
||||||
await _service.addContainerProxy(contextId);
|
if (container.metadata.contextualIdentity.isNotEmpty) {
|
||||||
|
if (container.metadata.useProxy) {
|
||||||
|
await _service.addContainerProxy(
|
||||||
|
container.metadata.contextualIdentity!,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
await _service.removeContainerProxy(
|
||||||
|
container.metadata.contextualIdentity!,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ref.listen(
|
||||||
|
fireImmediately: true,
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(value) => value.proxyPrivateTabsTor,
|
||||||
|
),
|
||||||
|
(previous, next) async {
|
||||||
|
if (next) {
|
||||||
|
await _service.addContainerProxy('private');
|
||||||
|
} else {
|
||||||
|
await _service.removeContainerProxy('private');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -7,7 +7,7 @@ part of 'proxy_settings_replication.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$proxySettingsReplicationHash() =>
|
String _$proxySettingsReplicationHash() =>
|
||||||
r'9571d178534f68ad3104f1168665ffb57711c6cc';
|
r'cd3a7573abfa0b32562289c02e77f0b44e88a8ae';
|
||||||
|
|
||||||
/// See also [ProxySettingsReplication].
|
/// See also [ProxySettingsReplication].
|
||||||
@ProviderFor(ProxySettingsReplication)
|
@ProviderFor(ProxySettingsReplication)
|
||||||
|
|||||||
@@ -2,7 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
import 'package:flutter_material_design_icons/flutter_material_design_icons.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:weblibre/features/settings/presentation/controllers/save_settings.dart';
|
||||||
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
|
import 'package:weblibre/features/tor/domain/services/tor_proxy.dart';
|
||||||
|
import 'package:weblibre/features/user/data/models/general_settings.dart';
|
||||||
|
import 'package:weblibre/features/user/domain/repositories/general_settings.dart';
|
||||||
import 'package:weblibre/presentation/hooks/on_initialization.dart';
|
import 'package:weblibre/presentation/hooks/on_initialization.dart';
|
||||||
|
|
||||||
class TorProxyScreen extends HookConsumerWidget {
|
class TorProxyScreen extends HookConsumerWidget {
|
||||||
@@ -11,6 +14,11 @@ class TorProxyScreen extends HookConsumerWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final torProxyPort = ref.watch(torProxyServiceProvider);
|
final torProxyPort = ref.watch(torProxyServiceProvider);
|
||||||
|
final proxyPrivateTabsTor = ref.watch(
|
||||||
|
generalSettingsRepositoryProvider.select(
|
||||||
|
(value) => value.proxyPrivateTabsTor,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
useOnInitialization(() async {
|
useOnInitialization(() async {
|
||||||
await ref.read(torProxyServiceProvider.notifier).requestSync();
|
await ref.read(torProxyServiceProvider.notifier).requestSync();
|
||||||
@@ -77,6 +85,55 @@ class TorProxyScreen extends HookConsumerWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
ListTileTheme(
|
||||||
|
iconColor: Colors.white,
|
||||||
|
textColor: Colors.white,
|
||||||
|
child: SwitchListTile.adaptive(
|
||||||
|
inactiveThumbColor: Colors.white,
|
||||||
|
activeColor: const Color(0xFF68B030),
|
||||||
|
trackColor: WidgetStateProperty.resolveWith<Color?>((
|
||||||
|
Set<WidgetState> states,
|
||||||
|
) {
|
||||||
|
if (states.isEmpty) {
|
||||||
|
return const Color(0xFF333A41);
|
||||||
|
}
|
||||||
|
return null; // Use the default color.
|
||||||
|
}),
|
||||||
|
trackOutlineColor:
|
||||||
|
WidgetStateProperty.resolveWith<Color?>((
|
||||||
|
Set<WidgetState> states,
|
||||||
|
) {
|
||||||
|
if (states.isEmpty) {
|
||||||
|
return Colors.white;
|
||||||
|
}
|
||||||
|
return null; // Use the default color.
|
||||||
|
}),
|
||||||
|
thumbIcon: WidgetStateProperty.resolveWith<Icon?>((
|
||||||
|
Set<WidgetState> states,
|
||||||
|
) {
|
||||||
|
if (states.contains(WidgetState.selected)) {
|
||||||
|
return const Icon(MdiIcons.incognito);
|
||||||
|
}
|
||||||
|
return null; // Use the default color.
|
||||||
|
}),
|
||||||
|
value: proxyPrivateTabsTor,
|
||||||
|
title: const Text('Proxy Private Tabs'),
|
||||||
|
subtitle: const Text(
|
||||||
|
'When enabled, all Private Tabs will be tunneled through Tor',
|
||||||
|
),
|
||||||
|
secondary: const Icon(MdiIcons.arrowDecision),
|
||||||
|
onChanged: (value) async {
|
||||||
|
await ref
|
||||||
|
.read(
|
||||||
|
saveGeneralSettingsControllerProvider.notifier,
|
||||||
|
)
|
||||||
|
.save(
|
||||||
|
(currentSettings) => currentSettings.copyWith
|
||||||
|
.proxyPrivateTabsTor(value),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -87,6 +144,7 @@ class TorProxyScreen extends HookConsumerWidget {
|
|||||||
const Column(
|
const Column(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
|
SizedBox(height: 8),
|
||||||
LinearProgressIndicator(
|
LinearProgressIndicator(
|
||||||
backgroundColor: Color(0xFF333A41),
|
backgroundColor: Color(0xFF333A41),
|
||||||
color: Color(0xFF68B030),
|
color: Color(0xFF68B030),
|
||||||
|
|||||||
@@ -28,12 +28,15 @@ class GeneralSettings with FastEquatable {
|
|||||||
final Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit;
|
final Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit;
|
||||||
final String defaultSearchProvider;
|
final String defaultSearchProvider;
|
||||||
|
|
||||||
|
final bool proxyPrivateTabsTor;
|
||||||
|
|
||||||
GeneralSettings({
|
GeneralSettings({
|
||||||
required this.themeMode,
|
required this.themeMode,
|
||||||
required this.enableReadability,
|
required this.enableReadability,
|
||||||
required this.enforceReadability,
|
required this.enforceReadability,
|
||||||
required this.deleteBrowsingDataOnQuit,
|
required this.deleteBrowsingDataOnQuit,
|
||||||
required this.defaultSearchProvider,
|
required this.defaultSearchProvider,
|
||||||
|
required this.proxyPrivateTabsTor,
|
||||||
});
|
});
|
||||||
|
|
||||||
GeneralSettings.withDefaults({
|
GeneralSettings.withDefaults({
|
||||||
@@ -42,10 +45,12 @@ class GeneralSettings with FastEquatable {
|
|||||||
bool? enforceReadability,
|
bool? enforceReadability,
|
||||||
this.deleteBrowsingDataOnQuit,
|
this.deleteBrowsingDataOnQuit,
|
||||||
String? defaultSearchProvider,
|
String? defaultSearchProvider,
|
||||||
|
bool? proxyPrivateTabsTor,
|
||||||
}) : themeMode = themeMode ?? ThemeMode.dark,
|
}) : themeMode = themeMode ?? ThemeMode.dark,
|
||||||
enableReadability = enableReadability ?? true,
|
enableReadability = enableReadability ?? true,
|
||||||
enforceReadability = enforceReadability ?? false,
|
enforceReadability = enforceReadability ?? false,
|
||||||
defaultSearchProvider = defaultSearchProvider ?? 'lais';
|
defaultSearchProvider = defaultSearchProvider ?? 'lais',
|
||||||
|
proxyPrivateTabsTor = proxyPrivateTabsTor ?? false;
|
||||||
|
|
||||||
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
factory GeneralSettings.fromJson(Map<String, dynamic> json) =>
|
||||||
_$GeneralSettingsFromJson(json);
|
_$GeneralSettingsFromJson(json);
|
||||||
@@ -59,5 +64,6 @@ class GeneralSettings with FastEquatable {
|
|||||||
enforceReadability,
|
enforceReadability,
|
||||||
deleteBrowsingDataOnQuit,
|
deleteBrowsingDataOnQuit,
|
||||||
defaultSearchProvider,
|
defaultSearchProvider,
|
||||||
|
proxyPrivateTabsTor,
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
|
|
||||||
GeneralSettings defaultSearchProvider(String defaultSearchProvider);
|
GeneralSettings defaultSearchProvider(String defaultSearchProvider);
|
||||||
|
|
||||||
|
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
||||||
|
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
///
|
///
|
||||||
/// Usage
|
/// Usage
|
||||||
@@ -31,6 +33,7 @@ abstract class _$GeneralSettingsCWProxy {
|
|||||||
bool enforceReadability,
|
bool enforceReadability,
|
||||||
Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit,
|
Set<DeleteBrowsingDataType>? deleteBrowsingDataOnQuit,
|
||||||
String defaultSearchProvider,
|
String defaultSearchProvider,
|
||||||
|
bool proxyPrivateTabsTor,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,6 +63,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
GeneralSettings defaultSearchProvider(String defaultSearchProvider) =>
|
GeneralSettings defaultSearchProvider(String defaultSearchProvider) =>
|
||||||
this(defaultSearchProvider: defaultSearchProvider);
|
this(defaultSearchProvider: defaultSearchProvider);
|
||||||
|
|
||||||
|
@override
|
||||||
|
GeneralSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor) =>
|
||||||
|
this(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `GeneralSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||||
///
|
///
|
||||||
@@ -73,6 +80,7 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
Object? enforceReadability = const $CopyWithPlaceholder(),
|
Object? enforceReadability = const $CopyWithPlaceholder(),
|
||||||
Object? deleteBrowsingDataOnQuit = const $CopyWithPlaceholder(),
|
Object? deleteBrowsingDataOnQuit = const $CopyWithPlaceholder(),
|
||||||
Object? defaultSearchProvider = const $CopyWithPlaceholder(),
|
Object? defaultSearchProvider = const $CopyWithPlaceholder(),
|
||||||
|
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return GeneralSettings(
|
return GeneralSettings(
|
||||||
themeMode: themeMode == const $CopyWithPlaceholder()
|
themeMode: themeMode == const $CopyWithPlaceholder()
|
||||||
@@ -97,6 +105,10 @@ class _$GeneralSettingsCWProxyImpl implements _$GeneralSettingsCWProxy {
|
|||||||
? _value.defaultSearchProvider
|
? _value.defaultSearchProvider
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: defaultSearchProvider as String,
|
: defaultSearchProvider as String,
|
||||||
|
proxyPrivateTabsTor: proxyPrivateTabsTor == const $CopyWithPlaceholder()
|
||||||
|
? _value.proxyPrivateTabsTor
|
||||||
|
// ignore: cast_nullable_to_non_nullable
|
||||||
|
: proxyPrivateTabsTor as bool,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +133,7 @@ GeneralSettings _$GeneralSettingsFromJson(Map<String, dynamic> json) =>
|
|||||||
?.map((e) => $enumDecode(_$DeleteBrowsingDataTypeEnumMap, e))
|
?.map((e) => $enumDecode(_$DeleteBrowsingDataTypeEnumMap, e))
|
||||||
.toSet(),
|
.toSet(),
|
||||||
defaultSearchProvider: json['defaultSearchProvider'] as String?,
|
defaultSearchProvider: json['defaultSearchProvider'] as String?,
|
||||||
|
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
||||||
@@ -132,6 +145,7 @@ Map<String, dynamic> _$GeneralSettingsToJson(GeneralSettings instance) =>
|
|||||||
?.map((e) => _$DeleteBrowsingDataTypeEnumMap[e]!)
|
?.map((e) => _$DeleteBrowsingDataTypeEnumMap[e]!)
|
||||||
.toList(),
|
.toList(),
|
||||||
'defaultSearchProvider': instance.defaultSearchProvider,
|
'defaultSearchProvider': instance.defaultSearchProvider,
|
||||||
|
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
||||||
};
|
};
|
||||||
|
|
||||||
const _$ThemeModeEnumMap = {
|
const _$ThemeModeEnumMap = {
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ class GeneralSettingsRepository extends _$GeneralSettingsRepository {
|
|||||||
DriftSqlType.string,
|
DriftSqlType.string,
|
||||||
db.typeMapping,
|
db.typeMapping,
|
||||||
),
|
),
|
||||||
|
'proxyPrivateTabsTor': settings['proxyPrivateTabsTor']?.readAs(
|
||||||
|
DriftSqlType.bool,
|
||||||
|
db.typeMapping,
|
||||||
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'general_settings.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$generalSettingsRepositoryHash() =>
|
String _$generalSettingsRepositoryHash() =>
|
||||||
r'2dcc600ccfb074fa27fae90acb3d61e10c87e884';
|
r'e16ce010f5feb692bd9f3a394c9502f959ded589';
|
||||||
|
|
||||||
/// See also [GeneralSettingsRepository].
|
/// See also [GeneralSettingsRepository].
|
||||||
@ProviderFor(GeneralSettingsRepository)
|
@ProviderFor(GeneralSettingsRepository)
|
||||||
|
|||||||
+10
-2
@@ -9,6 +9,7 @@ import _OnRequestDetails = browser.proxy._OnRequestDetails
|
|||||||
const localhosts = new Set(['localhost', '127.0.0.1', '[::1]'])
|
const localhosts = new Set(['localhost', '127.0.0.1', '[::1]'])
|
||||||
|
|
||||||
const containerIdentifier = 'firefox-container-'
|
const containerIdentifier = 'firefox-container-'
|
||||||
|
const privateIdentifier = 'firefox-private'
|
||||||
|
|
||||||
type DoNotProxy = never[]
|
type DoNotProxy = never[]
|
||||||
export const doNotProxy: DoNotProxy = []
|
export const doNotProxy: DoNotProxy = []
|
||||||
@@ -59,9 +60,16 @@ export default class BackgroundMain {
|
|||||||
if (requestDetails.tabId > -1) {
|
if (requestDetails.tabId > -1) {
|
||||||
const tab = (await browser.tabs.get(requestDetails.tabId))
|
const tab = (await browser.tabs.get(requestDetails.tabId))
|
||||||
|
|
||||||
if (tab.cookieStoreId?.startsWith(containerIdentifier) === true) {
|
if (tab.cookieStoreId?.startsWith(containerIdentifier) === true || tab.cookieStoreId === privateIdentifier) {
|
||||||
try {
|
try {
|
||||||
const cookieStoreId = tab.cookieStoreId.substring(containerIdentifier.length)
|
let cookieStoreId: string
|
||||||
|
|
||||||
|
if (tab.cookieStoreId.startsWith(containerIdentifier)) {
|
||||||
|
cookieStoreId = tab.cookieStoreId.substring(containerIdentifier.length)
|
||||||
|
} else {
|
||||||
|
// Handle private tabs - use 'private' as identifier
|
||||||
|
cookieStoreId = 'private'
|
||||||
|
}
|
||||||
|
|
||||||
const proxies = await this.store.getProxiesForContainer(cookieStoreId)
|
const proxies = await this.store.getProxiesForContainer(cookieStoreId)
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ port.onMessage.addListener((raw: unknown): void => {
|
|||||||
break
|
break
|
||||||
case "removeContainerProxy":
|
case "removeContainerProxy":
|
||||||
store.removeContainerProxyRelation(message.args, "tor")
|
store.removeContainerProxyRelation(message.args, "tor")
|
||||||
|
console.log('removed container relation ' + message.args)
|
||||||
break
|
break
|
||||||
case "healthcheck":
|
case "healthcheck":
|
||||||
port.postMessage({
|
port.postMessage({
|
||||||
|
|||||||
Reference in New Issue
Block a user