Skip to content
This repository has been archived by the owner on Sep 22, 2022. It is now read-only.

Tor integration #120

Draft
wants to merge 29 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
70a8b6a
Tor compilation for iOS
SalomonBrys Jan 19, 2021
9e83a77
We do not use universal binaries
SalomonBrys Jan 19, 2021
e5ad6f0
Android compilation
SalomonBrys Jan 19, 2021
0a288b1
Compilation piloted by Gradle.
SalomonBrys Jan 20, 2021
366fa8a
Merge branch 'master' into feature/tor
SalomonBrys Jan 20, 2021
7866848
Ability to start and stop Tor.
SalomonBrys Jan 22, 2021
83c93a3
Tor strong authentication.
SalomonBrys Jan 25, 2021
fb0ae26
Tor code suspends.
SalomonBrys Jan 25, 2021
7f7fdd0
Socks5 without auth
SalomonBrys Jan 26, 2021
2fe2906
Socks5 API
SalomonBrys Jan 26, 2021
e6dcb64
Socks5 Proxy implements TcpSocket.Builder
SalomonBrys Jan 27, 2021
7bbeab1
Removed GLibToolize in XZ build script.
SalomonBrys Jan 27, 2021
cb25a00
liblzma.a instead of .la
SalomonBrys Jan 27, 2021
fd618a6
Tor is extracted to the new Tor-Mobile-KMP project.
SalomonBrys Jan 29, 2021
a73a5f5
Merge remote-tracking branch 'origin/master' into feature/tor
Jan 29, 2021
0f42422
can now call + with nullable Connection state
Feb 1, 2021
936b020
refactor Peer args
Feb 1, 2021
05f6b52
create manager for Tor configuration
Feb 1, 2021
3304242
display Tor badge when connected
Feb 1, 2021
a7cd08f
torManager is now TcpConnectionManager + function to update network a…
Feb 1, 2021
df76602
use Tor status to broadcast network availability
Feb 1, 2021
5116fcc
The peer needs an accurate tcp socket builder (through tor or not) be…
Feb 1, 2021
e19477c
navigationLink on HomeView when connected through Tor
Feb 2, 2021
0ab9ed4
display Tor info in TorConfigurationView
Feb 2, 2021
514ded5
Merge remote-tracking branch 'origin/master' into feature/tor
SalomonBrys Feb 2, 2021
c7b10d0
Update Socks5 proxy to support TLS after handshake.
SalomonBrys Feb 3, 2021
8eff15b
fix electrum conf to be able tu use SSL port
Feb 4, 2021
3eaf4f9
remove TcpConnectionManager
Feb 5, 2021
e7dd67b
finalize the Tor connection lifecycle
Feb 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ kotlin.code.style = official
kotlin.mpp.stability.nowarn=true
kotlin.incremental.multiplatform = true
kotlin.parallel.tasks.in.project = true
kotlin.mpp.enableGranularSourceSetsMetadata = true
#kotlin.mpp.enableGranularSourceSetsMetadata = true
kotlin.native.enableDependencyPropagation = false

# Android
Expand Down
1 change: 1 addition & 0 deletions phoenix-ios/phoenix-ios/controllers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class MockControllerFactory : ControllerFactory {
func scan() -> MVIController<Scan.Model, Scan.Intent> { MVIControllerMock(model: ScanView_Previews.mockModel) }
func restoreWallet() -> MVIController<RestoreWallet.Model, RestoreWallet.Intent> { MVIControllerMock(model: RestoreWalletView_Previews.mockModel) }
func configuration() -> MVIController<Configuration.Model, Configuration.Intent> { MVIControllerMock(model: ConfigurationView_Previews.mockModel) }
func torConfiguration() -> MVIController<TorConfiguration.Model, TorConfiguration.Intent> { MVIControllerMock(model: TorConfigurationView_Previews.mockModel) }
func electrumConfiguration() -> MVIController<ElectrumConfiguration.Model, ElectrumConfiguration.Intent> { MVIControllerMock(model: ElectrumConfigurationView_Previews.mockModel) }
func channelsConfiguration() -> MVIController<ChannelsConfiguration.Model, ChannelsConfiguration.Intent> { MVIControllerMock(model: ChannelsConfigurationView_Previews.mockModel) }
func logsConfiguration() -> MVIController<LogsConfiguration.Model, LogsConfiguration.Intent> { MVIControllerMock(model: LogsConfigurationView_Previews.mockModel) }
Expand Down
72 changes: 44 additions & 28 deletions phoenix-ios/phoenix-ios/views/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -180,41 +180,56 @@ struct ConnectionStatusButton : View {
@Environment(\.popoverState) var popoverState: PopoverState

var body: some View {
let tor = connectionsMonitor.connections.tor
let status = connectionsMonitor.connections.global

let connectedWithTor = status == Eclair_kmpConnection.established && tor != nil
let connectedWithoutTor = status == Eclair_kmpConnection.established && tor == nil

Group {
Button {
showConnectionsPopover()
} label: {
HStack {
Image("ic_connection_lost")
.resizable()
.frame(width: 16, height: 16)
Text(status.localizedText())
.font(.caption2)
if connectedWithTor {
NavigationLink(destination: TorConfigurationView()) {
HStack {
Image(systemName: "checkmark.shield")
.frame(width: 16, height: 16)
.foregroundColor(.appGreen)
Text("Tor enabled")
.font(.caption2)
}
}
}
.buttonStyle(PlainButtonStyle())
.padding([.leading, .top, .bottom], 4)
.padding([.trailing], 6)
.background(Color.buttonFill)
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray, lineWidth: 1)
)
.opacity(dimStatus ? 0.2 : 1.0)
.isHidden(status == Eclair_kmpConnection.established)
}
.onAppear {
DispatchQueue.main.async {
withAnimation(Animation.linear(duration: 1.0).repeatForever()) {
self.dimStatus.toggle()
} else {
Button {
showConnectionsPopover()
} label: {
HStack {
Image("ic_connection_lost")
.resizable()
.frame(width: 16, height: 16)
Text(status.localizedText())
.font(.caption2)
}
}
}
}
.buttonStyle(PlainButtonStyle())
.padding([.leading, .top, .bottom], 4)
.padding([.trailing], 6)
.background(Color.buttonFill)
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(Color.gray, lineWidth: 1)
)
.opacity((dimStatus && !connectedWithTor) ? 0.2 : 1.0)
.isHidden(connectedWithoutTor)
.onAppear {
DispatchQueue.main.async {
withAnimation(Animation.linear(duration: 1.0).repeatForever()) {
self.dimStatus.toggle()
}
}
}
}

func showConnectionsPopover() -> Void {
log.trace("(ConnectionStatusButton) showConnectionsPopover()")

Expand Down Expand Up @@ -325,6 +340,7 @@ class HomeView_Previews: PreviewProvider {

static let connections = Connections(
internet : .established,
tor : .established,
peer : .established,
electrum : .closed
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,7 @@ class ElectrumConfigurationView_Previews: PreviewProvider {
id: 0,
host: "tn.not.fyi",
port: 55002,
tls: .safe,
customized: true,
blockHeight: 123456789,
tipTimestamp: 1599564210
Expand All @@ -497,6 +498,7 @@ class ElectrumConfigurationView_Previews: PreviewProvider {
id: 0,
host: "",
port: 0,
tls: nil,
customized: false,
blockHeight: 123456789,
tipTimestamp: 1599564210
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
import SwiftUI
import PhoenixShared

struct TorConfigurationView: View {

@State var isTorEnabled = Prefs.shared.isTorEnabled
@State var theme = Prefs.shared.theme

var body: some View {
Form {
Section(header: TorFormHeader(), content: {}).textCase(nil)

Toggle(isOn: $isTorEnabled.animation()) {
if isTorEnabled {
Text("Tor is enabled")
} else {
Text("Tor is disabled")
MVIView({ $0.torConfiguration() }) { model, postIntent in
Form {
Section(header: TorFormHeader(), content: {}).textCase(nil)

Toggle(isOn: $isTorEnabled.animation()) {
if isTorEnabled {
Text("Tor is enabled")
} else {
Text("Tor is disabled")
}
}.onChange(of: isTorEnabled) { newValue in
self.toggleTor(newValue)
}

if let info = model.info {
VStack {
HStack {
Text("Tor version: \(info.version)")
Spacer()
}
HStack {
Text("Network: \(info.networkLiveness)")
Spacer()
}
}
.padding(.top, 10)
.font(.caption)
}
}.onChange(of: isTorEnabled) { newValue in
self.toggleTor(newValue)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.bottom)
.navigationBarTitle("Tor Settings", displayMode: .inline)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.edgesIgnoringSafeArea(.bottom)
.navigationBarTitle("Tor Settings", displayMode: .inline)
}

struct TorFormHeader: View {
Expand All @@ -47,4 +64,6 @@ class TorConfigurationView_Previews: PreviewProvider {
TorConfigurationView()
.previewDevice("iPhone 11")
}

static let mockModel = TorConfiguration.Model(info: Tor_mobile_kmpTor.TorInfo(version: "1.0.0", networkLiveness: "UP"))
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ struct ConnectionsPopover: View {
Divider()
ConnectionCell(label: "Internet", connection: monitor.connections.internet)
Divider()
if let tor = monitor.connections.tor {
ConnectionCell(label: "Tor", connection: tor)
Divider()
}
ConnectionCell(label: "Lightning peer", connection: monitor.connections.peer)
Divider()
ConnectionCell(label: "Electrum server", connection: monitor.connections.electrum)
Expand Down
4 changes: 3 additions & 1 deletion phoenix-shared/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ kotlin {
val coroutinesVersion = "1.4.2-native-mt"
val serializationVersion = "1.0.0"
val secp256k1Version = "0.4.1"
val ktorVersion = "1.4.1"
val ktorVersion = "1.5.0"
val kodeinDBVersion = "0.2.0-beta"
val sqldelightVersion = "1.4.4"

val commonMain by getting {
dependencies {
api("fr.acinq.eclair:eclair-kmp:snapshot")
api("fr.acinq.tor:tor-mobile-kmp:0.1.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serializationVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-cbor:$serializationVersion")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
Expand All @@ -81,6 +82,7 @@ kotlin {

val commonTest by getting {
dependencies {
implementation("fr.acinq.eclair:eclair-kmp-test-fixtures:snapshot")
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import fr.acinq.phoenix.ctrl.config.*
import fr.acinq.phoenix.data.Chain
import fr.acinq.phoenix.db.*
import fr.acinq.phoenix.utils.*
import fr.acinq.tor.Tor
import io.ktor.client.*
import io.ktor.client.features.json.JsonFeature
import io.ktor.client.features.json.serializer.*
Expand Down Expand Up @@ -40,7 +41,15 @@ class PhoenixBusiness(private val ctx: PlatformContext) {
logMemory.withShortPackageKeepLast(1)
)

public val tor by lazy { Tor(getApplicationCacheDirectoryPath(ctx), torLog(loggerFactory)) }

private val tcpSocketBuilder = TcpSocket.Builder()
private val tcpSockerBuilderFactory = {
if (appConfigurationManager.isTorEnabled.value)
tcpSocketBuilder.torProxy(loggerFactory)
else
tcpSocketBuilder
}

private val networkMonitor by lazy { NetworkMonitor(loggerFactory, ctx) }
private val httpClient by lazy {
Expand All @@ -64,18 +73,18 @@ class PhoenixBusiness(private val ctx: PlatformContext) {

private val masterPubkeyPath = if (chain == Chain.MAINNET) "m/84'/0'/0'" else "m/84'/1'/0'"

private val electrumClient by lazy { ElectrumClient(tcpSocketBuilder, MainScope()) }
private val electrumClient by lazy { ElectrumClient(null, MainScope()) }
private val electrumWatcher by lazy { ElectrumWatcher(electrumClient, MainScope()) }

private var appConnectionsDaemon: AppConnectionsDaemon? = null

private val walletManager by lazy { WalletManager() }
private val peerManager by lazy { PeerManager(loggerFactory, walletManager, appConfigurationManager, paymentsDb, tcpSocketBuilder, electrumWatcher, chain, ctx) }
private val peerManager by lazy { PeerManager(loggerFactory, walletManager, appConfigurationManager, paymentsDb, electrumWatcher, chain, ctx) }
private val paymentsManager by lazy { PaymentsManager(loggerFactory, paymentsDb, peerManager) }
private val appConfigurationManager by lazy { AppConfigurationManager(noSqlAppDB, appDb, httpClient, electrumClient, chain, loggerFactory) }

val currencyManager by lazy { CurrencyManager(loggerFactory, noSqlAppDB, httpClient) }
val connectionsMonitor by lazy { ConnectionsMonitor(peerManager, electrumClient, networkMonitor) }
val connectionsMonitor by lazy { ConnectionsMonitor(peerManager, electrumClient, networkMonitor, appConfigurationManager, tor) }
val util by lazy { Utilities(loggerFactory, chain) }

init {
Expand All @@ -90,6 +99,8 @@ class PhoenixBusiness(private val ctx: PlatformContext) {
peerManager,
currencyManager,
networkMonitor,
tcpSockerBuilderFactory,
tor,
electrumClient,
loggerFactory,
)
Expand Down Expand Up @@ -140,6 +151,7 @@ class PhoenixBusiness(private val ctx: PlatformContext) {
override fun scan(): ScanController = AppScanController(loggerFactory, peerManager)
override fun restoreWallet(): RestoreWalletController = AppRestoreWalletController(loggerFactory)
override fun configuration(): ConfigurationController = AppConfigurationController(loggerFactory, walletManager)
override fun torConfiguration(): TorConfigurationController = AppTorConfigurationController(loggerFactory, tor)
override fun electrumConfiguration(): ElectrumConfigurationController = AppElectrumConfigurationController(loggerFactory, appConfigurationManager, chain, masterPubkeyPath, walletManager, electrumClient)
override fun channelsConfiguration(): ChannelsConfigurationController = AppChannelsConfigurationController(loggerFactory, peerManager, chain)
override fun logsConfiguration(): LogsConfigurationController = AppLogsConfigurationController(ctx, loggerFactory, logMemory)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ class AppConfigurationManager(
//endregion

//region Tor configuration
private val isTorEnabled = MutableStateFlow(false)
fun subscribeToIsTorEnabled(): StateFlow<Boolean> = isTorEnabled
fun updateTorUsage(enabled: Boolean): Unit {
private val _isTorEnabled = MutableStateFlow(false)
public val isTorEnabled get() = _isTorEnabled
public fun updateTorUsage(enabled: Boolean): Unit {
isTorEnabled.value = enabled
}
//endregion
Expand Down
Loading