2023-09-07 18:07:05 +00:00
|
|
|
import 'dart:io';
|
|
|
|
|
2023-08-07 16:39:04 +00:00
|
|
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
2023-09-07 22:13:27 +00:00
|
|
|
import 'package:stackwallet/services/event_bus/events/global/tor_connection_status_changed_event.dart';
|
2023-09-07 21:27:00 +00:00
|
|
|
import 'package:stackwallet/services/event_bus/global_event_bus.dart';
|
2023-09-07 18:07:05 +00:00
|
|
|
import 'package:stackwallet/utilities/logger.dart';
|
2023-09-12 18:49:25 +00:00
|
|
|
import 'package:tor_ffi_plugin/tor_ffi_plugin.dart';
|
2023-08-07 16:39:04 +00:00
|
|
|
|
2023-08-07 16:46:34 +00:00
|
|
|
final pTorService = Provider((_) => TorService.sharedInstance);
|
2023-08-07 16:39:04 +00:00
|
|
|
|
|
|
|
class TorService {
|
2023-09-08 21:41:37 +00:00
|
|
|
Tor? _tor;
|
2023-09-07 22:56:48 +00:00
|
|
|
|
|
|
|
/// Flag to indicate that a Tor circuit is thought to have been established.
|
2023-09-07 18:07:05 +00:00
|
|
|
bool _enabled = false;
|
|
|
|
|
2023-09-07 22:56:48 +00:00
|
|
|
/// Getter for the enabled flag.
|
|
|
|
bool get enabled => _enabled;
|
|
|
|
|
2023-09-07 18:07:05 +00:00
|
|
|
TorService._();
|
|
|
|
|
2023-09-07 22:56:48 +00:00
|
|
|
/// Singleton instance of the TorService.
|
|
|
|
///
|
|
|
|
/// Use this to access the TorService and its properties.
|
2023-09-07 18:07:05 +00:00
|
|
|
static final sharedInstance = TorService._();
|
2023-08-07 16:39:04 +00:00
|
|
|
|
2023-09-07 22:56:48 +00:00
|
|
|
/// Getter for the proxyInfo.
|
2023-09-07 18:07:05 +00:00
|
|
|
({
|
|
|
|
InternetAddress host,
|
|
|
|
int port,
|
|
|
|
}) get proxyInfo => (
|
|
|
|
host: InternetAddress.loopbackIPv4,
|
2023-09-08 21:41:37 +00:00
|
|
|
port: _tor!.port,
|
2023-09-07 18:07:05 +00:00
|
|
|
);
|
|
|
|
|
2023-09-08 21:41:37 +00:00
|
|
|
/// Initialize the tor ffi lib instance if it hasn't already been set. Nothing
|
|
|
|
/// changes if _tor is already been set.
|
|
|
|
void init({Tor? mockableOverride}) {
|
2023-09-12 18:49:25 +00:00
|
|
|
_tor ??= mockableOverride ?? Tor.instance;
|
2023-09-08 21:41:37 +00:00
|
|
|
}
|
|
|
|
|
2023-09-07 22:56:48 +00:00
|
|
|
/// Start the Tor service.
|
|
|
|
///
|
|
|
|
/// This will start the Tor service and establish a Tor circuit.
|
|
|
|
///
|
|
|
|
/// Throws an exception if the Tor service fails to start.
|
|
|
|
///
|
|
|
|
/// Returns a Future that completes when the Tor service has started.
|
2023-08-07 16:39:04 +00:00
|
|
|
Future<void> start() async {
|
2023-09-08 21:41:37 +00:00
|
|
|
if (_tor == null) {
|
|
|
|
throw Exception("TorService.init has not been called!");
|
|
|
|
}
|
|
|
|
|
2023-09-07 18:07:05 +00:00
|
|
|
if (_enabled) {
|
|
|
|
// already started so just return
|
|
|
|
// could throw an exception here or something so the caller
|
|
|
|
// is explicitly made aware of this
|
2023-09-07 20:37:23 +00:00
|
|
|
// TODO restart tor after that's been added to the tor-ffi crate
|
2023-09-08 13:53:06 +00:00
|
|
|
// (probably better to have a restart function separately)
|
2023-09-12 20:28:16 +00:00
|
|
|
|
|
|
|
// Fire a TorConnectionStatusChangedEvent on the event bus.
|
|
|
|
GlobalEventBus.instance.fire(
|
|
|
|
TorConnectionStatusChangedEvent(
|
|
|
|
TorConnectionStatus.connected,
|
|
|
|
"Tor connection status changed: connect ($_enabled)",
|
|
|
|
),
|
|
|
|
);
|
2023-09-07 18:07:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-07 22:56:48 +00:00
|
|
|
// Start the Tor service.
|
2023-09-07 18:07:05 +00:00
|
|
|
try {
|
2023-09-07 21:27:00 +00:00
|
|
|
GlobalEventBus.instance.fire(
|
|
|
|
TorConnectionStatusChangedEvent(
|
|
|
|
TorConnectionStatus.connecting,
|
|
|
|
"Tor connection status changed: connecting",
|
|
|
|
),
|
|
|
|
);
|
2023-09-08 21:41:37 +00:00
|
|
|
await _tor!.start();
|
2023-09-07 18:07:05 +00:00
|
|
|
// no exception or error so we can (probably?) assume tor
|
|
|
|
// has started successfully
|
|
|
|
_enabled = true;
|
2023-09-07 23:28:55 +00:00
|
|
|
|
|
|
|
// Fire a TorConnectionStatusChangedEvent on the event bus.
|
2023-09-07 21:27:00 +00:00
|
|
|
GlobalEventBus.instance.fire(
|
|
|
|
TorConnectionStatusChangedEvent(
|
|
|
|
TorConnectionStatus.connected,
|
|
|
|
"Tor connection status changed: connect ($_enabled)",
|
|
|
|
),
|
|
|
|
);
|
2023-09-07 18:07:05 +00:00
|
|
|
} catch (e, s) {
|
|
|
|
Logging.instance.log(
|
|
|
|
"TorService.start failed: $e\n$s",
|
|
|
|
level: LogLevel.Warning,
|
|
|
|
);
|
2023-09-07 21:27:00 +00:00
|
|
|
// _enabled should already be false
|
2023-09-07 23:28:55 +00:00
|
|
|
|
|
|
|
// Fire a TorConnectionStatusChangedEvent on the event bus.
|
2023-09-07 21:27:00 +00:00
|
|
|
GlobalEventBus.instance.fire(
|
|
|
|
TorConnectionStatusChangedEvent(
|
|
|
|
TorConnectionStatus.disconnected,
|
|
|
|
"Tor connection status changed: $_enabled (failed)",
|
|
|
|
),
|
|
|
|
);
|
2023-09-07 18:07:05 +00:00
|
|
|
rethrow;
|
|
|
|
}
|
2023-08-07 16:39:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Future<void> stop() async {
|
2023-09-08 21:41:37 +00:00
|
|
|
if (_tor == null) {
|
|
|
|
throw Exception("TorService.init has not been called!");
|
|
|
|
}
|
|
|
|
|
2023-09-07 18:07:05 +00:00
|
|
|
if (!_enabled) {
|
|
|
|
// already stopped so just return
|
|
|
|
// could throw an exception here or something so the caller
|
|
|
|
// is explicitly made aware of this
|
2023-09-07 20:37:23 +00:00
|
|
|
// TODO make sure to kill
|
2023-09-07 18:07:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-09-07 22:56:48 +00:00
|
|
|
// Stop the Tor service.
|
2023-09-07 18:07:05 +00:00
|
|
|
try {
|
2023-09-08 21:41:37 +00:00
|
|
|
await _tor!.disable();
|
2023-09-07 18:07:05 +00:00
|
|
|
// no exception or error so we can (probably?) assume tor
|
|
|
|
// has started successfully
|
|
|
|
_enabled = false;
|
2023-09-07 21:27:00 +00:00
|
|
|
GlobalEventBus.instance.fire(
|
|
|
|
TorConnectionStatusChangedEvent(
|
|
|
|
TorConnectionStatus.disconnected,
|
|
|
|
"Tor connection status changed: $_enabled (disabled)",
|
|
|
|
),
|
|
|
|
);
|
2023-09-07 18:07:05 +00:00
|
|
|
} catch (e, s) {
|
|
|
|
Logging.instance.log(
|
|
|
|
"TorService.stop failed: $e\n$s",
|
|
|
|
level: LogLevel.Warning,
|
|
|
|
);
|
|
|
|
rethrow;
|
|
|
|
}
|
2023-08-07 16:39:04 +00:00
|
|
|
}
|
|
|
|
}
|