From 85d35b52d62c0193267b191abd5c046584139c75 Mon Sep 17 00:00:00 2001 From: Michael Kirk Date: Wed, 5 Sep 2018 22:44:36 -0600 Subject: [PATCH] restore PreKey upload failure tracking --- .../src/Account/PreKeyRefreshOperation.swift | 40 ++++++++++++ .../src/Account/TSPreKeyManager.h | 11 +++- .../src/Account/TSPreKeyManager.m | 6 ++ .../src/Network/API/NetworkManager.swift | 46 ++++++++++++++ .../src/Network/ServiceSocket.swift | 61 ++++--------------- 5 files changed, 114 insertions(+), 50 deletions(-) create mode 100644 SignalServiceKit/src/Network/API/NetworkManager.swift diff --git a/SignalServiceKit/src/Account/PreKeyRefreshOperation.swift b/SignalServiceKit/src/Account/PreKeyRefreshOperation.swift index d4def95cb..09e67c99e 100644 --- a/SignalServiceKit/src/Account/PreKeyRefreshOperation.swift +++ b/SignalServiceKit/src/Account/PreKeyRefreshOperation.swift @@ -80,6 +80,7 @@ public class RotateSignedPreKeyOperation: OWSOperation { self.primaryStorage.storeSignedPreKey(signedPreKeyRecord.id, signedPreKeyRecord: signedPreKeyRecord) self.primaryStorage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) + TSPreKeyManager.clearPreKeyUpdateFailureCount() TSPreKeyManager.clearSignedPreKeyRecords() }.then { () -> Void in Logger.debug("done") @@ -88,6 +89,25 @@ public class RotateSignedPreKeyOperation: OWSOperation { self.reportError(error) }.retainUntilComplete() } + + override public func didFail(error: Error) { + switch error { + case let networkManagerError as NetworkManagerError: + guard !networkManagerError.isNetworkError else { + Logger.debug("don't report SPK rotation failure w/ network error") + return + } + + guard networkManagerError.statusCode >= 400 && networkManagerError.statusCode <= 599 else { + Logger.debug("don't report SPK rotation failure w/ non application error") + return + } + + TSPreKeyManager.incrementPreKeyUpdateFailureCount() + default: + Logger.debug("don't report SPK rotation failure w/ non NetworkManager error: \(error)") + } + } } @objc(SSKRefreshPreKeysOperation) @@ -136,6 +156,7 @@ public class RefreshPreKeysOperation: OWSOperation { self.primaryStorage.setCurrentSignedPrekeyId(signedPreKeyRecord.id) self.primaryStorage.storePreKeyRecords(preKeyRecords) + TSPreKeyManager.clearPreKeyUpdateFailureCount() TSPreKeyManager.clearSignedPreKeyRecords() } }.then { () -> Void in @@ -145,4 +166,23 @@ public class RefreshPreKeysOperation: OWSOperation { self.reportError(error) }.retainUntilComplete() } + + override public func didFail(error: Error) { + switch error { + case let networkManagerError as NetworkManagerError: + guard !networkManagerError.isNetworkError else { + Logger.debug("don't report SPK rotation failure w/ network error") + return + } + + guard networkManagerError.statusCode >= 400 && networkManagerError.statusCode <= 599 else { + Logger.debug("don't report SPK rotation failure w/ non application error") + return + } + + TSPreKeyManager.incrementPreKeyUpdateFailureCount() + default: + Logger.debug("don't report SPK rotation failure w/ non NetworkManager error: \(error)") + } + } } diff --git a/SignalServiceKit/src/Account/TSPreKeyManager.h b/SignalServiceKit/src/Account/TSPreKeyManager.h index 19964f430..ece1c7b65 100644 --- a/SignalServiceKit/src/Account/TSPreKeyManager.h +++ b/SignalServiceKit/src/Account/TSPreKeyManager.h @@ -19,8 +19,18 @@ typedef NS_ENUM(NSInteger, RefreshPreKeysMode) { @interface TSPreKeyManager : NSObject +#pragma mark - State Tracking + + (BOOL)isAppLockedDueToPreKeyUpdateFailures; ++ (void)incrementPreKeyUpdateFailureCount; + ++ (void)clearPreKeyUpdateFailureCount; + ++ (void)clearSignedPreKeyRecords; + +#pragma mark - Check/Request Initiation + + (void)rotateSignedPreKeyWithSuccess:(void (^)(void))successHandler failure:(void (^)(NSError *error))failureHandler; + (void)createPreKeysWithSuccess:(void (^)(void))successHandler failure:(void (^)(NSError *error))failureHandler; @@ -28,6 +38,5 @@ typedef NS_ENUM(NSInteger, RefreshPreKeysMode) { + (void)checkPreKeys; + (void)checkPreKeysIfNecessary; -+ (void)clearSignedPreKeyRecordsWithKeyId:(NSNumber *)keyId; @end diff --git a/SignalServiceKit/src/Account/TSPreKeyManager.m b/SignalServiceKit/src/Account/TSPreKeyManager.m index cb862d4ff..dd8dd099b 100644 --- a/SignalServiceKit/src/Account/TSPreKeyManager.m +++ b/SignalServiceKit/src/Account/TSPreKeyManager.m @@ -37,6 +37,8 @@ static const NSUInteger kMaxPrekeyUpdateFailureCount = 5; @implementation TSPreKeyManager +#pragma mark - State Tracking + + (BOOL)isAppLockedDueToPreKeyUpdateFailures { // Only disable message sending if we have failed more than N times @@ -53,6 +55,8 @@ static const NSUInteger kMaxPrekeyUpdateFailureCount = 5; // Record a prekey update failure. OWSPrimaryStorage *primaryStorage = [OWSPrimaryStorage sharedManager]; int failureCount = [primaryStorage incrementPrekeyUpdateFailureCount]; + OWSLogInfo(@"new failureCount: %d", failureCount); + if (failureCount == 1 || ![primaryStorage firstPrekeyUpdateFailureDate]) { // If this is the "first" failure, record the timestamp of that // failure. @@ -67,6 +71,8 @@ static const NSUInteger kMaxPrekeyUpdateFailureCount = 5; [primaryStorage clearPrekeyUpdateFailureCount]; } +#pragma mark - Check/Request Initiation + + (NSOperationQueue *)operationQueue { static dispatch_once_t onceToken; diff --git a/SignalServiceKit/src/Network/API/NetworkManager.swift b/SignalServiceKit/src/Network/API/NetworkManager.swift new file mode 100644 index 000000000..17a8acb1c --- /dev/null +++ b/SignalServiceKit/src/Network/API/NetworkManager.swift @@ -0,0 +1,46 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +import Foundation +import PromiseKit + +enum NetworkManagerError: Error { + /// Wraps TSNetworkManager failure callback params in a single throwable error + case taskError(task: URLSessionDataTask, underlyingError: Error) +} + +extension NetworkManagerError { + var isNetworkError: Bool { + switch self { + case .taskError(_, let underlyingError): + return IsNSErrorNetworkFailure(underlyingError) + } + } + + var statusCode: Int { + switch self { + case .taskError(let task, _): + return task.statusCode() + } + } +} + +extension TSNetworkManager { + func makePromise(request: TSRequest) -> Promise<(task: URLSessionDataTask, responseObject: Any?)> { + let (promise, fulfill, reject) = Promise<(task: URLSessionDataTask, responseObject: Any?)>.pending() + + self.makeRequest(request, + success: { task, responseObject in + fulfill((task: task, responseObject: responseObject)) + }, + failure: { task, error in + let nmError = NetworkManagerError.taskError(task: task, underlyingError: error) + let nsError: NSError = nmError as NSError + nsError.isRetryable = (error as NSError).isRetryable + reject(nsError) + }) + + return promise + } +} diff --git a/SignalServiceKit/src/Network/ServiceSocket.swift b/SignalServiceKit/src/Network/ServiceSocket.swift index a503d9ae0..f885ffb8e 100644 --- a/SignalServiceKit/src/Network/ServiceSocket.swift +++ b/SignalServiceKit/src/Network/ServiceSocket.swift @@ -24,67 +24,30 @@ class ServiceRestSocket: ServiceSocket { func getAvailablePreKeys() -> Promise { Logger.debug("") - let (promise, fulfill, reject) = Promise.pending() - let request = OWSRequestFactory.availablePreKeysCountRequest() - networkManager.makeRequest(request, - success: { (_, responseObject) in - Logger.debug("got response") - guard let params = ParamParser(responseObject: responseObject) else { - reject(self.unexpectedServerResponseError()) - return - } + return networkManager.makePromise(request: request).then { (_, responseObject) -> Int in + Logger.debug("got response") + guard let params = ParamParser(responseObject: responseObject) else { + throw self.unexpectedServerResponseError() + } - let count: Int - do { - count = try params.required(key: "count") - } catch { - reject(error) - return - } + let count: Int = try! params.required(key: "count") - fulfill(count) - }, - failure: { (_, error) in - Logger.debug("error: \(error)") - reject(error) - }) - return promise + return count + } } func registerPreKeys(identityKey: IdentityKey, signedPreKeyRecord: SignedPreKeyRecord, preKeyRecords: [PreKeyRecord]) -> Promise { Logger.debug("") - let (promise, fulfill, reject) = Promise.pending() let request = OWSRequestFactory.registerPrekeysRequest(withPrekeyArray: preKeyRecords, identityKey: identityKey, signedPreKey: signedPreKeyRecord) - - networkManager.makeRequest(request, - success: { (_, _) in - Logger.debug("success") - fulfill(()) - - }, - failure: { (_, error) in - Logger.debug("error: \(error)") - reject(error) - }) - return promise + return networkManager.makePromise(request: request).asVoid() } public func setCurrentSignedPreKey(_ signedPreKey: SignedPreKeyRecord) -> Promise { - let (promise, fulfill, reject) = Promise.pending() + Logger.debug("") + let request = OWSRequestFactory.registerSignedPrekeyRequest(with: signedPreKey) - - networkManager.makeRequest(request, - success: { (_, _) in - Logger.debug("success") - fulfill(()) - - }, - failure: { (_, error) in - Logger.debug("error: \(error)") - reject(error) - }) - return promise + return networkManager.makePromise(request: request).asVoid() } }