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
|
* 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/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:fading_scroll/fading_scroll.dart';
|
import 'package:fading_scroll/fading_scroll.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hooks/flutter_hooks.dart';
|
import 'package:flutter_hooks/flutter_hooks.dart';
|
||||||
@@ -163,6 +166,38 @@ class DeveloperSettingsScreen extends HookConsumerWidget {
|
|||||||
label: const Text('Copy'),
|
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:async';
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter_background_service/flutter_background_service.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:pluggable_transports_proxy/pluggable_transports_proxy.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
import 'package:rxdart/rxdart.dart';
|
import 'package:rxdart/rxdart.dart';
|
||||||
import 'package:weblibre/core/logger.dart';
|
import 'package:weblibre/core/logger.dart';
|
||||||
import 'package:weblibre/features/geckoview/features/browser/domain/providers/lifecycle.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/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';
|
import 'package:weblibre/features/user/domain/repositories/tor_settings.dart';
|
||||||
|
|
||||||
part 'tor_proxy.g.dart';
|
part 'tor_proxy.g.dart';
|
||||||
@@ -38,9 +42,19 @@ class _TorService {
|
|||||||
|
|
||||||
ValueStream<int?> get portStream => _portSubject.stream;
|
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();
|
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 (proxyType != null) 'proxyType': proxyType.name,
|
||||||
if (bridgeLines != null) 'bridgeLines': bridgeLines,
|
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();
|
final currentPort = await requestSync();
|
||||||
|
|
||||||
if (currentPort == null || forceReconnect) {
|
if (currentPort == null || forceReconnect) {
|
||||||
@@ -111,14 +125,97 @@ class TorProxyService extends _$TorProxyService {
|
|||||||
.read(torSettingsRepositoryProvider.notifier)
|
.read(torSettingsRepositoryProvider.notifier)
|
||||||
.fetchSettings();
|
.fetchSettings();
|
||||||
|
|
||||||
if (torSettings.autoConfig) {
|
Setting? setting;
|
||||||
final moat = MoatService();
|
if (torSettings.config == TorConnectionConfig.auto) {
|
||||||
final config = await moat.autoConf();
|
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();
|
_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) {
|
if (result == true) {
|
||||||
final connection = ref
|
final connection = ref
|
||||||
.read(torProxyServiceProvider.notifier)
|
.read(torProxyServiceProvider.notifier)
|
||||||
.connect();
|
.startOrReconfigure();
|
||||||
|
|
||||||
ref
|
ref
|
||||||
.read(overlayControllerProvider.notifier)
|
.read(overlayControllerProvider.notifier)
|
||||||
@@ -59,6 +59,9 @@ class StartProxyController extends _$StartProxyController {
|
|||||||
await connection;
|
await connection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
//Reconfigure
|
||||||
|
await ref.read(torProxyServiceProvider.notifier).startOrReconfigure();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ part of 'start_tor_proxy.dart';
|
|||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$startProxyControllerHash() =>
|
String _$startProxyControllerHash() =>
|
||||||
r'3e8b409f069f32b601b1c60acbe0a72694fd1cc2';
|
r'8840d5ffe9346c3f8b0aa0b3e034605b606c5e34';
|
||||||
|
|
||||||
/// See also [StartProxyController].
|
/// See also [StartProxyController].
|
||||||
@ProviderFor(StartProxyController)
|
@ProviderFor(StartProxyController)
|
||||||
|
|||||||
@@ -39,6 +39,14 @@ class TorProxyScreen extends HookConsumerWidget {
|
|||||||
await ref.read(torProxyServiceProvider.notifier).requestSync();
|
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(
|
return Scaffold(
|
||||||
appBar: AppBar(title: const Text('Tor™ Proxy')),
|
appBar: AppBar(title: const Text('Tor™ Proxy')),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
@@ -46,9 +54,8 @@ class TorProxyScreen extends HookConsumerWidget {
|
|||||||
color: const Color(0xFF7D4698),
|
color: const Color(0xFF7D4698),
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Expanded(
|
||||||
child: Column(
|
child: ListView(
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
children: [
|
||||||
const Icon(TorIcons.onionAlt, size: 84),
|
const Icon(TorIcons.onionAlt, size: 84),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
@@ -92,7 +99,7 @@ class TorProxyScreen extends HookConsumerWidget {
|
|||||||
if (value) {
|
if (value) {
|
||||||
await ref
|
await ref
|
||||||
.read(torProxyServiceProvider.notifier)
|
.read(torProxyServiceProvider.notifier)
|
||||||
.connect();
|
.startOrReconfigure();
|
||||||
} else {
|
} else {
|
||||||
await ref
|
await ref
|
||||||
.read(torProxyServiceProvider.notifier)
|
.read(torProxyServiceProvider.notifier)
|
||||||
@@ -137,7 +144,7 @@ class TorProxyScreen extends HookConsumerWidget {
|
|||||||
subtitle: const Text(
|
subtitle: const Text(
|
||||||
'When enabled, all Private Tabs will be tunneled through Tor',
|
'When enabled, all Private Tabs will be tunneled through Tor',
|
||||||
),
|
),
|
||||||
secondary: const Icon(MdiIcons.arrowDecision),
|
secondary: const Icon(MdiIcons.incognito),
|
||||||
onChanged: (value) async {
|
onChanged: (value) async {
|
||||||
await ref
|
await ref
|
||||||
.read(saveTorSettingsControllerProvider.notifier)
|
.read(saveTorSettingsControllerProvider.notifier)
|
||||||
@@ -179,27 +186,173 @@ class TorProxyScreen extends HookConsumerWidget {
|
|||||||
}
|
}
|
||||||
return null; // Use the default color.
|
return null; // Use the default color.
|
||||||
}),
|
}),
|
||||||
value: torSettings.autoConfig,
|
value: torSettings.config == TorConnectionConfig.auto,
|
||||||
title: const Text('Configure Transport Automatically'),
|
title: const Text('Auto Configure Transport'),
|
||||||
subtitle: const Text(
|
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),
|
secondary: const Icon(MdiIcons.arrowDecisionAuto),
|
||||||
onChanged: (value) async {
|
onChanged: torProxyPort.isLoading
|
||||||
await ref
|
? null
|
||||||
.read(saveTorSettingsControllerProvider.notifier)
|
: (value) async {
|
||||||
.save(
|
await ref
|
||||||
(currentSettings) =>
|
.read(
|
||||||
currentSettings.copyWith.autoConfig(value),
|
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(
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
if (torProxyPort.isLoading)
|
if (torProxyPort.isLoading)
|
||||||
const Column(
|
const Column(
|
||||||
|
|||||||
@@ -35,16 +35,19 @@ Future<void> onStart(ServiceInstance service) async {
|
|||||||
service.invoke('portUpdate', {'port': port});
|
service.invoke('portUpdate', {'port': port});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Future<void> stopProxies() async {
|
||||||
|
for (final proxyType in startedProxyType) {
|
||||||
|
await IPtProxyController().stop(proxyType);
|
||||||
|
}
|
||||||
|
startedProxyType.clear();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> stopService() async {
|
Future<void> stopService() async {
|
||||||
timeout?.cancel();
|
timeout?.cancel();
|
||||||
timeout = null;
|
timeout = null;
|
||||||
|
|
||||||
Tor.instance.stop();
|
Tor.instance.stop();
|
||||||
|
await stopProxies();
|
||||||
for (final proxyType in startedProxyType) {
|
|
||||||
await IPtProxyController().stop(proxyType);
|
|
||||||
}
|
|
||||||
startedProxyType.clear();
|
|
||||||
|
|
||||||
service.invoke('portUpdate', {'port': -1});
|
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(
|
final proxyType = ProxyType.values.firstWhereOrNull(
|
||||||
(x) => x.name == event?['proxyType'],
|
(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) {
|
service.on("heartbeat").listen((event) {
|
||||||
|
|||||||
@@ -42,7 +42,12 @@ class SettingDao extends DatabaseAccessor<UserDatabase> with _$SettingDaoMixin {
|
|||||||
partitionKey: Value(partitionKey),
|
partitionKey: Value(partitionKey),
|
||||||
value: Value(driftvalue),
|
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,
|
'showExtensionShortcut': instance.showExtensionShortcut,
|
||||||
'enableLocalAiFeatures': instance.enableLocalAiFeatures,
|
'enableLocalAiFeatures': instance.enableLocalAiFeatures,
|
||||||
'defaultCreateTabType': _$TabTypeEnumMap[instance.defaultCreateTabType]!,
|
'defaultCreateTabType': _$TabTypeEnumMap[instance.defaultCreateTabType]!,
|
||||||
'defaultIntentTabType': _$TabTypeEnumMap[instance.defaultIntentTabType]!,
|
'tabIntentOpenSetting':
|
||||||
|
_$TabIntentOpenSettingEnumMap[instance.tabIntentOpenSetting]!,
|
||||||
'autoHideTabBar': instance.autoHideTabBar,
|
'autoHideTabBar': instance.autoHideTabBar,
|
||||||
'tabBarSwipeAction': _$TabBarSwipeActionEnumMap[instance.tabBarSwipeAction]!,
|
'tabBarSwipeAction': _$TabBarSwipeActionEnumMap[instance.tabBarSwipeAction]!,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,17 +4,32 @@ import 'package:json_annotation/json_annotation.dart';
|
|||||||
|
|
||||||
part 'tor_settings.g.dart';
|
part 'tor_settings.g.dart';
|
||||||
|
|
||||||
|
enum TorConnectionConfig { auto, direct, obfs4, snowflake }
|
||||||
|
|
||||||
@CopyWith()
|
@CopyWith()
|
||||||
@JsonSerializable(includeIfNull: true, constructor: 'withDefaults')
|
@JsonSerializable(includeIfNull: true, constructor: 'withDefaults')
|
||||||
class TorSettings with FastEquatable {
|
class TorSettings with FastEquatable {
|
||||||
final bool proxyPrivateTabsTor;
|
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})
|
TorSettings.withDefaults({
|
||||||
: proxyPrivateTabsTor = proxyPrivateTabsTor ?? false,
|
bool? proxyPrivateTabsTor,
|
||||||
autoConfig = autoConfig ?? true;
|
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) =>
|
factory TorSettings.fromJson(Map<String, dynamic> json) =>
|
||||||
_$TorSettingsFromJson(json);
|
_$TorSettingsFromJson(json);
|
||||||
@@ -22,5 +37,10 @@ class TorSettings with FastEquatable {
|
|||||||
Map<String, dynamic> toJson() => _$TorSettingsToJson(this);
|
Map<String, dynamic> toJson() => _$TorSettingsToJson(this);
|
||||||
|
|
||||||
@override
|
@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 {
|
abstract class _$TorSettingsCWProxy {
|
||||||
TorSettings proxyPrivateTabsTor(bool proxyPrivateTabsTor);
|
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.
|
/// 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
|
/// ```dart
|
||||||
/// TorSettings(...).copyWith(id: 12, name: "My name")
|
/// 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(...)`
|
/// 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);
|
this(proxyPrivateTabsTor: proxyPrivateTabsTor);
|
||||||
|
|
||||||
@override
|
@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
|
@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.
|
/// 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({
|
TorSettings call({
|
||||||
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
Object? proxyPrivateTabsTor = const $CopyWithPlaceholder(),
|
||||||
Object? autoConfig = const $CopyWithPlaceholder(),
|
Object? config = const $CopyWithPlaceholder(),
|
||||||
|
Object? requireBridge = const $CopyWithPlaceholder(),
|
||||||
|
Object? fetchRemoteBridges = const $CopyWithPlaceholder(),
|
||||||
}) {
|
}) {
|
||||||
return TorSettings(
|
return TorSettings(
|
||||||
proxyPrivateTabsTor: proxyPrivateTabsTor == const $CopyWithPlaceholder()
|
proxyPrivateTabsTor: proxyPrivateTabsTor == const $CopyWithPlaceholder()
|
||||||
? _value.proxyPrivateTabsTor
|
? _value.proxyPrivateTabsTor
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// ignore: cast_nullable_to_non_nullable
|
||||||
: proxyPrivateTabsTor as bool,
|
: proxyPrivateTabsTor as bool,
|
||||||
autoConfig: autoConfig == const $CopyWithPlaceholder()
|
config: config == const $CopyWithPlaceholder()
|
||||||
? _value.autoConfig
|
? _value.config
|
||||||
// ignore: cast_nullable_to_non_nullable
|
// 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 _$TorSettingsFromJson(Map<String, dynamic> json) =>
|
||||||
TorSettings.withDefaults(
|
TorSettings.withDefaults(
|
||||||
proxyPrivateTabsTor: json['proxyPrivateTabsTor'] as bool?,
|
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) =>
|
Map<String, dynamic> _$TorSettingsToJson(TorSettings instance) =>
|
||||||
<String, dynamic>{
|
<String, dynamic>{
|
||||||
'proxyPrivateTabsTor': instance.proxyPrivateTabsTor,
|
'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 =
|
typedef GeneralSettingsWithDefaultsRef =
|
||||||
AutoDisposeProviderRef<GeneralSettings>;
|
AutoDisposeProviderRef<GeneralSettings>;
|
||||||
String _$generalSettingsRepositoryHash() =>
|
String _$generalSettingsRepositoryHash() =>
|
||||||
r'07eeaf811fac4b9c787cce7c29379a7329910ae5';
|
r'0d207ae4ae9fd94b1257eb8aa4cfd73d4a47caf2';
|
||||||
|
|
||||||
/// See also [GeneralSettingsRepository].
|
/// See also [GeneralSettingsRepository].
|
||||||
@ProviderFor(GeneralSettingsRepository)
|
@ProviderFor(GeneralSettingsRepository)
|
||||||
|
|||||||
@@ -23,7 +23,12 @@ class TorSettingsRepository extends _$TorSettingsRepository {
|
|||||||
DriftSqlType.bool,
|
DriftSqlType.bool,
|
||||||
db.typeMapping,
|
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,
|
DriftSqlType.bool,
|
||||||
db.typeMapping,
|
db.typeMapping,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ final torSettingsWithDefaultsProvider =
|
|||||||
// ignore: unused_element
|
// ignore: unused_element
|
||||||
typedef TorSettingsWithDefaultsRef = AutoDisposeProviderRef<TorSettings>;
|
typedef TorSettingsWithDefaultsRef = AutoDisposeProviderRef<TorSettings>;
|
||||||
String _$torSettingsRepositoryHash() =>
|
String _$torSettingsRepositoryHash() =>
|
||||||
r'686e8576453f33a0d2d0eb2869e29ca88e00bc37';
|
r'ef80d1cc6b9b72cce371c03c656b10a0924d49d0';
|
||||||
|
|
||||||
/// See also [TorSettingsRepository].
|
/// See also [TorSettingsRepository].
|
||||||
@ProviderFor(TorSettingsRepository)
|
@ProviderFor(TorSettingsRepository)
|
||||||
|
|||||||
@@ -0,0 +1,4 @@
|
|||||||
|
description: This file stores settings for Dart & Flutter DevTools.
|
||||||
|
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
|
||||||
|
extensions:
|
||||||
|
- drift: true
|
||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8"/>
|
<meta charset="UTF-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
<title>readability [24 Aug 2025 at 12:45]</title>
|
<title>readability [12 Sep 2025 at 07:08]</title>
|
||||||
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABrVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+O1foceMD///+J0/qK1Pr7/v8Xdr/9///W8P4UdL7L7P0Scr2r4Pyj3vwad8D5/f/2/f+55f3E6f34+/2H0/ojfMKpzOd0rNgQcb3F3O/j9f7c8v6g3Pz0/P/w+v/q+P7n9v6T1/uQ1vuE0vqLut/y+v+Z2fvt+f+15Pzv9fuc2/vR7v2V2Pvd6/bg9P7I6/285/2y4/yp3/zp8vk8i8kqgMT7/P31+fyv4vxGkcz6/P6/6P3j7vfS5PNnpNUxhcbO7f7F6v3O4vHK3/DA2u631Ouy0eqXweKJud5wqthfoNMMbLvY8f73+v2dxeR8sNtTmdDx9/zX6PSjyeaCtd1YnNGX2PuQveCGt95Nls42h8dLlM3F4vBtAAAAM3RSTlMAAyOx0/sKBvik8opWGBMOAe3l1snDm2E9LSb06eHcu5JpHbarfHZCN9CBb08zzkdNS0kYaptYAAAFV0lEQVRYw92X51/aYBDHHS2O2qqttVbrqNq9m+TJIAYIShBkWwqIiCgoWvfeq7Z2/s29hyQNyUcR7LveGwVyXy6XH8/9rqxglLfUPLxVduUor3h0rfp2TYvpivk37929TkG037hffoX0+peVtZQc1589rigVUdXS/ABSAyEmGIO/1XfvldSK8vs3OqB6u3m0nxmIrvgB0dj7rr7Y9IbuF68hnfFaiHA/sxqm0wciIG43P60qKv9WXWc1RXGh/mFESFABTSBi0sNAKzqet17eCtOb3kZIDwxEEU0oAIJGYxNBDhBND29e0rtXXbcpuPmED9IhEAAQ/AXEaF8EPmnrrKsv0LvWR3fg5sWDNAFZOgAgaKvZDogHNU9MFwnnYROkc56RD5CjAbQX9Ow4g7upCsvYu55aSI/Nj0H1akgKQEUM94dwK65hYRmFU9MIcH/fqJYOZYcnuJSU/waKDgTOEVaVKhwrTRP5XzgSpAITYzom7UvkhFX5VutmxeNnWDjjswTKTyfgluNDGbUpWissXhF3s7mlSml+czWkg3D0l1nNjGNjz3myOQOa1KM/jOS6ebdbAVTCi4gljHSFrviza7tOgRWcS0MOUX9zdNgag5w7rRqA44Lzw0hr1WqES36dFliSJFlh2rXIae3FFcDDgKdxrUIDePr8jGcSClV1u7A9xeN0ModY/pHMxmR1EzRh8TJiwqsHmKW0l4FCEZI+jHio+JdPPE9qwQtTRxku2D8sIeRL2LnxWSllANCQGOIiqVHAz2ye2JR0DcH+HoxDkaADLjgxjKQ+AwCX/g0+DNgdG0ukYCONAe+dbc2IAc6fwt1ARoDSezNHxV2Cmzwv3O6lDMV55edBGwGK9n1+x2F8EDfAGCxug8MhpsMEcTEAWf3rx2vZhe/LAmtIn/6apE6PN0ULKgywD9mmdxbmFl3OvD5AS5fW5zLbv/YHmcsBTjf/afDz3MaZTVCfAP9z6/Bw6ycv8EUBWJIn9zYcoAWWlW9+OzO3vkTy8H+RANLmdrpOuYWdZYEXpo+TlCJrW5EARb7fF+bWdqf3hhyZI1nWJQHgznErZhbjoEsWqi8dQNoE294aldzFurwSABL2XXMf9+H1VQGke9exw5P/AnA5Pv5ngMul7LOvO922iwACu8WkCwLCafvM4CeWPxfA8lNHcWZSoi8EwMAIciKX2Z4SWCMAa3snCZ/G4EA8D6CMLNFsGQhkkz/gQNEBbPCbWsxGUpYVu3z8IyNAknwJkfPMEhLyrdi5RTyUVACkw4GSFRNWJNEW+fgPGwHD8/JxnRuLabN4CGNRkAE23na2+VmEAUmrYymSGjMAYqH84YUIyzgzs3XC7gNgH36Vcc4zKY9o9fgPBXUAiHHwVboBHGLiX6Zcjp1f2wu4tvzZKo0ecPnDtQYDQvJXaBeNzce45Fp28ZQLrEZVuFqgBwOalArKXnW1UzlnSusQKJqKYNuz4tOnI6sZG4zanpemv+7ySU2jbA9h6uhcgpfy6G2PahirDZ6zvq6zDduMVFTKvzw8wgyEdelwY9in3XkEPs3osJuwRQ4qTkfzifndg9Gfc4pdsu82+tTnHZTBa2EAMrqr2t43pguc8tNm7JQVQ2S0ukj2d22dhXYP0/veWtwKrCkNoNimAN5+Xr/oLrxswKbVJjteWrX7eR63o4j9q0GxnaBdWgGA5VStpanIjQmEhV0/nVt5VOFUvix6awJhPcAaTEShgrG+iGyvb5a0Ndb1YGHFPEwoqAinoaykaID1o1pdPNu7XsnCKQ3R+hwWIIhGvORcJUBYXe3Xa3vq/mF/N9V13ugufMkfXn+KHsRD0B8AAAAASUVORK5CYII=" type="image/x-icon" />
|
<link rel="shortcut icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAABrVBMVEUAAAD///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+O1foceMD///+J0/qK1Pr7/v8Xdr/9///W8P4UdL7L7P0Scr2r4Pyj3vwad8D5/f/2/f+55f3E6f34+/2H0/ojfMKpzOd0rNgQcb3F3O/j9f7c8v6g3Pz0/P/w+v/q+P7n9v6T1/uQ1vuE0vqLut/y+v+Z2fvt+f+15Pzv9fuc2/vR7v2V2Pvd6/bg9P7I6/285/2y4/yp3/zp8vk8i8kqgMT7/P31+fyv4vxGkcz6/P6/6P3j7vfS5PNnpNUxhcbO7f7F6v3O4vHK3/DA2u631Ouy0eqXweKJud5wqthfoNMMbLvY8f73+v2dxeR8sNtTmdDx9/zX6PSjyeaCtd1YnNGX2PuQveCGt95Nls42h8dLlM3F4vBtAAAAM3RSTlMAAyOx0/sKBvik8opWGBMOAe3l1snDm2E9LSb06eHcu5JpHbarfHZCN9CBb08zzkdNS0kYaptYAAAFV0lEQVRYw92X51/aYBDHHS2O2qqttVbrqNq9m+TJIAYIShBkWwqIiCgoWvfeq7Z2/s29hyQNyUcR7LveGwVyXy6XH8/9rqxglLfUPLxVduUor3h0rfp2TYvpivk37929TkG037hffoX0+peVtZQc1589rigVUdXS/ABSAyEmGIO/1XfvldSK8vs3OqB6u3m0nxmIrvgB0dj7rr7Y9IbuF68hnfFaiHA/sxqm0wciIG43P60qKv9WXWc1RXGh/mFESFABTSBi0sNAKzqet17eCtOb3kZIDwxEEU0oAIJGYxNBDhBND29e0rtXXbcpuPmED9IhEAAQ/AXEaF8EPmnrrKsv0LvWR3fg5sWDNAFZOgAgaKvZDogHNU9MFwnnYROkc56RD5CjAbQX9Ow4g7upCsvYu55aSI/Nj0H1akgKQEUM94dwK65hYRmFU9MIcH/fqJYOZYcnuJSU/waKDgTOEVaVKhwrTRP5XzgSpAITYzom7UvkhFX5VutmxeNnWDjjswTKTyfgluNDGbUpWissXhF3s7mlSml+czWkg3D0l1nNjGNjz3myOQOa1KM/jOS6ebdbAVTCi4gljHSFrviza7tOgRWcS0MOUX9zdNgag5w7rRqA44Lzw0hr1WqES36dFliSJFlh2rXIae3FFcDDgKdxrUIDePr8jGcSClV1u7A9xeN0ModY/pHMxmR1EzRh8TJiwqsHmKW0l4FCEZI+jHio+JdPPE9qwQtTRxku2D8sIeRL2LnxWSllANCQGOIiqVHAz2ye2JR0DcH+HoxDkaADLjgxjKQ+AwCX/g0+DNgdG0ukYCONAe+dbc2IAc6fwt1ARoDSezNHxV2Cmzwv3O6lDMV55edBGwGK9n1+x2F8EDfAGCxug8MhpsMEcTEAWf3rx2vZhe/LAmtIn/6apE6PN0ULKgywD9mmdxbmFl3OvD5AS5fW5zLbv/YHmcsBTjf/afDz3MaZTVCfAP9z6/Bw6ycv8EUBWJIn9zYcoAWWlW9+OzO3vkTy8H+RANLmdrpOuYWdZYEXpo+TlCJrW5EARb7fF+bWdqf3hhyZI1nWJQHgznErZhbjoEsWqi8dQNoE294aldzFurwSABL2XXMf9+H1VQGke9exw5P/AnA5Pv5ngMul7LOvO922iwACu8WkCwLCafvM4CeWPxfA8lNHcWZSoi8EwMAIciKX2Z4SWCMAa3snCZ/G4EA8D6CMLNFsGQhkkz/gQNEBbPCbWsxGUpYVu3z8IyNAknwJkfPMEhLyrdi5RTyUVACkw4GSFRNWJNEW+fgPGwHD8/JxnRuLabN4CGNRkAE23na2+VmEAUmrYymSGjMAYqH84YUIyzgzs3XC7gNgH36Vcc4zKY9o9fgPBXUAiHHwVboBHGLiX6Zcjp1f2wu4tvzZKo0ecPnDtQYDQvJXaBeNzce45Fp28ZQLrEZVuFqgBwOalArKXnW1UzlnSusQKJqKYNuz4tOnI6sZG4zanpemv+7ySU2jbA9h6uhcgpfy6G2PahirDZ6zvq6zDduMVFTKvzw8wgyEdelwY9in3XkEPs3osJuwRQ4qTkfzifndg9Gfc4pdsu82+tTnHZTBa2EAMrqr2t43pguc8tNm7JQVQ2S0ukj2d22dhXYP0/veWtwKrCkNoNimAN5+Xr/oLrxswKbVJjteWrX7eR63o4j9q0GxnaBdWgGA5VStpanIjQmEhV0/nVt5VOFUvix6awJhPcAaTEShgrG+iGyvb5a0Ndb1YGHFPEwoqAinoaykaID1o1pdPNu7XsnCKQ3R+hwWIIhGvORcJUBYXe3Xa3vq/mF/N9V13ugufMkfXn+KHsRD0B8AAAAASUVORK5CYII=" type="image/x-icon" />
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"hash": "1d5bede379cdf6035685",
|
"hash": "1d5bede379cdf6035685",
|
||||||
"version": "5.97.1",
|
"version": "5.97.1",
|
||||||
"time": 548,
|
"time": 557,
|
||||||
"builtAt": 1756032309689,
|
"builtAt": 1757653694040,
|
||||||
"publicPath": "auto",
|
"publicPath": "auto",
|
||||||
"outputPath": "/home/fafre/development/repos/lensai/packages/flutter_mozilla_components/javascript/readability/dist",
|
"outputPath": "/home/fafre/development/repos/lensai/packages/flutter_mozilla_components/javascript/readability/dist",
|
||||||
"assetsByChunkName": {
|
"assetsByChunkName": {
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
|
export 'src/data/models/moat.dart';
|
||||||
export 'src/data/service/moat_service.dart';
|
export 'src/data/service/moat_service.dart';
|
||||||
export 'src/pigeons/proxy.g.dart' show IPtProxyController, ProxyType;
|
export 'src/pigeons/proxy.g.dart' show IPtProxyController, ProxyType;
|
||||||
|
|||||||
@@ -83,13 +83,19 @@ class Setting {
|
|||||||
|
|
||||||
@JsonSerializable()
|
@JsonSerializable()
|
||||||
class Bridge {
|
class Bridge {
|
||||||
final String type;
|
@JsonKey(toJson: _transportToJson, fromJson: _transportFromJson)
|
||||||
|
final TransportType type;
|
||||||
final String source;
|
final String source;
|
||||||
@JsonKey(name: 'bridge_strings')
|
@JsonKey(name: 'bridge_strings')
|
||||||
final List<String>? bridges;
|
final List<String>? bridges;
|
||||||
|
|
||||||
const Bridge({required this.type, required this.source, this.bridges});
|
const Bridge({required this.type, required this.source, this.bridges});
|
||||||
|
|
||||||
|
static String _transportToJson(TransportType transport) => transport.value;
|
||||||
|
|
||||||
|
static TransportType _transportFromJson(dynamic json) =>
|
||||||
|
TransportType.fromString(json as String)!;
|
||||||
|
|
||||||
factory Bridge.fromJson(Map<String, dynamic> json) => _$BridgeFromJson(json);
|
factory Bridge.fromJson(Map<String, dynamic> json) => _$BridgeFromJson(json);
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => _$BridgeToJson(this);
|
Map<String, dynamic> toJson() => _$BridgeToJson(this);
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ Map<String, dynamic> _$SettingToJson(Setting instance) => <String, dynamic>{
|
|||||||
};
|
};
|
||||||
|
|
||||||
Bridge _$BridgeFromJson(Map<String, dynamic> json) => Bridge(
|
Bridge _$BridgeFromJson(Map<String, dynamic> json) => Bridge(
|
||||||
type: json['type'] as String,
|
type: Bridge._transportFromJson(json['type']),
|
||||||
source: json['source'] as String,
|
source: json['source'] as String,
|
||||||
bridges: (json['bridge_strings'] as List<dynamic>?)
|
bridges: (json['bridge_strings'] as List<dynamic>?)
|
||||||
?.map((e) => e as String)
|
?.map((e) => e as String)
|
||||||
@@ -58,7 +58,7 @@ Bridge _$BridgeFromJson(Map<String, dynamic> json) => Bridge(
|
|||||||
);
|
);
|
||||||
|
|
||||||
Map<String, dynamic> _$BridgeToJson(Bridge instance) => <String, dynamic>{
|
Map<String, dynamic> _$BridgeToJson(Bridge instance) => <String, dynamic>{
|
||||||
'type': instance.type,
|
'type': Bridge._transportToJson(instance.type),
|
||||||
'source': instance.source,
|
'source': instance.source,
|
||||||
'bridge_strings': instance.bridges,
|
'bridge_strings': instance.bridges,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ import 'package:socks5_proxy/socks_client.dart';
|
|||||||
const String _meekParameters =
|
const String _meekParameters =
|
||||||
'url=https://1723079976.rsc.cdn77.org;front=www.phpmyadmin.net';
|
'url=https://1723079976.rsc.cdn77.org;front=www.phpmyadmin.net';
|
||||||
|
|
||||||
|
const defaultBridges = [TransportType.obfs4, TransportType.snowflake];
|
||||||
|
|
||||||
/// Manages MOAT API connections with persistent proxy setup.
|
/// Manages MOAT API connections with persistent proxy setup.
|
||||||
class MoatService {
|
class MoatService {
|
||||||
MoatApi? _api;
|
MoatApi? _api;
|
||||||
@@ -66,10 +68,10 @@ class MoatService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Converts BuiltInBridges to Settings for requested transports.
|
/// Converts BuiltInBridges to Settings for requested transports.
|
||||||
List<Setting> _convertBuiltinToSettings(
|
static List<Setting> convertBuiltinToSettings(
|
||||||
BuiltInBridges builtinBridges,
|
BuiltInBridges builtinBridges, {
|
||||||
List<TransportType> transports,
|
List<TransportType> transports = defaultBridges,
|
||||||
) {
|
}) {
|
||||||
final settings = <Setting>[];
|
final settings = <Setting>[];
|
||||||
|
|
||||||
for (final transport in transports) {
|
for (final transport in transports) {
|
||||||
@@ -85,7 +87,7 @@ class MoatService {
|
|||||||
settings.add(
|
settings.add(
|
||||||
Setting(
|
Setting(
|
||||||
bridge: Bridge(
|
bridge: Bridge(
|
||||||
type: transport.value,
|
type: transport,
|
||||||
source: 'builtin',
|
source: 'builtin',
|
||||||
bridges: bridgeStrings,
|
bridges: bridgeStrings,
|
||||||
),
|
),
|
||||||
@@ -98,29 +100,20 @@ class MoatService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Gets built-in bridges from the MOAT service endpoint.
|
/// Gets built-in bridges from the MOAT service endpoint.
|
||||||
Future<List<Setting>?> getBuiltinBridges({
|
Future<BuiltInBridges> getBuiltinBridges({
|
||||||
List<TransportType> transports = const [
|
List<TransportType> transports = defaultBridges,
|
||||||
TransportType.obfs4,
|
|
||||||
TransportType.snowflake,
|
|
||||||
TransportType.meek,
|
|
||||||
],
|
|
||||||
}) async {
|
}) async {
|
||||||
_ensureInitialized();
|
_ensureInitialized();
|
||||||
|
|
||||||
final builtinBridges = await _api!.builtin();
|
final builtinBridges = await _api!.builtin();
|
||||||
final settings = _convertBuiltinToSettings(builtinBridges, transports);
|
return builtinBridges;
|
||||||
return settings.isEmpty ? null : settings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to automatically configure Pluggable Transports.
|
/// Tries to automatically configure Pluggable Transports.
|
||||||
Future<List<Setting>?> autoConf({
|
Future<List<Setting>?> autoConf({
|
||||||
String? country,
|
String? country,
|
||||||
bool cannotConnectWithoutPt = false,
|
bool cannotConnectWithoutPt = false,
|
||||||
List<TransportType> transports = const [
|
List<TransportType> transports = defaultBridges,
|
||||||
TransportType.obfs4,
|
|
||||||
TransportType.snowflake,
|
|
||||||
TransportType.webtunnel,
|
|
||||||
],
|
|
||||||
}) async {
|
}) async {
|
||||||
_ensureInitialized();
|
_ensureInitialized();
|
||||||
|
|
||||||
@@ -146,6 +139,18 @@ class MoatService {
|
|||||||
return response.settings;
|
return response.settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<Setting>?> getDefaultBridges({
|
||||||
|
List<TransportType> transports = defaultBridges,
|
||||||
|
}) async {
|
||||||
|
_ensureInitialized();
|
||||||
|
|
||||||
|
final response = await _api!.defaults(
|
||||||
|
SettingsRequest(transports: transports),
|
||||||
|
);
|
||||||
|
|
||||||
|
return response.settings;
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets the list of supported countries from the MOAT service.
|
/// Gets the list of supported countries from the MOAT service.
|
||||||
Future<List<String>> getCountries() async {
|
Future<List<String>> getCountries() async {
|
||||||
_ensureInitialized();
|
_ensureInitialized();
|
||||||
|
|||||||
@@ -13,10 +13,7 @@ dependencies:
|
|||||||
sdk: flutter
|
sdk: flutter
|
||||||
http: ^1.5.0
|
http: ^1.5.0
|
||||||
json_annotation: ^4.9.0
|
json_annotation: ^4.9.0
|
||||||
socks5_proxy:
|
socks5_proxy: ^2.1.1
|
||||||
git:
|
|
||||||
url: https://github.com/sylvieon/socks_dart.git
|
|
||||||
ref: 04550bc08f42cc1a35f1e870f651b93a4f9aceab
|
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
build_runner: ^2.4.15
|
build_runner: ^2.4.15
|
||||||
|
|||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
BASE=$(dirname "$0")
|
||||||
|
|
||||||
|
cd "$BASE/../packages/flutter_mozilla_components/javascript/container_proxy" || exit
|
||||||
|
|
||||||
|
npm ci
|
||||||
|
npx webpack
|
||||||
Executable
+8
@@ -0,0 +1,8 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
BASE=$(dirname "$0")
|
||||||
|
|
||||||
|
cd "$BASE/../packages/flutter_mozilla_components/javascript/readability" || exit
|
||||||
|
|
||||||
|
npm ci
|
||||||
|
npx webpack
|
||||||
Executable
+9
@@ -0,0 +1,9 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
|
BASE=$(dirname "$0")
|
||||||
|
|
||||||
|
cd "$BASE/../app/assets/preferences" || exit
|
||||||
|
|
||||||
|
rm -f builtin-bridges.json
|
||||||
|
|
||||||
|
wget -O builtin-bridges.json https://bridges.torproject.org/moat/circumvention/builtin
|
||||||
Reference in New Issue
Block a user