Handle clock out of sync issue
Also generally improve error handling
This commit is contained in:
parent
afed01e4c0
commit
a586c9db2d
|
@ -1,7 +1,5 @@
|
|||
import PromiseKit
|
||||
|
||||
extension String : Error { }
|
||||
|
||||
public extension LokiAPI {
|
||||
|
||||
fileprivate static var failureCount: [LokiAPITarget:UInt] = [:]
|
||||
|
@ -67,7 +65,7 @@ public extension LokiAPI {
|
|||
print("[Loki] Invoking get_n_service_nodes on \(target).")
|
||||
return TSNetworkManager.shared().perform(request, withCompletionQueue: DispatchQueue.global()).map { intermediate in
|
||||
let rawResponse = intermediate.responseObject
|
||||
guard let json = rawResponse as? JSON, let intermediate = json["result"] as? JSON, let rawTargets = intermediate["service_node_states"] as? [JSON] else { throw "Failed to update random snode pool from: \(rawResponse)." }
|
||||
guard let json = rawResponse as? JSON, let intermediate = json["result"] as? JSON, let rawTargets = intermediate["service_node_states"] as? [JSON] else { throw LokiAPIError.randomSnodePoolUpdatingFailed }
|
||||
randomSnodePool = try Set(rawTargets.flatMap { rawTarget in
|
||||
guard let address = rawTarget["public_ip"] as? String, let port = rawTarget["storage_port"] as? Int, let idKey = rawTarget["pubkey_ed25519"] as? String, let encryptionKey = rawTarget["pubkey_x25519"] as? String, address != "0.0.0.0" else {
|
||||
print("[Loki] Failed to parse target from: \(rawTarget).")
|
||||
|
@ -138,7 +136,8 @@ internal extension Promise {
|
|||
LokiAPI.failureCount[target] = 0
|
||||
}
|
||||
case 406:
|
||||
break // TODO: Handle clock out of sync
|
||||
print("[Loki] The user's clock is out of sync with the service node network.")
|
||||
throw LokiAPI.LokiAPIError.clockOutOfSync
|
||||
case 421:
|
||||
// The snode isn't associated with the given public key anymore
|
||||
print("[Loki] Invalidating swarm for: \(hexEncodedPublicKey).")
|
||||
|
|
|
@ -26,17 +26,12 @@ public final class LokiAPI : NSObject {
|
|||
// MARK: Types
|
||||
public typealias RawResponse = Any
|
||||
|
||||
public enum Error : LocalizedError {
|
||||
/// Only applicable to snode targets as proof of work isn't required for P2P messaging.
|
||||
case proofOfWorkCalculationFailed
|
||||
case messageConversionFailed
|
||||
@objc public class LokiAPIError : NSError { // Not called `Error` for Obj-C interoperablity
|
||||
|
||||
public var errorDescription: String? {
|
||||
switch self {
|
||||
case .proofOfWorkCalculationFailed: return NSLocalizedString("Failed to calculate proof of work.", comment: "")
|
||||
case .messageConversionFailed: return "Failed to convert Signal message to Loki message."
|
||||
}
|
||||
}
|
||||
@objc public static let proofOfWorkCalculationFailed = LokiAPIError(domain: "LokiAPIErrorDomain", code: 1, userInfo: [ NSLocalizedDescriptionKey : "Failed to calculate proof of work." ])
|
||||
@objc public static let messageConversionFailed = LokiAPIError(domain: "LokiAPIErrorDomain", code: 2, userInfo: [ NSLocalizedDescriptionKey : "Failed to construct message." ])
|
||||
@objc public static let clockOutOfSync = LokiAPIError(domain: "LokiAPIErrorDomain", code: 3, userInfo: [ NSLocalizedDescriptionKey : "Your clock is out of sync with the service node network." ])
|
||||
@objc public static let randomSnodePoolUpdatingFailed = LokiAPIError(domain: "LokiAPIErrorDomain", code: 4, userInfo: [ NSLocalizedDescriptionKey : "Failed to update random service node pool." ])
|
||||
}
|
||||
|
||||
@objc(LKDestination)
|
||||
|
@ -136,7 +131,7 @@ public final class LokiAPI : NSObject {
|
|||
getDestinations()
|
||||
lastDeviceLinkUpdate[hexEncodedPublicKey] = Date()
|
||||
}.catch(on: DispatchQueue.global()) { error in
|
||||
if (error as? LokiDotNetAPI.Error) == LokiDotNetAPI.Error.parsingFailed {
|
||||
if (error as? LokiDotNetAPI.LokiDotNetAPIError) == LokiDotNetAPI.LokiDotNetAPIError.parsingFailed {
|
||||
// Don't immediately re-fetch in case of failure due to a parsing error
|
||||
lastDeviceLinkUpdate[hexEncodedPublicKey] = Date()
|
||||
getDestinations()
|
||||
|
@ -152,7 +147,7 @@ public final class LokiAPI : NSObject {
|
|||
}
|
||||
|
||||
public static func sendSignalMessage(_ signalMessage: SignalMessage, onP2PSuccess: @escaping () -> Void) -> Promise<Set<RawResponsePromise>> {
|
||||
guard let lokiMessage = LokiMessage.from(signalMessage: signalMessage) else { return Promise(error: Error.messageConversionFailed) }
|
||||
guard let lokiMessage = LokiMessage.from(signalMessage: signalMessage) else { return Promise(error: LokiAPIError.messageConversionFailed) }
|
||||
let notificationCenter = NotificationCenter.default
|
||||
let destination = lokiMessage.destination
|
||||
func sendLokiMessage(_ lokiMessage: LokiMessage, to target: LokiAPITarget) -> RawResponsePromise {
|
||||
|
|
|
@ -12,14 +12,14 @@ public class LokiDotNetAPI : NSObject {
|
|||
private static let attachmentType = "network.loki"
|
||||
|
||||
// MARK: Error
|
||||
@objc public class Error : NSError {
|
||||
@objc public class LokiDotNetAPIError : NSError { // Not called `Error` for Obj-C interoperablity
|
||||
|
||||
@objc public static let generic = Error(domain: "com.loki-project.loki-messenger", code: 1, userInfo: [ NSLocalizedDescriptionKey : "An error occurred." ])
|
||||
@objc public static let parsingFailed = Error(domain: "com.loki-project.loki-messenger", code: 2, userInfo: [ NSLocalizedDescriptionKey : "Invalid file server response." ])
|
||||
@objc public static let signingFailed = Error(domain: "com.loki-project.loki-messenger", code: 3, userInfo: [ NSLocalizedDescriptionKey : "Couldn't sign message." ])
|
||||
@objc public static let encryptionFailed = Error(domain: "com.loki-project.loki-messenger", code: 4, userInfo: [ NSLocalizedDescriptionKey : "Couldn't encrypt file." ])
|
||||
@objc public static let decryptionFailed = Error(domain: "com.loki-project.loki-messenger", code: 5, userInfo: [ NSLocalizedDescriptionKey : "Couldn't decrypt file." ])
|
||||
@objc public static let maxFileSizeExceeded = Error(domain: "com.loki-project.loki-messenger", code: 6, userInfo: [ NSLocalizedDescriptionKey : "Maximum file size exceeded." ])
|
||||
@objc public static let generic = LokiDotNetAPIError(domain: "LokiDotNetAPIErrorDomain", code: 1, userInfo: [ NSLocalizedDescriptionKey : "An error occurred." ])
|
||||
@objc public static let parsingFailed = LokiDotNetAPIError(domain: "LokiDotNetAPIErrorDomain", code: 2, userInfo: [ NSLocalizedDescriptionKey : "Invalid file server response." ])
|
||||
@objc public static let signingFailed = LokiDotNetAPIError(domain: "LokiDotNetAPIErrorDomain", code: 3, userInfo: [ NSLocalizedDescriptionKey : "Couldn't sign message." ])
|
||||
@objc public static let encryptionFailed = LokiDotNetAPIError(domain: "LokiDotNetAPIErrorDomain", code: 4, userInfo: [ NSLocalizedDescriptionKey : "Couldn't encrypt file." ])
|
||||
@objc public static let decryptionFailed = LokiDotNetAPIError(domain: "LokiDotNetAPIErrorDomain", code: 5, userInfo: [ NSLocalizedDescriptionKey : "Couldn't decrypt file." ])
|
||||
@objc public static let maxFileSizeExceeded = LokiDotNetAPIError(domain: "LokiDotNetAPIErrorDomain", code: 6, userInfo: [ NSLocalizedDescriptionKey : "Maximum file size exceeded." ])
|
||||
}
|
||||
|
||||
// MARK: Database
|
||||
|
@ -52,7 +52,7 @@ public class LokiDotNetAPI : NSObject {
|
|||
let data: Data
|
||||
guard let unencryptedAttachmentData = try? attachment.readDataFromFile() else {
|
||||
print("[Loki] Couldn't read attachment from disk.")
|
||||
return seal.reject(Error.generic)
|
||||
return seal.reject(LokiDotNetAPIError.generic)
|
||||
}
|
||||
// Encrypt the attachment if needed
|
||||
if isEncryptionRequired {
|
||||
|
@ -60,7 +60,7 @@ public class LokiDotNetAPI : NSObject {
|
|||
var digest = NSData()
|
||||
guard let encryptedAttachmentData = Cryptography.encryptAttachmentData(unencryptedAttachmentData, outKey: &encryptionKey, outDigest: &digest) else {
|
||||
print("[Loki] Couldn't encrypt attachment.")
|
||||
return seal.reject(Error.encryptionFailed)
|
||||
return seal.reject(LokiDotNetAPIError.encryptionFailed)
|
||||
}
|
||||
attachment.encryptionKey = encryptionKey as Data
|
||||
attachment.digest = digest as Data
|
||||
|
@ -71,7 +71,7 @@ public class LokiDotNetAPI : NSObject {
|
|||
// Check the file size if needed
|
||||
let isLokiFileServer = (server == LokiFileServerAPI.server)
|
||||
if isLokiFileServer && data.count > LokiFileServerAPI.maxFileSize {
|
||||
return seal.reject(Error.maxFileSizeExceeded)
|
||||
return seal.reject(LokiDotNetAPIError.maxFileSizeExceeded)
|
||||
}
|
||||
// Create the request
|
||||
let url = "\(server)/files"
|
||||
|
@ -90,7 +90,7 @@ public class LokiDotNetAPI : NSObject {
|
|||
// Parse the server ID & download URL
|
||||
guard let json = response as? JSON, let data = json["data"] as? JSON, let serverID = data["id"] as? UInt64, let downloadURL = data["url"] as? String else {
|
||||
print("[Loki] Couldn't parse attachment from: \(response).")
|
||||
return seal.reject(Error.parsingFailed)
|
||||
return seal.reject(LokiDotNetAPIError.parsingFailed)
|
||||
}
|
||||
// Update the attachment
|
||||
attachment.serverId = serverID
|
||||
|
@ -125,7 +125,7 @@ public class LokiDotNetAPI : NSObject {
|
|||
let isSuccessful = (200...299) ~= statusCode
|
||||
guard isSuccessful else {
|
||||
print("[Loki] Couldn't upload attachment.")
|
||||
return seal.reject(Error.generic)
|
||||
return seal.reject(LokiDotNetAPIError.generic)
|
||||
}
|
||||
parseResponse(responseObject)
|
||||
})
|
||||
|
@ -166,7 +166,7 @@ public class LokiDotNetAPI : NSObject {
|
|||
return LokiFileServerProxy(for: server).perform(request, withCompletionQueue: DispatchQueue.global()).map { rawResponse in
|
||||
guard let json = rawResponse as? JSON, let base64EncodedChallenge = json["cipherText64"] as? String, let base64EncodedServerPublicKey = json["serverPubKey64"] as? String,
|
||||
let challenge = Data(base64Encoded: base64EncodedChallenge), var serverPublicKey = Data(base64Encoded: base64EncodedServerPublicKey) else {
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
// Discard the "05" prefix if needed
|
||||
if serverPublicKey.count == 33 {
|
||||
|
@ -176,7 +176,7 @@ public class LokiDotNetAPI : NSObject {
|
|||
// The challenge is prefixed by the 16 bit IV
|
||||
guard let tokenAsData = try? DiffieHellman.decrypt(challenge, publicKey: serverPublicKey, privateKey: userKeyPair.privateKey),
|
||||
let token = String(bytes: tokenAsData, encoding: .utf8) else {
|
||||
throw Error.decryptionFailed
|
||||
throw LokiDotNetAPIError.decryptionFailed
|
||||
}
|
||||
return token
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public final class LokiFileServerAPI : LokiDotNetAPI {
|
|||
return TSNetworkManager.shared().perform(request, withCompletionQueue: DispatchQueue.global()).map { $0.responseObject }.map { rawResponse -> Set<DeviceLink> in
|
||||
guard let json = rawResponse as? JSON, let data = json["data"] as? [JSON] else {
|
||||
print("[Loki] Couldn't parse device links for users: \(hexEncodedPublicKeys) from: \(rawResponse).")
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
return Set(data.flatMap { data -> [DeviceLink] in
|
||||
guard let annotations = data["annotations"] as? [JSON], !annotations.isEmpty else { return [] }
|
||||
|
@ -159,11 +159,11 @@ public final class LokiFileServerAPI : LokiDotNetAPI {
|
|||
let isSuccessful = (200...299) ~= statusCode
|
||||
guard isSuccessful else {
|
||||
print("[Loki] Couldn't upload profile picture.")
|
||||
return seal.reject(Error.generic)
|
||||
return seal.reject(LokiDotNetAPIError.generic)
|
||||
}
|
||||
guard let json = responseObject as? JSON, let data = json["data"] as? JSON, let profilePicture = data["avatar_image"] as? JSON, let downloadURL = profilePicture["url"] as? String else {
|
||||
print("[Loki] Couldn't parse profile picture from: \(responseObject).")
|
||||
return seal.reject(Error.parsingFailed)
|
||||
return seal.reject(LokiDotNetAPIError.parsingFailed)
|
||||
}
|
||||
return seal.fulfill(downloadURL)
|
||||
})
|
||||
|
|
|
@ -58,7 +58,7 @@ public struct LokiMessage {
|
|||
result.nonce = nonce
|
||||
seal.fulfill(result)
|
||||
} else {
|
||||
seal.reject(LokiAPI.Error.proofOfWorkCalculationFailed)
|
||||
seal.reject(LokiAPI.LokiAPIError.proofOfWorkCalculationFailed)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|||
return LokiFileServerProxy(for: server).perform(request, withCompletionQueue: DispatchQueue.global()).map { rawResponse in
|
||||
guard let json = rawResponse as? JSON, let rawMessages = json["data"] as? [JSON] else {
|
||||
print("[Loki] Couldn't parse messages for public chat channel with ID: \(channel) on server: \(server) from: \(rawResponse).")
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
return rawMessages.flatMap { message in
|
||||
let isDeleted = (message["is_deleted"] as? Int == 1)
|
||||
|
@ -155,7 +155,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|||
}
|
||||
|
||||
public static func sendMessage(_ message: LokiPublicChatMessage, to channel: UInt64, on server: String) -> Promise<LokiPublicChatMessage> {
|
||||
guard let signedMessage = message.sign(with: userKeyPair.privateKey) else { return Promise(error: Error.signingFailed) }
|
||||
guard let signedMessage = message.sign(with: userKeyPair.privateKey) else { return Promise(error: LokiDotNetAPIError.signingFailed) }
|
||||
return getAuthToken(for: server).then(on: DispatchQueue.global()) { token -> Promise<LokiPublicChatMessage> in
|
||||
print("[Loki] Sending message to public chat channel with ID: \(channel) on server: \(server).")
|
||||
let url = URL(string: "\(server)/channels/\(channel)/messages")!
|
||||
|
@ -170,7 +170,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|||
guard let json = rawResponse as? JSON, let messageAsJSON = json["data"] as? JSON, let serverID = messageAsJSON["id"] as? UInt64, let body = messageAsJSON["text"] as? String,
|
||||
let dateAsString = messageAsJSON["created_at"] as? String, let date = dateFormatter.date(from: dateAsString) else {
|
||||
print("[Loki] Couldn't parse message for public chat channel with ID: \(channel) on server: \(server) from: \(rawResponse).")
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
let timestamp = UInt64(date.timeIntervalSince1970) * 1000
|
||||
return LokiPublicChatMessage(serverID: serverID, hexEncodedPublicKey: userHexEncodedPublicKey, displayName: displayName, profilePicture: signedMessage.profilePicture, body: body, type: publicChatMessageType, timestamp: timestamp, quote: signedMessage.quote, attachments: signedMessage.attachments, signature: signedMessage.signature)
|
||||
|
@ -197,7 +197,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|||
return LokiFileServerProxy(for: server).perform(request, withCompletionQueue: DispatchQueue.global()).map { rawResponse in
|
||||
guard let json = rawResponse as? JSON, let deletions = json["data"] as? [JSON] else {
|
||||
print("[Loki] Couldn't parse deleted messages for public chat channel with ID: \(channel) on server: \(server) from: \(rawResponse).")
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
return deletions.flatMap { deletion in
|
||||
guard let serverID = deletion["id"] as? UInt64, let messageServerID = deletion["message_id"] as? UInt64 else {
|
||||
|
@ -231,7 +231,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|||
return LokiFileServerProxy(for: server).perform(request, withCompletionQueue: DispatchQueue.global()).map { rawResponse in
|
||||
guard let json = rawResponse as? JSON, let moderators = json["moderators"] as? [String] else {
|
||||
print("[Loki] Couldn't parse moderators for public chat channel with ID: \(channel) on server: \(server) from: \(rawResponse).")
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
let moderatorAsSet = Set(moderators);
|
||||
if self.moderators.keys.contains(server) {
|
||||
|
@ -274,7 +274,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|||
return LokiFileServerProxy(for: server).perform(request, withCompletionQueue: DispatchQueue.global()).map { rawResponse in
|
||||
guard let json = rawResponse as? JSON, let users = json["data"] as? [JSON] else {
|
||||
print("[Loki] Couldn't parse user count for public chat channel with ID: \(channel) on server: \(server) from: \(rawResponse).")
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
let userCount = users.count
|
||||
let storage = OWSPrimaryStorage.shared()
|
||||
|
@ -298,7 +298,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|||
return LokiFileServerProxy(for: server).perform(request, withCompletionQueue: DispatchQueue.global()).map { rawResponse in
|
||||
guard let json = rawResponse as? JSON, let data = json["data"] as? [JSON] else {
|
||||
print("[Loki] Couldn't parse display names for users: \(hexEncodedPublicKeys) from: \(rawResponse).")
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
storage.dbReadWriteConnection.readWrite { transaction in
|
||||
data.forEach { data in
|
||||
|
@ -361,7 +361,7 @@ public final class LokiPublicChatAPI : LokiDotNetAPI {
|
|||
let info = annotation["value"] as? JSON,
|
||||
let displayName = info["name"] as? String else {
|
||||
print("[Loki] Couldn't parse info for public chat channel with ID: \(channel) on server: \(server) from: \(rawResponse).")
|
||||
throw Error.parsingFailed
|
||||
throw LokiDotNetAPIError.parsingFailed
|
||||
}
|
||||
return LokiPublicChatInfo(displayName: displayName)
|
||||
}
|
||||
|
|
|
@ -196,7 +196,7 @@ public final class LokiPublicChatPoller : NSObject {
|
|||
LokiAPI.lastDeviceLinkUpdate[$0] = Date()
|
||||
}
|
||||
}.catch(on: DispatchQueue.global()) { error in
|
||||
if (error as? LokiDotNetAPI.Error) == LokiDotNetAPI.Error.parsingFailed {
|
||||
if (error as? LokiDotNetAPI.LokiDotNetAPIError) == LokiDotNetAPI.LokiDotNetAPIError.parsingFailed {
|
||||
// Don't immediately re-fetch in case of failure due to a parsing error
|
||||
hexEncodedPublicKeysToUpdate.forEach {
|
||||
LokiAPI.lastDeviceLinkUpdate[$0] = Date()
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
import CryptoSwift
|
||||
import Curve25519Kit
|
||||
|
||||
public enum DiffieHellman {
|
||||
@objc public final class DiffieHellman : NSObject {
|
||||
|
||||
@objc public class DiffieHellmanError : NSError { // Not called `Error` for Obj-C interoperablity
|
||||
|
||||
@objc public static let decryptionFailed = DiffieHellmanError(domain: "DiffieHellmanErrorDomain", code: 1, userInfo: [ NSLocalizedDescriptionKey : "Couldn't decrypt data." ])
|
||||
}
|
||||
|
||||
public static let ivLength: Int32 = 16;
|
||||
|
||||
private override init() { }
|
||||
|
||||
public static func encrypt(_ plainTextData: Data, using symmetricKey: Data) throws -> Data {
|
||||
let iv = Randomness.generateRandomBytes(ivLength)!
|
||||
let ivBytes = [UInt8](iv)
|
||||
|
@ -24,7 +31,7 @@ public enum DiffieHellman {
|
|||
|
||||
public static func decrypt(_ encryptedData: Data, using symmetricKey: Data) throws -> Data {
|
||||
let symmetricKeyBytes = [UInt8](symmetricKey)
|
||||
guard encryptedData.count >= ivLength else { throw "Couldn't decrypt data." }
|
||||
guard encryptedData.count >= ivLength else { throw DiffieHellmanError.decryptionFailed }
|
||||
let ivBytes = [UInt8](encryptedData[..<ivLength])
|
||||
let cipherBytes = [UInt8](encryptedData[ivLength...])
|
||||
let blockMode = CBC(iv: ivBytes)
|
||||
|
|
|
@ -1229,7 +1229,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
}
|
||||
|
||||
void (^failedMessageSend)(NSError *error) = ^(NSError *error) {
|
||||
// Handle the error
|
||||
NSUInteger statusCode = 0;
|
||||
NSData *_Nullable responseData = nil;
|
||||
if ([error.domain isEqualToString:TSNetworkManagerErrorDomain]) {
|
||||
|
@ -1240,9 +1239,6 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
} else {
|
||||
OWSFailDebug(@"Missing underlying error: %@.", error);
|
||||
}
|
||||
} else {
|
||||
// TODO: Re-enable?
|
||||
// OWSFailDebug(@"Unexpected error: %@.", error);
|
||||
}
|
||||
[self messageSendDidFail:messageSend deviceMessages:deviceMessages statusCode:statusCode error:error responseData:responseData];
|
||||
};
|
||||
|
@ -1486,7 +1482,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
|
|||
|
||||
switch (statusCode) {
|
||||
case 0: { // Loki
|
||||
NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError();
|
||||
NSError *error;
|
||||
if ([responseError isKindOfClass:LokiAPIError.class] || [responseError isKindOfClass:LokiDotNetAPIError.class] || [responseError isKindOfClass:DiffieHellmanError.class]) {
|
||||
error = responseError;
|
||||
} else {
|
||||
error = OWSErrorMakeFailedToSendOutgoingMessageError();
|
||||
}
|
||||
[error setIsRetryable:NO];
|
||||
return messageSend.failure(error);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue