From ec5995010a4b85087317690cda88f6a589389175 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 09:27:11 +1100 Subject: [PATCH 01/19] Re-use paths if possible --- .../API/Onion Requests/OnionRequestAPI.swift | 72 +++++++++++++------ .../Storage+OnionRequests.swift | 32 +++++---- 2 files changed, 66 insertions(+), 38 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 8024e30db..29d787331 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -71,14 +71,16 @@ public enum OnionRequestAPI { /// Finds `guardSnodeCount` guard snodes to use for path building. The returned promise errors out with `Error.insufficientSnodes` /// if not enough (reliable) snodes are available. - private static func getGuardSnodes() -> Promise> { + private static func getGuardSnodes(reusing reusableGuardSnodes: [Snode]) -> Promise> { if guardSnodes.count >= guardSnodeCount { return Promise> { $0.fulfill(guardSnodes) } } else { + print("[Test] reusableGuardSnodes: \(reusableGuardSnodes)") print("[Loki] [Onion Request API] Populating guard snode cache.") return SnodeAPI.getRandomSnode().then2 { _ -> Promise> in // Just used to populate the snode pool - var unusedSnodes = SnodeAPI.snodePool // Sync on LokiAPI.workQueue - guard unusedSnodes.count >= guardSnodeCount else { throw Error.insufficientSnodes } + var unusedSnodes = SnodeAPI.snodePool.subtracting(reusableGuardSnodes) // Sync on LokiAPI.workQueue + let reusableGuardSnodeCount = UInt(reusableGuardSnodes.count) + guard unusedSnodes.count >= (guardSnodeCount - reusableGuardSnodeCount) else { throw Error.insufficientSnodes } func getGuardSnode() -> Promise { // randomElement() uses the system's default random generator, which is cryptographically secure guard let candidate = unusedSnodes.randomElement() else { return Promise { $0.reject(Error.insufficientSnodes) } } @@ -86,12 +88,13 @@ public enum OnionRequestAPI { print("[Loki] [Onion Request API] Testing guard snode: \(candidate).") // Loop until a reliable guard snode is found return testSnode(candidate).map2 { candidate }.recover(on: DispatchQueue.main) { _ in - withDelay(0.25, completionQueue: SnodeAPI.workQueue) { getGuardSnode() } + withDelay(0.1, completionQueue: SnodeAPI.workQueue) { getGuardSnode() } } } - let promises = (0.. Promise<[Path]> { + private static func buildPaths(reusing reusablePaths: [Path]) -> Promise<[Path]> { print("[Loki] [Onion Request API] Building onion request paths.") DispatchQueue.main.async { NotificationCenter.default.post(name: .buildingPaths, object: nil) } return SnodeAPI.getRandomSnode().then2 { _ -> Promise<[Path]> in // Just used to populate the snode pool - return getGuardSnodes().map2 { guardSnodes -> [Path] in + let reusableGuardSnodes = reusablePaths.map { $0[0] } + return getGuardSnodes(reusing: reusableGuardSnodes).map2 { guardSnodes -> [Path] in + print("[Test] reusablePaths: \(reusablePaths)") var unusedSnodes = SnodeAPI.snodePool.subtracting(guardSnodes) - let pathSnodeCount = guardSnodeCount * pathSize - guardSnodeCount + let reusableGuardSnodeCount = UInt(reusableGuardSnodes.count) + let pathSnodeCount = (guardSnodeCount - reusableGuardSnodeCount) * pathSize - (guardSnodeCount - reusableGuardSnodeCount) guard unusedSnodes.count >= pathSnodeCount else { throw Error.insufficientSnodes } // Don't test path snodes as this would reveal the user's IP to them - return guardSnodes.map { guardSnode in + return guardSnodes.subtracting(reusableGuardSnodes).map { guardSnode in let result = [ guardSnode ] + (0..<(pathSize - 1)).map { _ in // randomElement() uses the system's default random generator, which is cryptographically secure let pathSnode = unusedSnodes.randomElement()! // Safe because of the pathSnodeCount check above @@ -123,7 +129,8 @@ public enum OnionRequestAPI { return result } }.map2 { paths in - OnionRequestAPI.paths = paths + print("[Test] paths: \(paths + reusablePaths)") + OnionRequestAPI.paths = paths + reusablePaths try! Storage.writeSync { transaction in print("[Loki] Persisting onion request paths to database.") Storage.setOnionRequestPaths(paths, using: transaction) @@ -140,11 +147,14 @@ public enum OnionRequestAPI { private static func getPath(excluding snode: Snode?) -> Promise { guard pathSize >= 1 else { preconditionFailure("Can't build path of size zero.") } var paths = OnionRequestAPI.paths - if paths.count < pathCount { + if paths.isEmpty { paths = Storage.getOnionRequestPaths() OnionRequestAPI.paths = paths - if paths.count >= pathCount { - guardSnodes.formUnion([ paths[0][0], paths[1][0] ]) + if !paths.isEmpty { + guardSnodes.formUnion([ paths[0][0] ]) + if paths.count >= 2 { + guardSnodes.formUnion([ paths[1][0] ]) + } } } // randomElement() uses the system's default random generator, which is cryptographically secure @@ -157,7 +167,8 @@ public enum OnionRequestAPI { } } } else { - return buildPaths().map2 { paths in + print("[Test] Reusing: \(paths)") + return buildPaths(reusing: paths).map2 { paths in if let snode = snode { return paths.filter { !$0.contains(snode) }.randomElement()! } else { @@ -172,7 +183,11 @@ public enum OnionRequestAPI { } private static func drop(_ snode: Snode) throws { + // We repair the path here because we can do it sync. In the case where we drop a whole + // path we leave the re-building up to getPath(excluding:) because re-building the path + // in that case is async. var oldPaths = paths + print("[Test] [drop(_ snode: Snode)] oldPaths: \(oldPaths)") guard let pathIndex = oldPaths.firstIndex(where: { $0.contains(snode) }) else { return } var path = oldPaths[pathIndex] guard let snodeIndex = path.firstIndex(of: snode) else { return } @@ -184,6 +199,7 @@ public enum OnionRequestAPI { // Don't test the new snode as this would reveal the user's IP oldPaths.remove(at: pathIndex) let newPaths = oldPaths + [ path ] + print("[Test] [drop(_ snode: Snode)] newPaths: \(newPaths)") paths = newPaths try! Storage.writeSync { transaction in print("[Loki] Persisting onion request paths to database.") @@ -191,10 +207,16 @@ public enum OnionRequestAPI { } } - private static func dropAllPaths() { - paths.removeAll() + private static func drop(_ path: Path) { + var paths = self.paths + print("[Test] [drop(_ path: Path)] oldPaths: \(paths)") + guard let pathIndex = paths.firstIndex(of: path) else { return } + paths.remove(at: pathIndex) + print("[Test] [drop(_ path: Path)] newPaths: \(paths)") + self.paths = paths try! Storage.writeSync { transaction in - Storage.clearOnionRequestPaths(using: transaction) + print("[Loki] Persisting onion request paths to database.") + Storage.setOnionRequestPaths(paths, using: transaction) } } @@ -285,10 +307,11 @@ public enum OnionRequestAPI { "headers" : headers ] let destination = Destination.server(host: host, x25519PublicKey: x25519PublicKey) - return sendOnionRequest(with: payload, to: destination, isJSONRequired: isJSONRequired).recover2 { error -> Promise in + let promise = sendOnionRequest(with: payload, to: destination, isJSONRequired: isJSONRequired) + promise.catch2 { error in print("[Loki] [Onion Request API] Couldn't reach server: \(url) due to error: \(error).") - throw error } + return promise } internal static func sendOnionRequest(with payload: JSON, to destination: Destination, isJSONRequired: Bool = true) -> Promise { @@ -352,11 +375,13 @@ public enum OnionRequestAPI { guard case HTTP.Error.httpRequestFailed(let statusCode, let json) = error else { return } let path = paths.first { $0.contains(guardSnode) } func handleUnspecificError() { - path?.forEach { snode in + dropGuardSnode(guardSnode) + guard let path = path else { return } + path.forEach { snode in SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw } - dropAllPaths() - dropGuardSnode(guardSnode) + print("[Test] Unspecific error; dropping: \(path)") + drop(path) } let prefix = "Next node not found: " if let message = json?["result"] as? String, message.hasPrefix(prefix) { @@ -364,6 +389,7 @@ public enum OnionRequestAPI { if let path = path, let snode = path.first(where: { $0.publicKeySet?.ed25519Key == ed25519PublicKey }) { SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw do { + print("[Test] Specific error; dropping: \(snode)") try drop(snode) } catch { handleUnspecificError() diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift b/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift index 3ebeac856..bbcb7e0b6 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift @@ -5,38 +5,40 @@ public extension Storage { internal static let onionRequestPathCollection = "LokiOnionRequestPathCollection" internal static func setOnionRequestPaths(_ paths: [OnionRequestAPI.Path], using transaction: YapDatabaseReadWriteTransaction) { - // FIXME: This approach assumes 2 paths of length 3 each. We should do better than this. - guard paths.count == 2 else { return } - let path0 = paths[0] - let path1 = paths[1] - guard path0.count == 3, path1.count == 3 else { return } let collection = onionRequestPathCollection + // FIXME: This approach assumes either 1 or 2 paths of length 3 each. We should do better than this. + guard paths.count >= 1 else { return } + let path0 = paths[0] + guard path0.count == 3 else { return } transaction.setObject(path0[0], forKey: "0-0", inCollection: collection) transaction.setObject(path0[1], forKey: "0-1", inCollection: collection) transaction.setObject(path0[2], forKey: "0-2", inCollection: collection) + guard paths.count >= 2 else { return } + let path1 = paths[1] + guard path1.count == 3 else { return } transaction.setObject(path1[0], forKey: "1-0", inCollection: collection) transaction.setObject(path1[1], forKey: "1-1", inCollection: collection) transaction.setObject(path1[2], forKey: "1-2", inCollection: collection) } public static func getOnionRequestPaths() -> [OnionRequestAPI.Path] { + let collection = onionRequestPathCollection var result: [OnionRequestAPI.Path] = [] read { transaction in - let collection = onionRequestPathCollection if let path0Snode0 = transaction.object(forKey: "0-0", inCollection: collection) as? Snode, let path0Snode1 = transaction.object(forKey: "0-1", inCollection: collection) as? Snode, - let path0Snode2 = transaction.object(forKey: "0-2", inCollection: collection) as? Snode, - let path1Snode0 = transaction.object(forKey: "1-0", inCollection: collection) as? Snode, - let path1Snode1 = transaction.object(forKey: "1-1", inCollection: collection) as? Snode, - let path1Snode2 = transaction.object(forKey: "1-2", inCollection: collection) as? Snode { - result = [ [ path0Snode0, path0Snode1, path0Snode2 ], [ path1Snode0, path1Snode1, path1Snode2 ] ] + let path0Snode2 = transaction.object(forKey: "0-2", inCollection: collection) as? Snode { + result.append([ path0Snode0, path0Snode1, path0Snode2 ]) + if + let path1Snode0 = transaction.object(forKey: "1-0", inCollection: collection) as? Snode, + let path1Snode1 = transaction.object(forKey: "1-1", inCollection: collection) as? Snode, + let path1Snode2 = transaction.object(forKey: "1-2", inCollection: collection) as? Snode { + result.append([ path1Snode0, path1Snode1, path1Snode2 ]) + } } } + print("[Test] [getOnionRequestPaths()] result: \(result)") return result } - - internal static func clearOnionRequestPaths(using transaction: YapDatabaseReadWriteTransaction) { - transaction.removeAllObjects(inCollection: onionRequestPathCollection) - } } From 54e315f00d0b1be6d6e8c775e55e92548f249430 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 09:49:28 +1100 Subject: [PATCH 02/19] Don't immediately kick out misbehaving paths --- .../API/Onion Requests/OnionRequestAPI.swift | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 29d787331..4147dca75 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -9,6 +9,9 @@ public enum OnionRequestAPI { // MARK: Settings /// The number of snodes (including the guard snode) in a path. private static let pathSize: UInt = 3 + /// The number of times a path can fail before it's replaced. + private static let pathFailureThreshold: UInt = 2 + private static var pathFailureCount: [Path:UInt] = [:] public static let pathCount: UInt = 2 @@ -375,13 +378,18 @@ public enum OnionRequestAPI { guard case HTTP.Error.httpRequestFailed(let statusCode, let json) = error else { return } let path = paths.first { $0.contains(guardSnode) } func handleUnspecificError() { - dropGuardSnode(guardSnode) guard let path = path else { return } - path.forEach { snode in - SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw + let pathFailureCount = OnionRequestAPI.pathFailureCount[path] ?? 0 + if pathFailureCount >= pathFailureThreshold { + dropGuardSnode(guardSnode) + path.forEach { snode in + SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw + } + print("[Test] Unspecific error; dropping: \(path)") + drop(path) + } else { + OnionRequestAPI.pathFailureCount[path] = pathFailureCount + 1 } - print("[Test] Unspecific error; dropping: \(path)") - drop(path) } let prefix = "Next node not found: " if let message = json?["result"] as? String, message.hasPrefix(prefix) { From 60552eac2dc3b2e5a4acfed6edba7a102b4769a8 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 09:49:49 +1100 Subject: [PATCH 03/19] Fix missed case --- .../src/Loki/API/Onion Requests/OnionRequestAPI.swift | 8 ++++++-- .../Loki/API/Onion Requests/Storage+OnionRequests.swift | 4 ++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 4147dca75..8478bdc2d 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -218,8 +218,12 @@ public enum OnionRequestAPI { print("[Test] [drop(_ path: Path)] newPaths: \(paths)") self.paths = paths try! Storage.writeSync { transaction in - print("[Loki] Persisting onion request paths to database.") - Storage.setOnionRequestPaths(paths, using: transaction) + if !paths.isEmpty { + print("[Loki] Persisting onion request paths to database.") + Storage.setOnionRequestPaths(paths, using: transaction) + } else { + Storage.clearOnionRequestPaths(using: transaction) + } } } diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift b/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift index bbcb7e0b6..597e525f3 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift @@ -41,4 +41,8 @@ public extension Storage { print("[Test] [getOnionRequestPaths()] result: \(result)") return result } + + internal static func clearOnionRequestPaths(using transaction: YapDatabaseReadWriteTransaction) { + transaction.removeAllObjects(inCollection: onionRequestPathCollection) + } } From 008f74bd89b1e1c5898664bc059af6a6ae0a0433 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 09:50:15 +1100 Subject: [PATCH 04/19] Update UI for new path maintenance approach --- Signal/src/Loki/Utilities/IP2Country.swift | 4 ++-- Signal/src/Loki/View Controllers/PathVC.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Signal/src/Loki/Utilities/IP2Country.swift b/Signal/src/Loki/Utilities/IP2Country.swift index bc8309df1..fe67cfa7c 100644 --- a/Signal/src/Loki/Utilities/IP2Country.swift +++ b/Signal/src/Loki/Utilities/IP2Country.swift @@ -51,11 +51,11 @@ final class IP2Country { } func populateCacheIfNeeded() -> Bool { - if OnionRequestAPI.paths.count < OnionRequestAPI.pathCount { + if OnionRequestAPI.paths.isEmpty { OnionRequestAPI.paths = Storage.getOnionRequestPaths() } let paths = OnionRequestAPI.paths - guard paths.count >= OnionRequestAPI.pathCount else { return false } + guard !paths.isEmpty else { return false } let pathToDisplay = paths.first! pathToDisplay.forEach { snode in let _ = self.cacheCountry(for: snode.ip) // Preload if needed diff --git a/Signal/src/Loki/View Controllers/PathVC.swift b/Signal/src/Loki/View Controllers/PathVC.swift index 3924a856a..57e3d7bb5 100644 --- a/Signal/src/Loki/View Controllers/PathVC.swift +++ b/Signal/src/Loki/View Controllers/PathVC.swift @@ -105,7 +105,7 @@ final class PathVC : BaseVC { private func update() { pathStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } - if OnionRequestAPI.paths.count >= OnionRequestAPI.pathCount { + if !OnionRequestAPI.paths.isEmpty { let pathToDisplay = OnionRequestAPI.paths.first! let dotAnimationRepeatInterval = Double(pathToDisplay.count) + 2 let snodeRows: [UIStackView] = pathToDisplay.enumerated().map { index, snode in From 5987039f8b3b554e7310381d81f5dca506db0b81 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 10:10:01 +1100 Subject: [PATCH 05/19] Make path re-building non-blocking --- .../src/Loki/Components/PathStatusView.swift | 4 +-- .../API/Onion Requests/OnionRequestAPI.swift | 32 +++++++++++++------ 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/Signal/src/Loki/Components/PathStatusView.swift b/Signal/src/Loki/Components/PathStatusView.swift index e1d934bb2..1e0dcdf6c 100644 --- a/Signal/src/Loki/Components/PathStatusView.swift +++ b/Signal/src/Loki/Components/PathStatusView.swift @@ -16,10 +16,10 @@ final class PathStatusView : UIView { private func setUpViewHierarchy() { layer.cornerRadius = Values.pathStatusViewSize / 2 layer.masksToBounds = false - if OnionRequestAPI.paths.count < OnionRequestAPI.pathCount { + if OnionRequestAPI.paths.isEmpty { OnionRequestAPI.paths = Storage.getOnionRequestPaths() } - let color = (OnionRequestAPI.paths.count >= OnionRequestAPI.pathCount) ? Colors.accent : Colors.pathsBuilding + let color = (!OnionRequestAPI.paths.isEmpty) ? Colors.accent : Colors.pathsBuilding setColor(to: color, isAnimated: false) } diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 8478bdc2d..1db5aa8f8 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -13,9 +13,9 @@ public enum OnionRequestAPI { private static let pathFailureThreshold: UInt = 2 private static var pathFailureCount: [Path:UInt] = [:] - public static let pathCount: UInt = 2 + public static let targetPathCount: UInt = 2 - private static var guardSnodeCount: UInt { return pathCount } // One per path + private static var guardSnodeCount: UInt { return targetPathCount } // One per path // MARK: Destination internal enum Destination { @@ -105,7 +105,7 @@ public enum OnionRequestAPI { } } - /// Builds and returns `pathCount` paths. The returned promise errors out with `Error.insufficientSnodes` + /// Builds and returns `targetPathCount` paths. The returned promise errors out with `Error.insufficientSnodes` /// if not enough (reliable) snodes are available. private static func buildPaths(reusing reusablePaths: [Path]) -> Promise<[Path]> { print("[Loki] [Onion Request API] Building onion request paths.") @@ -161,17 +161,29 @@ public enum OnionRequestAPI { } } // randomElement() uses the system's default random generator, which is cryptographically secure - if paths.count >= pathCount { - return Promise { seal in - if let snode = snode { - seal.fulfill(paths.filter { !$0.contains(snode) }.randomElement()!) + if paths.count >= targetPathCount { + if let snode = snode { + return Promise { $0.fulfill(paths.filter { !$0.contains(snode) }.randomElement()!) } + } else { + return Promise { $0.fulfill(paths.randomElement()!) } + } + } else if !paths.isEmpty { + print("[Test] Reusing: \(paths)") + if let snode = snode { + if let path = paths.first(where: { !$0.contains(snode) }) { + buildPaths(reusing: paths).retainUntilComplete() // Re-build paths in the background + return Promise { $0.fulfill(path) } } else { - seal.fulfill(paths.randomElement()!) + return buildPaths(reusing: paths).map2 { paths in + return paths.filter { !$0.contains(snode) }.randomElement()! + } } + } else { + buildPaths(reusing: paths).retainUntilComplete() // Re-build paths in the background + return Promise { $0.fulfill(paths.randomElement()!) } } } else { - print("[Test] Reusing: \(paths)") - return buildPaths(reusing: paths).map2 { paths in + return buildPaths(reusing: []).map2 { paths in if let snode = snode { return paths.filter { !$0.contains(snode) }.randomElement()! } else { From c21b609dfde3db816a4f3995d2c9668554724abe Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 11:03:36 +1100 Subject: [PATCH 06/19] Minor refactoring --- .../API/Onion Requests/OnionRequestAPI.swift | 144 +++++++++--------- 1 file changed, 73 insertions(+), 71 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 1db5aa8f8..d3ae2d75e 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -3,6 +3,7 @@ import PromiseKit /// See the "Onion Requests" section of [The Session Whitepaper](https://arxiv.org/pdf/2002.04609.pdf) for more information. public enum OnionRequestAPI { + private static var pathFailureCount: [Path:UInt] = [:] public static var guardSnodes: Set = [] public static var paths: [Path] = [] // Not a set to ensure we consistently show the same path to the user @@ -11,11 +12,11 @@ public enum OnionRequestAPI { private static let pathSize: UInt = 3 /// The number of times a path can fail before it's replaced. private static let pathFailureThreshold: UInt = 2 - private static var pathFailureCount: [Path:UInt] = [:] - + /// The number of paths to maintain. public static let targetPathCount: UInt = 2 - private static var guardSnodeCount: UInt { return targetPathCount } // One per path + /// The number of guard snodes required to maintain `targetPathCount` paths. + private static var targetGuardSnodeCount: UInt { return targetPathCount } // One per path // MARK: Destination internal enum Destination { @@ -75,7 +76,7 @@ public enum OnionRequestAPI { /// Finds `guardSnodeCount` guard snodes to use for path building. The returned promise errors out with `Error.insufficientSnodes` /// if not enough (reliable) snodes are available. private static func getGuardSnodes(reusing reusableGuardSnodes: [Snode]) -> Promise> { - if guardSnodes.count >= guardSnodeCount { + if guardSnodes.count >= targetGuardSnodeCount { return Promise> { $0.fulfill(guardSnodes) } } else { print("[Test] reusableGuardSnodes: \(reusableGuardSnodes)") @@ -83,7 +84,7 @@ public enum OnionRequestAPI { return SnodeAPI.getRandomSnode().then2 { _ -> Promise> in // Just used to populate the snode pool var unusedSnodes = SnodeAPI.snodePool.subtracting(reusableGuardSnodes) // Sync on LokiAPI.workQueue let reusableGuardSnodeCount = UInt(reusableGuardSnodes.count) - guard unusedSnodes.count >= (guardSnodeCount - reusableGuardSnodeCount) else { throw Error.insufficientSnodes } + guard unusedSnodes.count >= (targetGuardSnodeCount - reusableGuardSnodeCount) else { throw Error.insufficientSnodes } func getGuardSnode() -> Promise { // randomElement() uses the system's default random generator, which is cryptographically secure guard let candidate = unusedSnodes.randomElement() else { return Promise { $0.reject(Error.insufficientSnodes) } } @@ -94,7 +95,7 @@ public enum OnionRequestAPI { withDelay(0.1, completionQueue: SnodeAPI.workQueue) { getGuardSnode() } } } - let promises = (0..<(guardSnodeCount - reusableGuardSnodeCount)).map { _ in getGuardSnode() } + let promises = (0..<(targetGuardSnodeCount - reusableGuardSnodeCount)).map { _ in getGuardSnode() } return when(fulfilled: promises).map2 { guardSnodes in let guardSnodesAsSet = Set(guardSnodes + reusableGuardSnodes) print("[Test] guardSnodes: \(guardSnodesAsSet)") @@ -118,7 +119,7 @@ public enum OnionRequestAPI { print("[Test] reusablePaths: \(reusablePaths)") var unusedSnodes = SnodeAPI.snodePool.subtracting(guardSnodes) let reusableGuardSnodeCount = UInt(reusableGuardSnodes.count) - let pathSnodeCount = (guardSnodeCount - reusableGuardSnodeCount) * pathSize - (guardSnodeCount - reusableGuardSnodeCount) + let pathSnodeCount = (targetGuardSnodeCount - reusableGuardSnodeCount) * pathSize - (targetGuardSnodeCount - reusableGuardSnodeCount) guard unusedSnodes.count >= pathSnodeCount else { throw Error.insufficientSnodes } // Don't test path snodes as this would reveal the user's IP to them return guardSnodes.subtracting(reusableGuardSnodes).map { guardSnode in @@ -272,68 +273,7 @@ public enum OnionRequestAPI { }.map2 { _ in (guardSnode, encryptionResult, targetSnodeSymmetricKey) } } - // MARK: Internal API - /// Sends an onion request to `snode`. Builds new paths as needed. - internal static func sendOnionRequest(to snode: Snode, invoking method: Snode.Method, with parameters: JSON, associatedWith publicKey: String) -> Promise { - let payload: JSON = [ "method" : method.rawValue, "params" : parameters ] - return sendOnionRequest(with: payload, to: Destination.snode(snode)).recover2 { error -> Promise in - guard case OnionRequestAPI.Error.httpRequestFailedAtDestination(let statusCode, let json) = error else { throw error } - throw SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode, associatedWith: publicKey) ?? error - } - } - - /// Sends an onion request to `server`. Builds new paths as needed. - internal static func sendOnionRequest(_ request: NSURLRequest, to server: String, using x25519PublicKey: String, isJSONRequired: Bool = true) -> Promise { - let rawHeaders = request.allHTTPHeaderFields ?? [:] - var headers: JSON = rawHeaders.mapValues { value in - switch value.lowercased() { - case "true": return true - case "false": return false - default: return value - } - } - guard let url = request.url?.absoluteString, let host = request.url?.host else { return Promise(error: Error.invalidURL) } - var endpoint = "" - if server.count < url.count { - guard let serverEndIndex = url.range(of: server)?.upperBound else { return Promise(error: Error.invalidURL) } - let endpointStartIndex = url.index(after: serverEndIndex) - endpoint = String(url[endpointStartIndex.. Promise { + private static func sendOnionRequest(with payload: JSON, to destination: Destination, isJSONRequired: Bool = true) -> Promise { let (promise, seal) = Promise.pending() var guardSnode: Snode! SnodeAPI.workQueue.async { // Avoid race conditions on `guardSnodes` and `paths` @@ -395,7 +335,8 @@ public enum OnionRequestAPI { let path = paths.first { $0.contains(guardSnode) } func handleUnspecificError() { guard let path = path else { return } - let pathFailureCount = OnionRequestAPI.pathFailureCount[path] ?? 0 + var pathFailureCount = OnionRequestAPI.pathFailureCount[path] ?? 0 + pathFailureCount += 1 if pathFailureCount >= pathFailureThreshold { dropGuardSnode(guardSnode) path.forEach { snode in @@ -404,7 +345,7 @@ public enum OnionRequestAPI { print("[Test] Unspecific error; dropping: \(path)") drop(path) } else { - OnionRequestAPI.pathFailureCount[path] = pathFailureCount + 1 + OnionRequestAPI.pathFailureCount[path] = pathFailureCount } } let prefix = "Next node not found: " @@ -427,4 +368,65 @@ public enum OnionRequestAPI { } return promise } + + // MARK: Internal API + /// Sends an onion request to `snode`. Builds new paths as needed. + internal static func sendOnionRequest(to snode: Snode, invoking method: Snode.Method, with parameters: JSON, associatedWith publicKey: String) -> Promise { + let payload: JSON = [ "method" : method.rawValue, "params" : parameters ] + return sendOnionRequest(with: payload, to: Destination.snode(snode)).recover2 { error -> Promise in + guard case OnionRequestAPI.Error.httpRequestFailedAtDestination(let statusCode, let json) = error else { throw error } + throw SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode, associatedWith: publicKey) ?? error + } + } + + /// Sends an onion request to `server`. Builds new paths as needed. + internal static func sendOnionRequest(_ request: NSURLRequest, to server: String, using x25519PublicKey: String, isJSONRequired: Bool = true) -> Promise { + let rawHeaders = request.allHTTPHeaderFields ?? [:] + var headers: JSON = rawHeaders.mapValues { value in + switch value.lowercased() { + case "true": return true + case "false": return false + default: return value + } + } + guard let url = request.url?.absoluteString, let host = request.url?.host else { return Promise(error: Error.invalidURL) } + var endpoint = "" + if server.count < url.count { + guard let serverEndIndex = url.range(of: server)?.upperBound else { return Promise(error: Error.invalidURL) } + let endpointStartIndex = url.index(after: serverEndIndex) + endpoint = String(url[endpointStartIndex.. Date: Fri, 9 Oct 2020 11:21:49 +1100 Subject: [PATCH 07/19] Remove debug logs --- .../src/Loki/API/Onion Requests/OnionRequestAPI.swift | 11 ----------- .../API/Onion Requests/Storage+OnionRequests.swift | 1 - 2 files changed, 12 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index d3ae2d75e..5ff30a9e0 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -79,7 +79,6 @@ public enum OnionRequestAPI { if guardSnodes.count >= targetGuardSnodeCount { return Promise> { $0.fulfill(guardSnodes) } } else { - print("[Test] reusableGuardSnodes: \(reusableGuardSnodes)") print("[Loki] [Onion Request API] Populating guard snode cache.") return SnodeAPI.getRandomSnode().then2 { _ -> Promise> in // Just used to populate the snode pool var unusedSnodes = SnodeAPI.snodePool.subtracting(reusableGuardSnodes) // Sync on LokiAPI.workQueue @@ -98,7 +97,6 @@ public enum OnionRequestAPI { let promises = (0..<(targetGuardSnodeCount - reusableGuardSnodeCount)).map { _ in getGuardSnode() } return when(fulfilled: promises).map2 { guardSnodes in let guardSnodesAsSet = Set(guardSnodes + reusableGuardSnodes) - print("[Test] guardSnodes: \(guardSnodesAsSet)") OnionRequestAPI.guardSnodes = guardSnodesAsSet return guardSnodesAsSet } @@ -116,7 +114,6 @@ public enum OnionRequestAPI { return SnodeAPI.getRandomSnode().then2 { _ -> Promise<[Path]> in // Just used to populate the snode pool let reusableGuardSnodes = reusablePaths.map { $0[0] } return getGuardSnodes(reusing: reusableGuardSnodes).map2 { guardSnodes -> [Path] in - print("[Test] reusablePaths: \(reusablePaths)") var unusedSnodes = SnodeAPI.snodePool.subtracting(guardSnodes) let reusableGuardSnodeCount = UInt(reusableGuardSnodes.count) let pathSnodeCount = (targetGuardSnodeCount - reusableGuardSnodeCount) * pathSize - (targetGuardSnodeCount - reusableGuardSnodeCount) @@ -133,7 +130,6 @@ public enum OnionRequestAPI { return result } }.map2 { paths in - print("[Test] paths: \(paths + reusablePaths)") OnionRequestAPI.paths = paths + reusablePaths try! Storage.writeSync { transaction in print("[Loki] Persisting onion request paths to database.") @@ -169,7 +165,6 @@ public enum OnionRequestAPI { return Promise { $0.fulfill(paths.randomElement()!) } } } else if !paths.isEmpty { - print("[Test] Reusing: \(paths)") if let snode = snode { if let path = paths.first(where: { !$0.contains(snode) }) { buildPaths(reusing: paths).retainUntilComplete() // Re-build paths in the background @@ -203,7 +198,6 @@ public enum OnionRequestAPI { // path we leave the re-building up to getPath(excluding:) because re-building the path // in that case is async. var oldPaths = paths - print("[Test] [drop(_ snode: Snode)] oldPaths: \(oldPaths)") guard let pathIndex = oldPaths.firstIndex(where: { $0.contains(snode) }) else { return } var path = oldPaths[pathIndex] guard let snodeIndex = path.firstIndex(of: snode) else { return } @@ -215,7 +209,6 @@ public enum OnionRequestAPI { // Don't test the new snode as this would reveal the user's IP oldPaths.remove(at: pathIndex) let newPaths = oldPaths + [ path ] - print("[Test] [drop(_ snode: Snode)] newPaths: \(newPaths)") paths = newPaths try! Storage.writeSync { transaction in print("[Loki] Persisting onion request paths to database.") @@ -225,10 +218,8 @@ public enum OnionRequestAPI { private static func drop(_ path: Path) { var paths = self.paths - print("[Test] [drop(_ path: Path)] oldPaths: \(paths)") guard let pathIndex = paths.firstIndex(of: path) else { return } paths.remove(at: pathIndex) - print("[Test] [drop(_ path: Path)] newPaths: \(paths)") self.paths = paths try! Storage.writeSync { transaction in if !paths.isEmpty { @@ -342,7 +333,6 @@ public enum OnionRequestAPI { path.forEach { snode in SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw } - print("[Test] Unspecific error; dropping: \(path)") drop(path) } else { OnionRequestAPI.pathFailureCount[path] = pathFailureCount @@ -354,7 +344,6 @@ public enum OnionRequestAPI { if let path = path, let snode = path.first(where: { $0.publicKeySet?.ed25519Key == ed25519PublicKey }) { SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw do { - print("[Test] Specific error; dropping: \(snode)") try drop(snode) } catch { handleUnspecificError() diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift b/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift index 597e525f3..e61ed440b 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift @@ -38,7 +38,6 @@ public extension Storage { } } } - print("[Test] [getOnionRequestPaths()] result: \(result)") return result } From 98a3f9fafb4d34011bffc65b32189f07ed20645e Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 14:11:41 +1100 Subject: [PATCH 08/19] Minor refactoring --- .../src/Loki/API/Onion Requests/OnionRequestAPI.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 5ff30a9e0..4c4199f60 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -73,7 +73,7 @@ public enum OnionRequestAPI { return promise } - /// Finds `guardSnodeCount` guard snodes to use for path building. The returned promise errors out with `Error.insufficientSnodes` + /// Finds `targetGuardSnodeCount` guard snodes to use for path building. The returned promise errors out with `Error.insufficientSnodes` /// if not enough (reliable) snodes are available. private static func getGuardSnodes(reusing reusableGuardSnodes: [Snode]) -> Promise> { if guardSnodes.count >= targetGuardSnodeCount { @@ -114,7 +114,7 @@ public enum OnionRequestAPI { return SnodeAPI.getRandomSnode().then2 { _ -> Promise<[Path]> in // Just used to populate the snode pool let reusableGuardSnodes = reusablePaths.map { $0[0] } return getGuardSnodes(reusing: reusableGuardSnodes).map2 { guardSnodes -> [Path] in - var unusedSnodes = SnodeAPI.snodePool.subtracting(guardSnodes) + var unusedSnodes = SnodeAPI.snodePool.subtracting(guardSnodes).subtracting(reusablePaths.flatMap { $0 }) let reusableGuardSnodeCount = UInt(reusableGuardSnodes.count) let pathSnodeCount = (targetGuardSnodeCount - reusableGuardSnodeCount) * pathSize - (targetGuardSnodeCount - reusableGuardSnodeCount) guard unusedSnodes.count >= pathSnodeCount else { throw Error.insufficientSnodes } @@ -217,10 +217,10 @@ public enum OnionRequestAPI { } private static func drop(_ path: Path) { - var paths = self.paths + var paths = OnionRequestAPI.paths guard let pathIndex = paths.firstIndex(of: path) else { return } paths.remove(at: pathIndex) - self.paths = paths + OnionRequestAPI.paths = paths try! Storage.writeSync { transaction in if !paths.isEmpty { print("[Loki] Persisting onion request paths to database.") From aff5f59455251abcdac8943d1ccd011645fca0da Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 14:39:06 +1100 Subject: [PATCH 09/19] Debug --- .../src/Loki/API/Onion Requests/Storage+OnionRequests.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift b/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift index e61ed440b..3a1e417ba 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/Storage+OnionRequests.swift @@ -7,6 +7,7 @@ public extension Storage { internal static func setOnionRequestPaths(_ paths: [OnionRequestAPI.Path], using transaction: YapDatabaseReadWriteTransaction) { let collection = onionRequestPathCollection // FIXME: This approach assumes either 1 or 2 paths of length 3 each. We should do better than this. + clearOnionRequestPaths(using: transaction) guard paths.count >= 1 else { return } let path0 = paths[0] guard path0.count == 3 else { return } From d67ab830e670504696419c185ddebfb90edda4f0 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Fri, 9 Oct 2020 16:08:22 +1100 Subject: [PATCH 10/19] Update version number --- Signal.xcodeproj/project.pbxproj | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 03bff2116..61cd2a1b2 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4143,7 +4143,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 127; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4157,7 +4157,7 @@ INFOPLIST_FILE = SignalShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.6.1; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.share-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -4205,7 +4205,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 127; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4224,7 +4224,7 @@ INFOPLIST_FILE = SignalShareExtension/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.6.1; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.share-extension"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -4259,7 +4259,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 127; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4278,7 +4278,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.6.1; MTL_ENABLE_DEBUG_INFO = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.utilities"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; @@ -4329,7 +4329,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 127; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4353,7 +4353,7 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.6.1; MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.utilities"; PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; @@ -4391,7 +4391,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 127; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4403,7 +4403,7 @@ INFOPLIST_FILE = LokiPushNotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.6.1; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service"; @@ -4454,7 +4454,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 127; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4471,7 +4471,7 @@ INFOPLIST_FILE = LokiPushNotificationService/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 12.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks"; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.6.1; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.push-notification-service"; @@ -4655,7 +4655,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4690,7 +4690,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.6.1; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; @@ -4722,7 +4722,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 125; + CURRENT_PROJECT_VERSION = 127; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4757,7 +4757,7 @@ "$(SRCROOT)", ); LLVM_LTO = NO; - MARKETING_VERSION = 1.6.0; + MARKETING_VERSION = 1.6.1; OTHER_LDFLAGS = "$(inherited)"; PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger"; PRODUCT_NAME = Session; From 62b2fa112bae18e7bf0c45f18fa0c40171fa3ada Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 22 Oct 2020 13:19:28 +1100 Subject: [PATCH 11/19] Clean --- .../src/Loki/API/Onion Requests/OnionRequestAPI.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 1324460a0..7a91e7801 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -11,7 +11,7 @@ public enum OnionRequestAPI { /// The number of snodes (including the guard snode) in a path. private static let pathSize: UInt = 3 /// The number of times a path can fail before it's replaced. - private static let pathFailureThreshold: UInt = 2 + private static let pathFailureThreshold: UInt = 3 /// The number of paths to maintain. public static let targetPathCount: UInt = 2 @@ -313,8 +313,8 @@ public enum OnionRequestAPI { } let payload: JSON = [ "body" : parametersAsString, - "endpoint": endpoint, - "method" : request.httpMethod, + "endpoint" : endpoint, + "method" : request.httpMethod!, "headers" : headers ] let destination = Destination.server(host: host, x25519PublicKey: x25519PublicKey) From 9305bc94bbae5fc8a66fb445a7eb76d8bfa15879 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 22 Oct 2020 13:53:21 +1100 Subject: [PATCH 12/19] Introduce snode failure threshold --- .../API/Onion Requests/OnionRequestAPI.swift | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 7a91e7801..e5854c832 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -4,6 +4,7 @@ import PromiseKit /// See the "Onion Requests" section of [The Session Whitepaper](https://arxiv.org/pdf/2002.04609.pdf) for more information. public enum OnionRequestAPI { private static var pathFailureCount: [Path:UInt] = [:] + private static var snodeFailureCount: [Snode:UInt] = [:] public static var guardSnodes: Set = [] public static var paths: [Path] = [] // Not a set to ensure we consistently show the same path to the user @@ -11,7 +12,9 @@ public enum OnionRequestAPI { /// The number of snodes (including the guard snode) in a path. private static let pathSize: UInt = 3 /// The number of times a path can fail before it's replaced. - private static let pathFailureThreshold: UInt = 3 + private static let pathFailureThreshold: UInt = 2 + /// The number of times a path can fail before it's replaced. + private static let snodeFailureThreshold: UInt = 2 /// The number of paths to maintain. public static let targetPathCount: UInt = 2 @@ -197,6 +200,7 @@ public enum OnionRequestAPI { // We repair the path here because we can do it sync. In the case where we drop a whole // path we leave the re-building up to getPath(excluding:) because re-building the path // in that case is async. + OnionRequestAPI.snodeFailureCount[snode] = 0 var oldPaths = paths guard let pathIndex = oldPaths.firstIndex(where: { $0.contains(snode) }) else { return } var path = oldPaths[pathIndex] @@ -217,6 +221,7 @@ public enum OnionRequestAPI { } private static func drop(_ path: Path) { + OnionRequestAPI.pathFailureCount[path] = 0 var paths = OnionRequestAPI.paths guard let pathIndex = paths.firstIndex(of: path) else { return } paths.remove(at: pathIndex) @@ -403,11 +408,17 @@ public enum OnionRequestAPI { if let message = json?["result"] as? String, message.hasPrefix(prefix) { let ed25519PublicKey = message.substring(from: prefix.count) if let path = path, let snode = path.first(where: { $0.publicKeySet?.ed25519Key == ed25519PublicKey }) { - SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw - do { - try drop(snode) - } catch { - handleUnspecificError() + var snodeFailureCount = OnionRequestAPI.snodeFailureCount[snode] ?? 0 + snodeFailureCount += 1 + if snodeFailureCount >= snodeFailureThreshold { + SnodeAPI.handleError(withStatusCode: statusCode, json: json, forSnode: snode) // Intentionally don't throw + do { + try drop(snode) + } catch { + handleUnspecificError() + } + } else { + OnionRequestAPI.snodeFailureCount[snode] = snodeFailureCount } } else { handleUnspecificError() From f4c2c8ce9d2ae16bf44d6c543ff9cc5f769f4953 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 22 Oct 2020 14:18:04 +1100 Subject: [PATCH 13/19] Handle Loki server errors --- .../src/Loki/API/Onion Requests/OnionRequestAPI.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index e5854c832..7bce636ec 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -423,6 +423,8 @@ public enum OnionRequestAPI { } else { handleUnspecificError() } + } else if let message = json?["result"] as? String, message == "Loki Server error" { + // Do nothing } else { handleUnspecificError() } From f4d10a89bc9968efd60a5f9682284b40aad39c5f Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Thu, 22 Oct 2020 14:19:49 +1100 Subject: [PATCH 14/19] Update build number --- Signal.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 500e4ac7b..210b19c25 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4157,7 +4157,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 128; + CURRENT_PROJECT_VERSION = 129; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4219,7 +4219,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 128; + CURRENT_PROJECT_VERSION = 129; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4273,7 +4273,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 128; + CURRENT_PROJECT_VERSION = 129; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4343,7 +4343,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 128; + CURRENT_PROJECT_VERSION = 129; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4405,7 +4405,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 128; + CURRENT_PROJECT_VERSION = 129; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4468,7 +4468,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 128; + CURRENT_PROJECT_VERSION = 129; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4669,7 +4669,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 128; + CURRENT_PROJECT_VERSION = 129; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4736,7 +4736,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 128; + CURRENT_PROJECT_VERSION = 129; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 5a7cd392f68b425f96274ad4a253e69fddb72853 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 27 Oct 2020 11:51:36 +1100 Subject: [PATCH 15/19] Fix documentation --- .../src/Loki/API/Onion Requests/OnionRequestAPI.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index 7bce636ec..f74e4d558 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -13,7 +13,7 @@ public enum OnionRequestAPI { private static let pathSize: UInt = 3 /// The number of times a path can fail before it's replaced. private static let pathFailureThreshold: UInt = 2 - /// The number of times a path can fail before it's replaced. + /// The number of times a snode can fail before it's replaced. private static let snodeFailureThreshold: UInt = 2 /// The number of paths to maintain. public static let targetPathCount: UInt = 2 From 1313232de6aaf3a80280915170919213222164db Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 27 Oct 2020 14:26:09 +1100 Subject: [PATCH 16/19] Update build number --- Signal.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index a1d81a633..3e6438f91 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4157,7 +4157,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 130; + CURRENT_PROJECT_VERSION = 131; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4219,7 +4219,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 130; + CURRENT_PROJECT_VERSION = 131; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4273,7 +4273,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 130; + CURRENT_PROJECT_VERSION = 131; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4343,7 +4343,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 130; + CURRENT_PROJECT_VERSION = 131; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4405,7 +4405,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 130; + CURRENT_PROJECT_VERSION = 131; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4468,7 +4468,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 130; + CURRENT_PROJECT_VERSION = 131; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4669,7 +4669,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 130; + CURRENT_PROJECT_VERSION = 131; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4736,7 +4736,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 130; + CURRENT_PROJECT_VERSION = 131; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 2ea088e00a029604fb45a94c8b20840a6a9fb70c Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 27 Oct 2020 15:21:26 +1100 Subject: [PATCH 17/19] Add missing retry --- SignalServiceKit/src/Loki/API/DotNetAPI.swift | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/DotNetAPI.swift b/SignalServiceKit/src/Loki/API/DotNetAPI.swift index 6f574985c..ec59ced68 100644 --- a/SignalServiceKit/src/Loki/API/DotNetAPI.swift +++ b/SignalServiceKit/src/Loki/API/DotNetAPI.swift @@ -8,6 +8,7 @@ public class DotNetAPI : NSObject { // MARK: Settings private static let attachmentType = "network.loki" + private static let maxRetryCount: UInt = 4 // MARK: Error @objc(LKDotNetAPIError) @@ -123,13 +124,15 @@ public class DotNetAPI : NSObject { } let serverPublicKeyPromise = FileServerAPI.server.contains(host) ? Promise.value(FileServerAPI.fileServerPublicKey) : PublicChatAPI.getOpenGroupServerPublicKey(for: host) - return serverPublicKeyPromise.then2 { serverPublicKey in - return OnionRequestAPI.sendOnionRequest(request, to: host, using: serverPublicKey, isJSONRequired: false).map2 { json in - guard let body = json["body"] as? JSON, let data = body["data"] as? [UInt8] else { - print("[Loki] Couldn't parse attachment from: \(json).") - throw DotNetAPIError.parsingFailed + return attempt(maxRetryCount: maxRetryCount, recoveringOn: SnodeAPI.workQueue) { + serverPublicKeyPromise.then2 { serverPublicKey in + return OnionRequestAPI.sendOnionRequest(request, to: host, using: serverPublicKey, isJSONRequired: false).map2 { json in + guard let body = json["body"] as? JSON, let data = body["data"] as? [UInt8] else { + print("[Loki] Couldn't parse attachment from: \(json).") + throw DotNetAPIError.parsingFailed + } + return Data(data) } - return Data(data) } } } From 0fd31c992b424d59a3cd98f24a1d27aeda178083 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Tue, 27 Oct 2020 15:25:53 +1100 Subject: [PATCH 18/19] Update build number --- Signal.xcodeproj/project.pbxproj | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 3e6438f91..1ee515a19 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -4157,7 +4157,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 131; + CURRENT_PROJECT_VERSION = 132; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4219,7 +4219,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 131; + CURRENT_PROJECT_VERSION = 132; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4273,7 +4273,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 131; + CURRENT_PROJECT_VERSION = 132; DEBUG_INFORMATION_FORMAT = dwarf; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4343,7 +4343,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 131; + CURRENT_PROJECT_VERSION = 132; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = SUQ8J2PCT7; @@ -4405,7 +4405,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 131; + CURRENT_PROJECT_VERSION = 132; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -4468,7 +4468,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 131; + CURRENT_PROJECT_VERSION = 132; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -4669,7 +4669,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 131; + CURRENT_PROJECT_VERSION = 132; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -4736,7 +4736,7 @@ CODE_SIGN_ENTITLEMENTS = Signal/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 131; + CURRENT_PROJECT_VERSION = 132; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", From 11048c50e362a26b268246587987a421b40a5c64 Mon Sep 17 00:00:00 2001 From: nielsandriesse Date: Wed, 28 Oct 2020 08:46:44 +1100 Subject: [PATCH 19/19] Tweak onion request settings a bit more --- .../src/Loki/API/Onion Requests/OnionRequestAPI.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift index f74e4d558..9bef181e7 100644 --- a/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift +++ b/SignalServiceKit/src/Loki/API/Onion Requests/OnionRequestAPI.swift @@ -12,9 +12,9 @@ public enum OnionRequestAPI { /// The number of snodes (including the guard snode) in a path. private static let pathSize: UInt = 3 /// The number of times a path can fail before it's replaced. - private static let pathFailureThreshold: UInt = 2 + private static let pathFailureThreshold: UInt = 3 /// The number of times a snode can fail before it's replaced. - private static let snodeFailureThreshold: UInt = 2 + private static let snodeFailureThreshold: UInt = 3 /// The number of paths to maintain. public static let targetPathCount: UInt = 2