finished implementation
This commit is contained in:
@@ -0,0 +1 @@
|
||||
{"meek":["meek_lite 192.0.2.20:80 url=https://1603026938.rsc.cdn77.org front=www.phpmyadmin.net utls=HelloRandomizedALPN"],"meek-azure":["meek_lite 192.0.2.20:80 url=https://1603026938.rsc.cdn77.org front=www.phpmyadmin.net utls=HelloRandomizedALPN"],"obfs4":["obfs4 51.222.13.177:80 5EDAC3B810E12B01F6FD8050D2FD3E277B289A08 cert=2uplIpLQ0q9+0qMFrK5pkaYRDOe460LL9WHBvatgkuRr/SL31wBOEupaMMJ6koRE6Ld0ew iat-mode=0","obfs4 37.218.245.14:38224 D9A82D2F9C2F65A18407B1D2B764F130847F8B5D cert=bjRaMrr1BRiAW8IE9U5z27fQaYgOhX1UCmOpg2pFpoMvo6ZgQMzLsaTzzQNTlm7hNcb+Sg iat-mode=0","obfs4 193.11.166.194:27015 2D82C2E354D531A68469ADF7F878FA6060C6BACA cert=4TLQPJrTSaDffMK7Nbao6LC7G9OW/NHkUwIdjLSS3KYf0Nv4/nQiiI8dY2TcsQx01NniOg iat-mode=0","obfs4 192.95.36.142:443 CDF2E852BF539B82BD10E27E9115A31734E378C2 cert=qUVQ0srL1JI/vO6V6m/24anYXiJD3QP2HgzUKQtQ7GRqqUvs7P+tG43RtAqdhLOALP7DJQ iat-mode=1","obfs4 45.145.95.6:27015 C5B7CD6946FF10C5B3E89691A7D3F2C122D2117C cert=TD7PbUO0/0k6xYHMPW3vJxICfkMZNdkRrb63Zhl5j9dW3iRGiCx0A7mPhe5T2EDzQ35+Zw iat-mode=0","obfs4 209.148.46.65:443 74FAD13168806246602538555B5521A0383A1875 cert=ssH+9rP8dG2NLDN2XuFw63hIO/9MNNinLmxQDpVa+7kTOa9/m+tGWT1SmSYpQ9uTBGa6Hw iat-mode=0","obfs4 193.11.166.194:27020 86AC7B8D430DAC4117E9F42C9EAED18133863AAF cert=0LDeJH4JzMDtkJJrFphJCiPqKx7loozKN7VNfuukMGfHO0Z8OGdzHVkhVAOfo1mUdv9cMg iat-mode=0","obfs4 85.31.186.26:443 91A6354697E6B02A386312F68D82CF86824D3606 cert=PBwr+S8JTVZo6MPdHnkTwXJPILWADLqfMGoVvhZClMq/Urndyd42BwX9YFJHZnBB3H0XCw iat-mode=0","obfs4 85.31.186.98:443 011F2599C0E9B27EE74B353155E244813763C3E5 cert=ayq0XzCwhpdysn5o0EyDUbmSOx3X/oTEbzDMvczHOdBJKlvIdHHLJGkZARtT4dcBFArPPg iat-mode=0","obfs4 146.57.248.225:22 10A6CD36A537FCE513A322361547444B393989F0 cert=K1gDtDAIcUfeLqbstggjIw2rtgIKqdIhUlHp82XRqNSq/mtAjp1BIC9vHKJ2FAEpGssTPw iat-mode=0","obfs4 193.11.166.194:27025 1AE2C08904527FEA90C4C4F8C1083EA59FBC6FAF cert=ItvYZzW5tn6v3G4UnQa6Qz04Npro6e81AP70YujmK/KXwDFPTs3aHXcHp4n8Vt6w/bv8cA iat-mode=0"],"snowflake":["snowflake 192.0.2.3:80 2B280B23E1107BB62ABFC40DDCC8824814F80A72 fingerprint=2B280B23E1107BB62ABFC40DDCC8824814F80A72 url=https://1098762253.rsc.cdn77.org/ fronts=www.cdn77.com,www.phpmyadmin.net ice=stun:stun.antisip.com:3478,stun:stun.epygi.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.mixvoip.com:3478,stun:stun.nextcloud.com:3478,stun:stun.bethesda.net:3478,stun:stun.nextcloud.com:443 utls-imitate=hellorandomizedalpn","snowflake 192.0.2.4:80 8838024498816A039FCBBAB14E6F40A0843051FA fingerprint=8838024498816A039FCBBAB14E6F40A0843051FA url=https://1098762253.rsc.cdn77.org/ fronts=www.cdn77.com,www.phpmyadmin.net ice=stun:stun.antisip.com:3478,stun:stun.epygi.com:3478,stun:stun.uls.co.za:3478,stun:stun.voipgate.com:3478,stun:stun.mixvoip.com:3478,stun:stun.nextcloud.com:3478,stun:stun.bethesda.net:3478,stun:stun.nextcloud.com:443 utls-imitate=hellorandomizedalpn"]}
|
||||
@@ -17,7 +17,10 @@
|
||||
* 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 'dart:developer';
|
||||
|
||||
import 'package:fading_scroll/fading_scroll.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||
@@ -163,6 +166,38 @@ class DeveloperSettingsScreen extends HookConsumerWidget {
|
||||
label: const Text('Copy'),
|
||||
),
|
||||
),
|
||||
if (kDebugMode)
|
||||
CustomListTile(
|
||||
title: 'Dart VM',
|
||||
subtitle: 'Copy Dart VM service URL',
|
||||
prefix: Padding(
|
||||
padding: const EdgeInsets.only(right: 16.0),
|
||||
child: Icon(
|
||||
Icons.bug_report,
|
||||
size: 24,
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
suffix: FilledButton.icon(
|
||||
onPressed: () async {
|
||||
final serviceProtocolInfo = await Service.getInfo();
|
||||
|
||||
await Clipboard.setData(
|
||||
ClipboardData(
|
||||
text:
|
||||
serviceProtocolInfo.serverUri?.toString() ??
|
||||
'Error',
|
||||
),
|
||||
);
|
||||
|
||||
if (context.mounted) {
|
||||
showInfoMessage(context, 'Service URL copied');
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.copy),
|
||||
label: const Text('Copy'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/services.dart' show rootBundle;
|
||||
import 'package:path/path.dart' as p;
|
||||
import 'package:path_provider/path_provider.dart' as path_provider;
|
||||
import 'package:pluggable_transports_proxy/pluggable_transports_proxy.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:universal_io/io.dart';
|
||||
|
||||
part 'builtin_bridges.g.dart';
|
||||
|
||||
@Riverpod(keepAlive: true)
|
||||
class BuiltinBridgesService extends _$BuiltinBridgesService {
|
||||
late final _bridgeFileFuture = path_provider
|
||||
.getApplicationSupportDirectory()
|
||||
.then((dir) => File(p.join(dir.path, 'builtin-bridges.json')));
|
||||
|
||||
Future<DateTime?> lastUpdate() async {
|
||||
final bridgeFile = await _bridgeFileFuture;
|
||||
if (!await bridgeFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return bridgeFile.lastModified();
|
||||
}
|
||||
|
||||
Future<void> updateStoredBuiltinBridges(BuiltInBridges bridges) async {
|
||||
final bridgeFile = await _bridgeFileFuture;
|
||||
await bridgeFile.writeAsString(jsonEncode(bridges.toJson()), flush: true);
|
||||
}
|
||||
|
||||
Future<BuiltInBridges?> getStoredBuiltinBridges() async {
|
||||
final bridgeFile = await _bridgeFileFuture;
|
||||
if (!await bridgeFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final content = await bridgeFile.readAsString();
|
||||
return BuiltInBridges.fromJson(jsonDecode(content) as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
Future<BuiltInBridges> getBundledBuiltinBridges() async {
|
||||
final content = await rootBundle.loadString(
|
||||
'assets/preferences/builtin-bridges.json',
|
||||
);
|
||||
return BuiltInBridges.fromJson(jsonDecode(content) as Map<String, dynamic>);
|
||||
}
|
||||
|
||||
@override
|
||||
void build() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'builtin_bridges.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$builtinBridgesServiceHash() =>
|
||||
r'beacb3c9d8c5a7179c7c9cad8024d128b09241f5';
|
||||
|
||||
/// See also [BuiltinBridgesService].
|
||||
@ProviderFor(BuiltinBridgesService)
|
||||
final builtinBridgesServiceProvider =
|
||||
NotifierProvider<BuiltinBridgesService, void>.internal(
|
||||
BuiltinBridgesService.new,
|
||||
name: r'builtinBridgesServiceProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$builtinBridgesServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$BuiltinBridgesService = Notifier<void>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -0,0 +1,49 @@
|
||||
import 'package:pluggable_transports_proxy/pluggable_transports_proxy.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:weblibre/core/logger.dart';
|
||||
import 'package:weblibre/features/tor/data/services/builtin_bridges.dart';
|
||||
|
||||
part 'builtin_bridges.g.dart';
|
||||
|
||||
@Riverpod()
|
||||
class BuiltinBridgesRepository extends _$BuiltinBridgesRepository {
|
||||
Future<void> updateIfNecessary() async {
|
||||
final lastUpdate = await ref
|
||||
.read(builtinBridgesServiceProvider.notifier)
|
||||
.lastUpdate();
|
||||
|
||||
if (lastUpdate == null ||
|
||||
DateTime.now().difference(lastUpdate) > const Duration(days: 2)) {
|
||||
BuiltInBridges? remoteBridges;
|
||||
try {
|
||||
remoteBridges = await service.getBuiltinBridges();
|
||||
} catch (e, s) {
|
||||
logger.e('Failed fetching builtin bridges', error: e, stackTrace: s);
|
||||
}
|
||||
|
||||
if (remoteBridges != null) {
|
||||
await ref
|
||||
.read(builtinBridgesServiceProvider.notifier)
|
||||
.updateStoredBuiltinBridges(remoteBridges);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<BuiltInBridges> getBridges({bool tryUpdate = true}) async {
|
||||
if (tryUpdate) {
|
||||
await updateIfNecessary();
|
||||
}
|
||||
|
||||
final storedBridges = await ref
|
||||
.read(builtinBridgesServiceProvider.notifier)
|
||||
.getStoredBuiltinBridges();
|
||||
|
||||
return storedBridges ??
|
||||
await ref
|
||||
.read(builtinBridgesServiceProvider.notifier)
|
||||
.getBundledBuiltinBridges();
|
||||
}
|
||||
|
||||
@override
|
||||
void build(MoatService service) {}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'builtin_bridges.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$builtinBridgesRepositoryHash() =>
|
||||
r'05fc40a7742fc266aeb76b4e3f1d9bdfdb8d448f';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
abstract class _$BuiltinBridgesRepository
|
||||
extends BuildlessAutoDisposeNotifier<void> {
|
||||
late final MoatService service;
|
||||
|
||||
void build(MoatService service);
|
||||
}
|
||||
|
||||
/// See also [BuiltinBridgesRepository].
|
||||
@ProviderFor(BuiltinBridgesRepository)
|
||||
const builtinBridgesRepositoryProvider = BuiltinBridgesRepositoryFamily();
|
||||
|
||||
/// See also [BuiltinBridgesRepository].
|
||||
class BuiltinBridgesRepositoryFamily extends Family<void> {
|
||||
/// See also [BuiltinBridgesRepository].
|
||||
const BuiltinBridgesRepositoryFamily();
|
||||
|
||||
/// See also [BuiltinBridgesRepository].
|
||||
BuiltinBridgesRepositoryProvider call(MoatService service) {
|
||||
return BuiltinBridgesRepositoryProvider(service);
|
||||
}
|
||||
|
||||
@override
|
||||
BuiltinBridgesRepositoryProvider getProviderOverride(
|
||||
covariant BuiltinBridgesRepositoryProvider provider,
|
||||
) {
|
||||
return call(provider.service);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'builtinBridgesRepositoryProvider';
|
||||
}
|
||||
|
||||
/// See also [BuiltinBridgesRepository].
|
||||
class BuiltinBridgesRepositoryProvider
|
||||
extends AutoDisposeNotifierProviderImpl<BuiltinBridgesRepository, void> {
|
||||
/// See also [BuiltinBridgesRepository].
|
||||
BuiltinBridgesRepositoryProvider(MoatService service)
|
||||
: this._internal(
|
||||
() => BuiltinBridgesRepository()..service = service,
|
||||
from: builtinBridgesRepositoryProvider,
|
||||
name: r'builtinBridgesRepositoryProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$builtinBridgesRepositoryHash,
|
||||
dependencies: BuiltinBridgesRepositoryFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
BuiltinBridgesRepositoryFamily._allTransitiveDependencies,
|
||||
service: service,
|
||||
);
|
||||
|
||||
BuiltinBridgesRepositoryProvider._internal(
|
||||
super._createNotifier, {
|
||||
required super.name,
|
||||
required super.dependencies,
|
||||
required super.allTransitiveDependencies,
|
||||
required super.debugGetCreateSourceHash,
|
||||
required super.from,
|
||||
required this.service,
|
||||
}) : super.internal();
|
||||
|
||||
final MoatService service;
|
||||
|
||||
@override
|
||||
void runNotifierBuild(covariant BuiltinBridgesRepository notifier) {
|
||||
return notifier.build(service);
|
||||
}
|
||||
|
||||
@override
|
||||
Override overrideWith(BuiltinBridgesRepository Function() create) {
|
||||
return ProviderOverride(
|
||||
origin: this,
|
||||
override: BuiltinBridgesRepositoryProvider._internal(
|
||||
() => create()..service = service,
|
||||
from: from,
|
||||
name: null,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
debugGetCreateSourceHash: null,
|
||||
service: service,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
AutoDisposeNotifierProviderElement<BuiltinBridgesRepository, void>
|
||||
createElement() {
|
||||
return _BuiltinBridgesRepositoryProviderElement(this);
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is BuiltinBridgesRepositoryProvider &&
|
||||
other.service == service;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, service.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated('Will be removed in 3.0. Use Ref instead')
|
||||
// ignore: unused_element
|
||||
mixin BuiltinBridgesRepositoryRef on AutoDisposeNotifierProviderRef<void> {
|
||||
/// The parameter `service` of this provider.
|
||||
MoatService get service;
|
||||
}
|
||||
|
||||
class _BuiltinBridgesRepositoryProviderElement
|
||||
extends AutoDisposeNotifierProviderElement<BuiltinBridgesRepository, void>
|
||||
with BuiltinBridgesRepositoryRef {
|
||||
_BuiltinBridgesRepositoryProviderElement(super.provider);
|
||||
|
||||
@override
|
||||
MoatService get service =>
|
||||
(origin as BuiltinBridgesRepositoryProvider).service;
|
||||
}
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -20,13 +20,17 @@
|
||||
import 'dart:async';
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter_background_service/flutter_background_service.dart';
|
||||
import 'package:nullability/nullability.dart';
|
||||
import 'package:pluggable_transports_proxy/pluggable_transports_proxy.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
import 'package:weblibre/core/logger.dart';
|
||||
import 'package:weblibre/features/geckoview/features/browser/domain/providers/lifecycle.dart';
|
||||
import 'package:weblibre/features/tor/domain/repositories/builtin_bridges.dart';
|
||||
import 'package:weblibre/features/tor/utils/tor_entrypoint.dart';
|
||||
import 'package:weblibre/features/user/data/models/tor_settings.dart';
|
||||
import 'package:weblibre/features/user/domain/repositories/tor_settings.dart';
|
||||
|
||||
part 'tor_proxy.g.dart';
|
||||
@@ -38,9 +42,19 @@ class _TorService {
|
||||
|
||||
ValueStream<int?> get portStream => _portSubject.stream;
|
||||
|
||||
Future<void> start({ProxyType? proxyType, String? bridgeLines}) async {
|
||||
Future<void> startOrReconfigure({
|
||||
ProxyType? proxyType,
|
||||
String? bridgeLines,
|
||||
}) async {
|
||||
await service.startService();
|
||||
service.invoke('start', {
|
||||
service.invoke('startOrReconfigure', {
|
||||
if (proxyType != null) 'proxyType': proxyType.name,
|
||||
if (bridgeLines != null) 'bridgeLines': bridgeLines,
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> reconfigure({ProxyType? proxyType, String? bridgeLines}) async {
|
||||
service.invoke('reconfigure', {
|
||||
if (proxyType != null) 'proxyType': proxyType.name,
|
||||
if (bridgeLines != null) 'bridgeLines': bridgeLines,
|
||||
});
|
||||
@@ -101,7 +115,7 @@ class TorProxyService extends _$TorProxyService {
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> connect({bool forceReconnect = false}) async {
|
||||
Future<void> startOrReconfigure({bool forceReconnect = false}) async {
|
||||
final currentPort = await requestSync();
|
||||
|
||||
if (currentPort == null || forceReconnect) {
|
||||
@@ -111,14 +125,97 @@ class TorProxyService extends _$TorProxyService {
|
||||
.read(torSettingsRepositoryProvider.notifier)
|
||||
.fetchSettings();
|
||||
|
||||
if (torSettings.autoConfig) {
|
||||
final moat = MoatService();
|
||||
final config = await moat.autoConf();
|
||||
Setting? setting;
|
||||
if (torSettings.config == TorConnectionConfig.auto) {
|
||||
List<Setting>? config;
|
||||
|
||||
todo
|
||||
final moat = MoatService();
|
||||
try {
|
||||
await moat.initialize();
|
||||
config = await moat.autoConf(
|
||||
cannotConnectWithoutPt: torSettings.requireBridge,
|
||||
);
|
||||
|
||||
if (config == null && torSettings.requireBridge) {
|
||||
config = MoatService.convertBuiltinToSettings(
|
||||
await ref
|
||||
.read(builtinBridgesRepositoryProvider(moat).notifier)
|
||||
.getBridges(),
|
||||
);
|
||||
}
|
||||
} catch (e, s) {
|
||||
logger.e('Failed auto configure bridges', error: e, stackTrace: s);
|
||||
} finally {
|
||||
await moat.dispose();
|
||||
}
|
||||
|
||||
setting = config.mapNotNull(
|
||||
(config) =>
|
||||
config.firstWhereOrNull(
|
||||
(setting) => setting.bridge.type == TransportType.obfs4,
|
||||
) ??
|
||||
config.firstWhereOrNull(
|
||||
(setting) => setting.bridge.type == TransportType.snowflake,
|
||||
),
|
||||
);
|
||||
} else if (torSettings.config != TorConnectionConfig.direct) {
|
||||
List<Setting>? config;
|
||||
|
||||
final moat = MoatService();
|
||||
try {
|
||||
await moat.initialize();
|
||||
if (torSettings.fetchRemoteBridges) {
|
||||
config = await moat.getDefaultBridges();
|
||||
}
|
||||
|
||||
if (config == null && torSettings.requireBridge) {
|
||||
config = MoatService.convertBuiltinToSettings(
|
||||
await ref
|
||||
.read(builtinBridgesRepositoryProvider(moat).notifier)
|
||||
.getBridges(tryUpdate: torSettings.fetchRemoteBridges),
|
||||
);
|
||||
}
|
||||
|
||||
setting = config.mapNotNull(
|
||||
(config) => config.firstWhereOrNull(
|
||||
(setting) =>
|
||||
setting.bridge.type ==
|
||||
switch (torSettings.config) {
|
||||
TorConnectionConfig.auto => throw UnimplementedError(),
|
||||
TorConnectionConfig.direct => throw UnimplementedError(),
|
||||
TorConnectionConfig.obfs4 => TransportType.obfs4,
|
||||
TorConnectionConfig.snowflake => TransportType.snowflake,
|
||||
},
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
logger.e('Failed auto configure bridges', error: e, stackTrace: s);
|
||||
} finally {
|
||||
await moat.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
if (setting != null) {
|
||||
switch (setting.bridge.type) {
|
||||
case TransportType.obfs4:
|
||||
await _tor.startOrReconfigure(
|
||||
proxyType: ProxyType.obfs4,
|
||||
bridgeLines: setting.bridge.bridges?.join('\n'),
|
||||
);
|
||||
case TransportType.snowflake:
|
||||
await _tor.startOrReconfigure(
|
||||
proxyType: ProxyType.snowflake,
|
||||
bridgeLines: setting.bridge.bridges?.join('\n'),
|
||||
);
|
||||
case TransportType.meek:
|
||||
case TransportType.meekAzure:
|
||||
case TransportType.webtunnel:
|
||||
throw UnimplementedError();
|
||||
}
|
||||
} else {
|
||||
await _tor.startOrReconfigure();
|
||||
}
|
||||
|
||||
await _tor.start();
|
||||
_enableHeartbeatTimer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'tor_proxy.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$torProxyServiceHash() => r'82b4964ddf14d02893ebbea3b25d91216359ba10';
|
||||
|
||||
/// See also [TorProxyService].
|
||||
@ProviderFor(TorProxyService)
|
||||
final torProxyServiceProvider =
|
||||
AsyncNotifierProvider<TorProxyService, int?>.internal(
|
||||
TorProxyService.new,
|
||||
name: r'torProxyServiceProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$torProxyServiceHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$TorProxyService = AsyncNotifier<int?>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package
|
||||
@@ -47,7 +47,7 @@ class StartProxyController extends _$StartProxyController {
|
||||
if (result == true) {
|
||||
final connection = ref
|
||||
.read(torProxyServiceProvider.notifier)
|
||||
.connect();
|
||||
.startOrReconfigure();
|
||||
|
||||
ref
|
||||
.read(overlayControllerProvider.notifier)
|
||||
@@ -59,6 +59,9 @@ class StartProxyController extends _$StartProxyController {
|
||||
await connection;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Reconfigure
|
||||
await ref.read(torProxyServiceProvider.notifier).startOrReconfigure();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ part of 'start_tor_proxy.dart';
|
||||
// **************************************************************************
|
||||
|
||||
String _$startProxyControllerHash() =>
|
||||
r'3e8b409f069f32b601b1c60acbe0a72694fd1cc2';
|
||||
r'8840d5ffe9346c3f8b0aa0b3e034605b606c5e34';
|
||||
|
||||
/// See also [StartProxyController].
|
||||
@ProviderFor(StartProxyController)
|
||||
|
||||
@@ -39,6 +39,14 @@ class TorProxyScreen extends HookConsumerWidget {
|
||||
await ref.read(torProxyServiceProvider.notifier).requestSync();
|
||||
});
|
||||
|
||||
ref.listen(torSettingsRepositoryProvider, (previous, next) async {
|
||||
final torService = ref.read(torProxyServiceProvider.notifier);
|
||||
|
||||
if (await torService.requestSync() != null) {
|
||||
await torService.startOrReconfigure();
|
||||
}
|
||||
});
|
||||
|
||||
return Scaffold(
|
||||
appBar: AppBar(title: const Text('Tor™ Proxy')),
|
||||
body: SafeArea(
|
||||
@@ -46,9 +54,8 @@ class TorProxyScreen extends HookConsumerWidget {
|
||||
color: const Color(0xFF7D4698),
|
||||
child: Column(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
const Icon(TorIcons.onionAlt, size: 84),
|
||||
const SizedBox(height: 16),
|
||||
@@ -92,7 +99,7 @@ class TorProxyScreen extends HookConsumerWidget {
|
||||
if (value) {
|
||||
await ref
|
||||
.read(torProxyServiceProvider.notifier)
|
||||
.connect();
|
||||
.startOrReconfigure();
|
||||
} else {
|
||||
await ref
|
||||
.read(torProxyServiceProvider.notifier)
|
||||
@@ -137,7 +144,7 @@ class TorProxyScreen extends HookConsumerWidget {
|
||||
subtitle: const Text(
|
||||
'When enabled, all Private Tabs will be tunneled through Tor',
|
||||
),
|
||||
secondary: const Icon(MdiIcons.arrowDecision),
|
||||
secondary: const Icon(MdiIcons.incognito),
|
||||
onChanged: (value) async {
|
||||
await ref
|
||||
.read(saveTorSettingsControllerProvider.notifier)
|
||||
@@ -179,27 +186,173 @@ class TorProxyScreen extends HookConsumerWidget {
|
||||
}
|
||||
return null; // Use the default color.
|
||||
}),
|
||||
value: torSettings.autoConfig,
|
||||
title: const Text('Configure Transport Automatically'),
|
||||
value: torSettings.config == TorConnectionConfig.auto,
|
||||
title: const Text('Auto Configure Transport'),
|
||||
subtitle: const Text(
|
||||
'From some locations, it is necessary to use a pluggable transport to connect to the Tor network that is otherwise blocked. Turn off automatic configuration to manually configure how Tor connects.',
|
||||
'From some locations, it is necessary to use a pluggable transport to connect to Tor',
|
||||
),
|
||||
secondary: const Icon(MdiIcons.arrowDecision),
|
||||
onChanged: (value) async {
|
||||
await ref
|
||||
.read(saveTorSettingsControllerProvider.notifier)
|
||||
.save(
|
||||
(currentSettings) =>
|
||||
currentSettings.copyWith.autoConfig(value),
|
||||
);
|
||||
},
|
||||
secondary: const Icon(MdiIcons.arrowDecisionAuto),
|
||||
onChanged: torProxyPort.isLoading
|
||||
? null
|
||||
: (value) async {
|
||||
await ref
|
||||
.read(
|
||||
saveTorSettingsControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.save(
|
||||
(currentSettings) =>
|
||||
currentSettings.copyWith.config(
|
||||
value
|
||||
? TorConnectionConfig.auto
|
||||
: TorConnectionConfig.direct,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
if (torSettings.config == TorConnectionConfig.auto) ...[
|
||||
SwitchListTile.adaptive(
|
||||
value: torSettings.requireBridge,
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 56,
|
||||
right: 24,
|
||||
),
|
||||
onChanged: torProxyPort.isLoading
|
||||
? null
|
||||
: (value) async {
|
||||
await ref
|
||||
.read(
|
||||
saveTorSettingsControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.save(
|
||||
(currentSettings) => currentSettings
|
||||
.copyWith
|
||||
.requireBridge(value),
|
||||
);
|
||||
},
|
||||
title: const Text(
|
||||
"I'm sure I cannot connect without a bridge",
|
||||
),
|
||||
),
|
||||
] else ...[
|
||||
RadioGroup(
|
||||
groupValue: torSettings.config,
|
||||
onChanged: (value) async {
|
||||
if (value != null) {
|
||||
await ref
|
||||
.read(
|
||||
saveTorSettingsControllerProvider.notifier,
|
||||
)
|
||||
.save(
|
||||
(currentSettings) =>
|
||||
currentSettings.copyWith.config(value),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: RadioListTile.adaptive(
|
||||
value: TorConnectionConfig.direct,
|
||||
enabled: !torProxyPort.isLoading,
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 56,
|
||||
right: 24,
|
||||
),
|
||||
title: Text('Direct Connection'),
|
||||
subtitle: Text(
|
||||
'The best way to connect to Tor if Tor is not blocked',
|
||||
),
|
||||
),
|
||||
),
|
||||
RadioGroup(
|
||||
groupValue: torSettings.config,
|
||||
onChanged: (value) async {
|
||||
if (value != null) {
|
||||
await ref
|
||||
.read(
|
||||
saveTorSettingsControllerProvider.notifier,
|
||||
)
|
||||
.save(
|
||||
(currentSettings) =>
|
||||
currentSettings.copyWith.config(value),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: RadioListTile.adaptive(
|
||||
value: TorConnectionConfig.obfs4,
|
||||
enabled: !torProxyPort.isLoading,
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 56,
|
||||
right: 24,
|
||||
),
|
||||
title: Text('obfs4'),
|
||||
subtitle: Text(
|
||||
'Suitable for light censorship and high bandwidth needs',
|
||||
),
|
||||
),
|
||||
),
|
||||
RadioGroup(
|
||||
groupValue: torSettings.config,
|
||||
onChanged: (value) async {
|
||||
if (value != null) {
|
||||
await ref
|
||||
.read(
|
||||
saveTorSettingsControllerProvider.notifier,
|
||||
)
|
||||
.save(
|
||||
(currentSettings) =>
|
||||
currentSettings.copyWith.config(value),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: RadioListTile.adaptive(
|
||||
value: TorConnectionConfig.snowflake,
|
||||
enabled: !torProxyPort.isLoading,
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 56,
|
||||
right: 24,
|
||||
),
|
||||
title: Text('Snowflake'),
|
||||
subtitle: Text('Suitable for heavy censorship'),
|
||||
),
|
||||
),
|
||||
CheckboxListTile.adaptive(
|
||||
value: torSettings.fetchRemoteBridges,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
enabled:
|
||||
torSettings.config != TorConnectionConfig.direct,
|
||||
contentPadding: const EdgeInsets.only(
|
||||
left: 56,
|
||||
right: 24,
|
||||
),
|
||||
onChanged: torProxyPort.isLoading
|
||||
? null
|
||||
: (value) async {
|
||||
if (value != null) {
|
||||
await ref
|
||||
.read(
|
||||
saveTorSettingsControllerProvider
|
||||
.notifier,
|
||||
)
|
||||
.save(
|
||||
(currentSettings) => currentSettings
|
||||
.copyWith
|
||||
.fetchRemoteBridges(value),
|
||||
);
|
||||
}
|
||||
},
|
||||
title: const Text(
|
||||
"Fetch fresh Bridges before connecting",
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (torProxyPort.isLoading)
|
||||
const Column(
|
||||
|
||||
@@ -35,16 +35,19 @@ Future<void> onStart(ServiceInstance service) async {
|
||||
service.invoke('portUpdate', {'port': port});
|
||||
});
|
||||
|
||||
Future<void> stopProxies() async {
|
||||
for (final proxyType in startedProxyType) {
|
||||
await IPtProxyController().stop(proxyType);
|
||||
}
|
||||
startedProxyType.clear();
|
||||
}
|
||||
|
||||
Future<void> stopService() async {
|
||||
timeout?.cancel();
|
||||
timeout = null;
|
||||
|
||||
Tor.instance.stop();
|
||||
|
||||
for (final proxyType in startedProxyType) {
|
||||
await IPtProxyController().stop(proxyType);
|
||||
}
|
||||
startedProxyType.clear();
|
||||
await stopProxies();
|
||||
|
||||
service.invoke('portUpdate', {'port': -1});
|
||||
|
||||
@@ -84,12 +87,57 @@ Future<void> onStart(ServiceInstance service) async {
|
||||
}
|
||||
}
|
||||
|
||||
service.on("start").listen((event) async {
|
||||
Future<void> reconfigureService(
|
||||
ProxyType? proxyType,
|
||||
String? bridgeLines,
|
||||
) async {
|
||||
if (Tor.instance.hasClient) {
|
||||
await stopProxies();
|
||||
|
||||
if (proxyType != null) {
|
||||
final port = await IPtProxyController().start(proxyType, "");
|
||||
startedProxyType.add(proxyType);
|
||||
|
||||
switch (proxyType) {
|
||||
case ProxyType.obfs4:
|
||||
await Tor.instance.reconfigure(
|
||||
obfs4Port: port,
|
||||
bridgeLines: bridgeLines,
|
||||
);
|
||||
case ProxyType.meekLite:
|
||||
throw UnimplementedError();
|
||||
case ProxyType.webtunnel:
|
||||
throw UnimplementedError();
|
||||
case ProxyType.snowflake:
|
||||
await Tor.instance.reconfigure(
|
||||
snowflakePort: port,
|
||||
bridgeLines: bridgeLines,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
await Tor.instance.reconfigure();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
service.on("startOrReconfigure").listen((event) async {
|
||||
final proxyType = ProxyType.values.firstWhereOrNull(
|
||||
(x) => x.name == event?['proxyType'],
|
||||
);
|
||||
|
||||
await startService(proxyType, event?['bridgeLines'] as String?);
|
||||
await reconfigureService(proxyType, event?['bridgeLines'] as String?);
|
||||
|
||||
if (!Tor.instance.hasClient) {
|
||||
await startService(proxyType, event?['bridgeLines'] as String?);
|
||||
}
|
||||
});
|
||||
|
||||
service.on("reconfigure").listen((event) async {
|
||||
final proxyType = ProxyType.values.firstWhereOrNull(
|
||||
(x) => x.name == event?['proxyType'],
|
||||
);
|
||||
|
||||
await reconfigureService(proxyType, event?['bridgeLines'] as String?);
|
||||
});
|
||||
|
||||
service.on("heartbeat").listen((event) {
|
||||
|
||||
@@ -42,7 +42,12 @@ class SettingDao extends DatabaseAccessor<UserDatabase> with _$SettingDaoMixin {
|
||||
partitionKey: Value(partitionKey),
|
||||
value: Value(driftvalue),
|
||||
),
|
||||
onConflict: DoUpdate((old) => SettingCompanion(value: Value(driftvalue))),
|
||||
onConflict: DoUpdate(
|
||||
(old) => SettingCompanion(
|
||||
partitionKey: Value(partitionKey),
|
||||
value: Value(driftvalue),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -266,7 +266,8 @@ Map<String, dynamic> _$GeneralSettingsToJson(
|
||||
'showExtensionShortcut': instance.showExtensionShortcut,
|
||||
'enableLocalAiFeatures': instance.enableLocalAiFeatures,
|
||||
'defaultCreateTabType': _$TabTypeEnumMap[instance.defaultCreateTabType]!,
|
||||
'defaultIntentTabType': _$TabTypeEnumMap[instance.defaultIntentTabType]!,
|
||||
'tabIntentOpenSetting':
|
||||
_$TabIntentOpenSettingEnumMap[instance.tabIntentOpenSetting]!,
|
||||
'autoHideTabBar': instance.autoHideTabBar,
|
||||
'tabBarSwipeAction': _$TabBarSwipeActionEnumMap[instance.tabBarSwipeAction]!,
|
||||
};
|
||||
|
||||
@@ -4,17 +4,32 @@ import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'tor_settings.g.dart';
|
||||
|
||||
enum TorConnectionConfig { auto, direct, obfs4, snowflake }
|
||||
|
||||
@CopyWith()
|
||||
@JsonSerializable(includeIfNull: true, constructor: 'withDefaults')
|
||||
class TorSettings with FastEquatable {
|
||||
final bool proxyPrivateTabsTor;
|
||||
final bool autoConfig;
|
||||
final TorConnectionConfig config;
|
||||
final bool requireBridge;
|
||||
final bool fetchRemoteBridges;
|
||||
|
||||
TorSettings({required this.proxyPrivateTabsTor, required this.autoConfig});
|
||||
TorSettings({
|
||||
required this.proxyPrivateTabsTor,
|
||||
required this.config,
|
||||
required this.requireBridge,
|
||||
required this.fetchRemoteBridges,
|
||||
});
|
||||
|
||||
TorSettings.withDefaults({bool? proxyPrivateTabsTor, bool? autoConfig})
|
||||
: proxyPrivateTabsTor = proxyPrivateTabsTor ?? false,
|
||||
autoConfig = autoConfig ?? true;
|
||||
TorSettings.withDefaults({
|
||||
bool? proxyPrivateTabsTor,
|
||||
TorConnectionConfig? config,
|
||||
bool? requireBridge,
|
||||
bool? fetchRemoteBridges,
|
||||
}) : proxyPrivateTabsTor = proxyPrivateTabsTor ?? false,
|
||||
config = config ?? TorConnectionConfig.auto,
|
||||
requireBridge = requireBridge ?? false,
|
||||
fetchRemoteBridges = fetchRemoteBridges ?? true;
|
||||
|
||||
factory TorSettings.fromJson(Map<String, dynamic> json) =>
|
||||
_$TorSettingsFromJson(json);
|
||||
@@ -22,5 +37,10 @@ class TorSettings with FastEquatable {
|
||||
Map<String, dynamic> toJson() => _$TorSettingsToJson(this);
|
||||
|
||||
@override
|
||||
List<Object?> get hashParameters => [proxyPrivateTabsTor, autoConfig];
|
||||
List<Object?> get hashParameters => [
|
||||
proxyPrivateTabsTor,
|
||||
config,
|
||||
requireBridge,
|
||||
fetchRemoteBridges,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@ part of 'tor_settings.dart';
|
||||
abstract class _$TorSettingsCWProxy {
|
||||
TorSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
||||
|
||||
TorSettings autoConfig(bool autoConfig);
|
||||
TorSettings config(TorConnectionConfig config);
|
||||
|
||||
TorSettings requireBridge(bool requireBridge);
|
||||
|
||||
TorSettings fetchRemoteBridges(bool fetchRemoteBridges);
|
||||
|
||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TorSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||
///
|
||||
@@ -17,7 +21,12 @@ abstract class _$TorSettingsCWProxy {
|
||||
/// ```dart
|
||||
/// TorSettings(...).copyWith(id: 12, name: "My name")
|
||||
/// ````
|
||||
TorSettings call({bool proxyPrivateTabsTor, bool autoConfig});
|
||||
TorSettings call({
|
||||
bool proxyPrivateTabsTor,
|
||||
TorConnectionConfig config,
|
||||
bool requireBridge,
|
||||
bool fetchRemoteBridges,
|
||||
});
|
||||
}
|
||||
|
||||
/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfTorSettings.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfTorSettings.copyWith.fieldName(...)`
|
||||
@@ -31,7 +40,15 @@ class _$TorSettingsCWProxyImpl implements _$TorSettingsCWProxy {
|
||||
this(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
||||
|
||||
@override
|
||||
TorSettings autoConfig(bool autoConfig) => this(autoConfig: autoConfig);
|
||||
TorSettings config(TorConnectionConfig config) => this(config: config);
|
||||
|
||||
@override
|
||||
TorSettings requireBridge(bool requireBridge) =>
|
||||
this(requireBridge: requireBridge);
|
||||
|
||||
@override
|
||||
TorSettings fetchRemoteBridges(bool fetchRemoteBridges) =>
|
||||
this(fetchRemoteBridges: fetchRemoteBridges);
|
||||
|
||||
@override
|
||||
/// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `TorSettings(...).copyWith.fieldName(...)` to override fields one at a time with nullification support.
|
||||
@@ -42,17 +59,27 @@ class _$TorSettingsCWProxyImpl implements _$TorSettingsCWProxy {
|
||||
/// ````
|
||||
TorSettings call({
|
||||
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
||||
Object? autoConfig = const $CopyWithPlaceholder(),
|
||||
Object? config = const $CopyWithPlaceholder(),
|
||||
Object? requireBridge = const $CopyWithPlaceholder(),
|
||||
Object? fetchRemoteBridges = const $CopyWithPlaceholder(),
|
||||
}) {
|
||||
return TorSettings(
|
||||
proxyPrivateTabsTor: proxyPrivateTabsTor == const $CopyWithPlaceholder()
|
||||
? _value.proxyPrivateTabsTor
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: proxyPrivateTabsTor as bool,
|
||||
autoConfig: autoConfig == const $CopyWithPlaceholder()
|
||||
? _value.autoConfig
|
||||
config: config == const $CopyWithPlaceholder()
|
||||
? _value.config
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: autoConfig as bool,
|
||||
: config as TorConnectionConfig,
|
||||
requireBridge: requireBridge == const $CopyWithPlaceholder()
|
||||
? _value.requireBridge
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: requireBridge as bool,
|
||||
fetchRemoteBridges: fetchRemoteBridges == const $CopyWithPlaceholder()
|
||||
? _value.fetchRemoteBridges
|
||||
// ignore: cast_nullable_to_non_nullable
|
||||
: fetchRemoteBridges as bool,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -70,11 +97,22 @@ extension $TorSettingsCopyWith on TorSettings {
|
||||
TorSettings _$TorSettingsFromJson(Map<String, dynamic> json) =>
|
||||
TorSettings.withDefaults(
|
||||
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
||||
autoConfig: json['autoConfig'] as bool?,
|
||||
config: $enumDecodeNullable(_$TorConnectionConfigEnumMap, json['config']),
|
||||
requireBridge: json['requireBridge'] as bool?,
|
||||
fetchRemoteBridges: json['fetchRemoteBridges'] as bool?,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$TorSettingsToJson(TorSettings instance) =>
|
||||
<String, dynamic>{
|
||||
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
||||
'autoConfig': instance.autoConfig,
|
||||
'config': _$TorConnectionConfigEnumMap[instance.config]!,
|
||||
'requireBridge': instance.requireBridge,
|
||||
'fetchRemoteBridges': instance.fetchRemoteBridges,
|
||||
};
|
||||
|
||||
const _$TorConnectionConfigEnumMap = {
|
||||
TorConnectionConfig.auto: 'auto',
|
||||
TorConnectionConfig.direct: 'direct',
|
||||
TorConnectionConfig.obfs4: 'obfs4',
|
||||
TorConnectionConfig.snowflake: 'snowflake',
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ final generalSettingsWithDefaultsProvider =
|
||||
typedef GeneralSettingsWithDefaultsRef =
|
||||
AutoDisposeProviderRef<GeneralSettings>;
|
||||
String _$generalSettingsRepositoryHash() =>
|
||||
r'07eeaf811fac4b9c787cce7c29379a7329910ae5';
|
||||
r'0d207ae4ae9fd94b1257eb8aa4cfd73d4a47caf2';
|
||||
|
||||
/// See also [GeneralSettingsRepository].
|
||||
@ProviderFor(GeneralSettingsRepository)
|
||||
|
||||
@@ -23,7 +23,12 @@ class TorSettingsRepository extends _$TorSettingsRepository {
|
||||
DriftSqlType.bool,
|
||||
db.typeMapping,
|
||||
),
|
||||
'autoConfig': settings['autoConfig']?.readAs(
|
||||
'config': settings['config']?.readAs(DriftSqlType.string, db.typeMapping),
|
||||
'requireBridge': settings['requireBridge']?.readAs(
|
||||
DriftSqlType.bool,
|
||||
db.typeMapping,
|
||||
),
|
||||
'fetchRemoteBridges': settings['fetchRemoteBridges']?.readAs(
|
||||
DriftSqlType.bool,
|
||||
db.typeMapping,
|
||||
),
|
||||
|
||||
@@ -26,7 +26,7 @@ final torSettingsWithDefaultsProvider =
|
||||
// ignore: unused_element
|
||||
typedef TorSettingsWithDefaultsRef = AutoDisposeProviderRef<TorSettings>;
|
||||
String _$torSettingsRepositoryHash() =>
|
||||
r'686e8576453f33a0d2d0eb2869e29ca88e00bc37';
|
||||
r'ef80d1cc6b9b72cce371c03c656b10a0924d49d0';
|
||||
|
||||
/// See also [TorSettingsRepository].
|
||||
@ProviderFor(TorSettingsRepository)
|
||||
|
||||
Reference in New Issue
Block a user