Handle incorrect clock setting
This commit is contained in:
parent
ac730e00b4
commit
8a29469eb5
|
@ -200,7 +200,8 @@ public final class MessageSender : NSObject {
|
||||||
}
|
}
|
||||||
// Send the result
|
// Send the result
|
||||||
let base64EncodedData = wrappedMessage.base64EncodedString()
|
let base64EncodedData = wrappedMessage.base64EncodedString()
|
||||||
let snodeMessage = SnodeMessage(recipient: message.recipient!, data: base64EncodedData, ttl: message.ttl, timestamp: message.sentTimestamp!)
|
let timestamp = UInt64(Int64(message.sentTimestamp!) + SnodeAPI.clockOffset)
|
||||||
|
let snodeMessage = SnodeMessage(recipient: message.recipient!, data: base64EncodedData, ttl: message.ttl, timestamp: timestamp)
|
||||||
SnodeAPI.sendMessage(snodeMessage).done(on: DispatchQueue.global(qos: .userInitiated)) { promises in
|
SnodeAPI.sendMessage(snodeMessage).done(on: DispatchQueue.global(qos: .userInitiated)) { promises in
|
||||||
var isSuccess = false
|
var isSuccess = false
|
||||||
let promiseCount = promises.count
|
let promiseCount = promises.count
|
||||||
|
|
|
@ -310,7 +310,7 @@ public enum OnionRequestAPI {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sends an onion request to `server`. Builds new paths as needed.
|
/// Sends an onion request to `server`. Builds new paths as needed.
|
||||||
public static func sendOnionRequest(_ request: NSURLRequest, to server: String, target: String = "/loki/v3/lsrpc", using x25519PublicKey: String, isJSONRequired: Bool = true) -> Promise<JSON> {
|
public static func sendOnionRequest(_ request: NSURLRequest, to server: String, target: String = "/loki/v3/lsrpc", using x25519PublicKey: String) -> Promise<JSON> {
|
||||||
var rawHeaders = request.allHTTPHeaderFields ?? [:]
|
var rawHeaders = request.allHTTPHeaderFields ?? [:]
|
||||||
rawHeaders.removeValue(forKey: "User-Agent")
|
rawHeaders.removeValue(forKey: "User-Agent")
|
||||||
var headers: JSON = rawHeaders.mapValues { value in
|
var headers: JSON = rawHeaders.mapValues { value in
|
||||||
|
@ -352,14 +352,14 @@ public enum OnionRequestAPI {
|
||||||
"headers" : headers
|
"headers" : headers
|
||||||
]
|
]
|
||||||
let destination = Destination.server(host: host, target: target, x25519PublicKey: x25519PublicKey, scheme: scheme, port: port)
|
let destination = Destination.server(host: host, target: target, x25519PublicKey: x25519PublicKey, scheme: scheme, port: port)
|
||||||
let promise = sendOnionRequest(with: payload, to: destination, isJSONRequired: isJSONRequired)
|
let promise = sendOnionRequest(with: payload, to: destination)
|
||||||
promise.catch2 { error in
|
promise.catch2 { error in
|
||||||
SNLog("Couldn't reach server: \(url) due to error: \(error).")
|
SNLog("Couldn't reach server: \(url) due to error: \(error).")
|
||||||
}
|
}
|
||||||
return promise
|
return promise
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func sendOnionRequest(with payload: JSON, to destination: Destination, isJSONRequired: Bool = true) -> Promise<JSON> {
|
public static func sendOnionRequest(with payload: JSON, to destination: Destination) -> Promise<JSON> {
|
||||||
let (promise, seal) = Promise<JSON>.pending()
|
let (promise, seal) = Promise<JSON>.pending()
|
||||||
var guardSnode: Snode?
|
var guardSnode: Snode?
|
||||||
Threading.workQueue.async { // Avoid race conditions on `guardSnodes` and `paths`
|
Threading.workQueue.async { // Avoid race conditions on `guardSnodes` and `paths`
|
||||||
|
@ -386,28 +386,28 @@ public enum OnionRequestAPI {
|
||||||
let ivAndCiphertext = Data(base64Encoded: base64EncodedIVAndCiphertext), ivAndCiphertext.count >= AESGCM.ivSize else { return seal.reject(HTTP.Error.invalidJSON) }
|
let ivAndCiphertext = Data(base64Encoded: base64EncodedIVAndCiphertext), ivAndCiphertext.count >= AESGCM.ivSize else { return seal.reject(HTTP.Error.invalidJSON) }
|
||||||
do {
|
do {
|
||||||
let data = try AESGCM.decrypt(ivAndCiphertext, with: destinationSymmetricKey)
|
let data = try AESGCM.decrypt(ivAndCiphertext, with: destinationSymmetricKey)
|
||||||
// The old open group server and file server implementations put the status code in the JSON under the "status"
|
|
||||||
// key, whereas the new implementations put it under the "status_code" key
|
|
||||||
guard let json = try JSONSerialization.jsonObject(with: data, options: [ .fragmentsAllowed ]) as? JSON,
|
guard let json = try JSONSerialization.jsonObject(with: data, options: [ .fragmentsAllowed ]) as? JSON,
|
||||||
let statusCode = json["status_code"] as? Int ?? json["status"] as? Int else { return seal.reject(HTTP.Error.invalidJSON) }
|
let statusCode = json["status_code"] as? Int ?? json["status"] as? Int else { return seal.reject(HTTP.Error.invalidJSON) }
|
||||||
if statusCode == 406 { // Clock out of sync
|
if statusCode == 406 { // Clock out of sync
|
||||||
SNLog("The user's clock is out of sync with the service node network.")
|
SNLog("The user's clock is out of sync with the service node network.")
|
||||||
seal.reject(SnodeAPI.Error.clockOutOfSync)
|
seal.reject(SnodeAPI.Error.clockOutOfSync)
|
||||||
} else if let bodyAsString = json["body"] as? String {
|
} else if let bodyAsString = json["body"] as? String {
|
||||||
// This clause is only used by the old open group and file server implementations. The new implementations will
|
guard let bodyAsData = bodyAsString.data(using: .utf8),
|
||||||
// always go to the next clause.
|
let body = try JSONSerialization.jsonObject(with: bodyAsData, options: [ .fragmentsAllowed ]) as? JSON else { return seal.reject(HTTP.Error.invalidJSON) }
|
||||||
let body: JSON
|
if let timestamp = body["t"] as? Int64 {
|
||||||
if !isJSONRequired {
|
let offset = timestamp - Int64(NSDate.millisecondTimestamp())
|
||||||
body = [ "result" : bodyAsString ]
|
if abs(offset) > 20 * 1000 { // If we're off by more than 20 seconds
|
||||||
} else {
|
SnodeAPI.clockOffset = offset
|
||||||
guard let bodyAsData = bodyAsString.data(using: .utf8),
|
}
|
||||||
let b = try JSONSerialization.jsonObject(with: bodyAsData, options: [ .fragmentsAllowed ]) as? JSON else { return seal.reject(HTTP.Error.invalidJSON) }
|
}
|
||||||
body = b
|
guard 200...299 ~= statusCode else {
|
||||||
|
return seal.reject(Error.httpRequestFailedAtDestination(statusCode: UInt(statusCode), json: body, destination: destination))
|
||||||
}
|
}
|
||||||
guard 200...299 ~= statusCode else { return seal.reject(Error.httpRequestFailedAtDestination(statusCode: UInt(statusCode), json: body, destination: destination)) }
|
|
||||||
seal.fulfill(body)
|
seal.fulfill(body)
|
||||||
} else {
|
} else {
|
||||||
guard 200...299 ~= statusCode else { return seal.reject(Error.httpRequestFailedAtDestination(statusCode: UInt(statusCode), json: json, destination: destination)) }
|
guard 200...299 ~= statusCode else {
|
||||||
|
return seal.reject(Error.httpRequestFailedAtDestination(statusCode: UInt(statusCode), json: json, destination: destination))
|
||||||
|
}
|
||||||
seal.fulfill(json)
|
seal.fulfill(json)
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
@ -13,6 +13,11 @@ public final class SnodeAPI : NSObject {
|
||||||
/// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions.
|
/// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions.
|
||||||
internal static var snodePool: Set<Snode> = []
|
internal static var snodePool: Set<Snode> = []
|
||||||
|
|
||||||
|
/// The offset between the user's clock and the Service Node's clock. Used in cases where the
|
||||||
|
/// user's clock is incorrect.
|
||||||
|
///
|
||||||
|
/// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions.
|
||||||
|
public static var clockOffset: Int64 = 0
|
||||||
/// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions.
|
/// - Note: Should only be accessed from `Threading.workQueue` to avoid race conditions.
|
||||||
public static var swarmCache: [String:Set<Snode>] = [:]
|
public static var swarmCache: [String:Set<Snode>] = [:]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue