|
|
@ -13,7 +13,7 @@ public enum OnionRequestAPI {
|
|
|
|
public static var paths: [Path] = [] // Not a set to ensure we consistently show the same path to the user
|
|
|
|
public static var paths: [Path] = [] // Not a set to ensure we consistently show the same path to the user
|
|
|
|
|
|
|
|
|
|
|
|
// MARK: Settings
|
|
|
|
// MARK: Settings
|
|
|
|
public static let maxFileSize = 10_000_000 // 10 MB
|
|
|
|
public static let maxRequestSize = 10_000_000 // 10 MB
|
|
|
|
/// The number of snodes (including the guard snode) in a path.
|
|
|
|
/// The number of snodes (including the guard snode) in a path.
|
|
|
|
private static let pathSize: UInt = 3
|
|
|
|
private static let pathSize: UInt = 3
|
|
|
|
/// The number of times a path can fail before it's replaced.
|
|
|
|
/// The number of times a path can fail before it's replaced.
|
|
|
@ -88,10 +88,9 @@ public enum OnionRequestAPI {
|
|
|
|
return Promise<Set<Snode>> { $0.fulfill(guardSnodes) }
|
|
|
|
return Promise<Set<Snode>> { $0.fulfill(guardSnodes) }
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
SNLog("Populating guard snode cache.")
|
|
|
|
SNLog("Populating guard snode cache.")
|
|
|
|
return SnodeAPI.getRandomSnode().then2 { _ -> Promise<Set<Snode>> in // Just used to populate the snode pool
|
|
|
|
|
|
|
|
var unusedSnodes = SnodeAPI.snodePool.subtracting(reusableGuardSnodes) // Sync on LokiAPI.workQueue
|
|
|
|
var unusedSnodes = SnodeAPI.snodePool.subtracting(reusableGuardSnodes) // Sync on LokiAPI.workQueue
|
|
|
|
let reusableGuardSnodeCount = UInt(reusableGuardSnodes.count)
|
|
|
|
let reusableGuardSnodeCount = UInt(reusableGuardSnodes.count)
|
|
|
|
guard unusedSnodes.count >= (targetGuardSnodeCount - reusableGuardSnodeCount) else { throw Error.insufficientSnodes }
|
|
|
|
guard unusedSnodes.count >= (targetGuardSnodeCount - reusableGuardSnodeCount) else { return Promise(error: Error.insufficientSnodes) }
|
|
|
|
func getGuardSnode() -> Promise<Snode> {
|
|
|
|
func getGuardSnode() -> Promise<Snode> {
|
|
|
|
// randomElement() uses the system's default random generator, which is cryptographically secure
|
|
|
|
// randomElement() uses the system's default random generator, which is cryptographically secure
|
|
|
|
guard let candidate = unusedSnodes.randomElement() else { return Promise<Snode> { $0.reject(Error.insufficientSnodes) } }
|
|
|
|
guard let candidate = unusedSnodes.randomElement() else { return Promise<Snode> { $0.reject(Error.insufficientSnodes) } }
|
|
|
@ -110,7 +109,6 @@ public enum OnionRequestAPI {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Builds and returns `targetPathCount` 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.
|
|
|
|
/// if not enough (reliable) snodes are available.
|
|
|
@ -120,7 +118,6 @@ public enum OnionRequestAPI {
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
DispatchQueue.main.async {
|
|
|
|
NotificationCenter.default.post(name: .buildingPaths, object: nil)
|
|
|
|
NotificationCenter.default.post(name: .buildingPaths, object: nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return SnodeAPI.getRandomSnode().then2 { _ -> Promise<[Path]> in // Just used to populate the snode pool
|
|
|
|
|
|
|
|
let reusableGuardSnodes = reusablePaths.map { $0[0] }
|
|
|
|
let reusableGuardSnodes = reusablePaths.map { $0[0] }
|
|
|
|
return getGuardSnodes(reusing: reusableGuardSnodes).map2 { guardSnodes -> [Path] in
|
|
|
|
return getGuardSnodes(reusing: reusableGuardSnodes).map2 { guardSnodes -> [Path] in
|
|
|
|
var unusedSnodes = SnodeAPI.snodePool.subtracting(guardSnodes).subtracting(reusablePaths.flatMap { $0 })
|
|
|
|
var unusedSnodes = SnodeAPI.snodePool.subtracting(guardSnodes).subtracting(reusablePaths.flatMap { $0 })
|
|
|
@ -150,7 +147,6 @@ public enum OnionRequestAPI {
|
|
|
|
return paths
|
|
|
|
return paths
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns a `Path` to be used for building an onion request. Builds new paths as needed.
|
|
|
|
/// Returns a `Path` to be used for building an onion request. Builds new paths as needed.
|
|
|
|
private static func getPath(excluding snode: Snode?) -> Promise<Path> {
|
|
|
|
private static func getPath(excluding snode: Snode?) -> Promise<Path> {
|
|
|
@ -353,7 +349,7 @@ public enum OnionRequestAPI {
|
|
|
|
let url = "\(guardSnode!.address):\(guardSnode!.port)/onion_req/v2"
|
|
|
|
let url = "\(guardSnode!.address):\(guardSnode!.port)/onion_req/v2"
|
|
|
|
let finalEncryptionResult = intermediate.finalEncryptionResult
|
|
|
|
let finalEncryptionResult = intermediate.finalEncryptionResult
|
|
|
|
let onion = finalEncryptionResult.ciphertext
|
|
|
|
let onion = finalEncryptionResult.ciphertext
|
|
|
|
if case Destination.server = destination, Double(onion.count) > 0.75 * Double(maxFileSize) {
|
|
|
|
if case Destination.server = destination, Double(onion.count) > 0.75 * Double(maxRequestSize) {
|
|
|
|
SNLog("Approaching request size limit: ~\(onion.count) bytes.")
|
|
|
|
SNLog("Approaching request size limit: ~\(onion.count) bytes.")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let parameters: JSON = [
|
|
|
|
let parameters: JSON = [
|
|
|
|