|
|
|
@ -7,6 +7,7 @@
|
|
|
|
|
#import "TSNetworkManager.h"
|
|
|
|
|
#import "TSRegisterSignedPrekeyRequest.h"
|
|
|
|
|
#import "TSStorageHeaders.h"
|
|
|
|
|
#import "TSStorageManager+SignedPreKeyStore.h"
|
|
|
|
|
|
|
|
|
|
// Time before deletion of signed prekeys (measured in seconds)
|
|
|
|
|
//
|
|
|
|
@ -16,7 +17,7 @@ static const CGFloat kSignedPreKeysDeletionTime = 14 * 24 * 60 * 60;
|
|
|
|
|
// Time before rotation of signed prekeys (measured in seconds)
|
|
|
|
|
//
|
|
|
|
|
// Currently we rotate signed prekeys every 2 days (48 hours).
|
|
|
|
|
static const CGFloat kSignedPreKeysRotationTime = 2 * 24 * 60 * 60;
|
|
|
|
|
static const CGFloat kSignedPreKeyRotationTime = 2 * 24 * 60 * 60;
|
|
|
|
|
|
|
|
|
|
// How often we check prekey state on app activation.
|
|
|
|
|
//
|
|
|
|
@ -30,8 +31,50 @@ static const NSUInteger kEphemeralPreKeysMinimumCount = 35;
|
|
|
|
|
// This global should only be accessed on prekeyQueue.
|
|
|
|
|
static NSDate *lastPreKeyCheckTimestamp = nil;
|
|
|
|
|
|
|
|
|
|
// Maximum number of failures while updating signed prekeys
|
|
|
|
|
// before the message sending is disabled.
|
|
|
|
|
static const NSUInteger kMaxPrekeyUpdateFailureCount = 5;
|
|
|
|
|
|
|
|
|
|
// Maximum amount of time that can elapse without updating signed prekeys
|
|
|
|
|
// before the message sending is disabled.
|
|
|
|
|
//
|
|
|
|
|
// Current value is 10 days (240 hours).
|
|
|
|
|
static const CGFloat kSignedPreKeyUpdateFailureMaxFailureDuration = 10 * 24 * 60 * 60;
|
|
|
|
|
|
|
|
|
|
#pragma mark -
|
|
|
|
|
|
|
|
|
|
@implementation TSPreKeyManager
|
|
|
|
|
|
|
|
|
|
+ (BOOL)isAppLockedDueToPreKeyUpdateFailures
|
|
|
|
|
{
|
|
|
|
|
// Only disable message sending if we have failed more than N times
|
|
|
|
|
// over a period of at least M days.
|
|
|
|
|
TSStorageManager *storageManager = [TSStorageManager sharedManager];
|
|
|
|
|
return ([storageManager prekeyUpdateFailureCount] >= kMaxPrekeyUpdateFailureCount &&
|
|
|
|
|
[storageManager firstPrekeyUpdateFailureDate] != nil
|
|
|
|
|
&& fabs([[storageManager firstPrekeyUpdateFailureDate] timeIntervalSinceNow])
|
|
|
|
|
>= kSignedPreKeyUpdateFailureMaxFailureDuration);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void)incrementPreKeyUpdateFailureCount
|
|
|
|
|
{
|
|
|
|
|
// Record a prekey update failure.
|
|
|
|
|
TSStorageManager *storageManager = [TSStorageManager sharedManager];
|
|
|
|
|
int failureCount = [storageManager incrementPrekeyUpdateFailureCount];
|
|
|
|
|
if (failureCount == 1 || ![storageManager firstPrekeyUpdateFailureDate]) {
|
|
|
|
|
// If this is the "first" failure, record the timestamp of that
|
|
|
|
|
// failure.
|
|
|
|
|
[storageManager setFirstPrekeyUpdateFailureDate:[NSDate new]];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+ (void)clearPreKeyUpdateFailureCount
|
|
|
|
|
{
|
|
|
|
|
TSStorageManager *storageManager = [TSStorageManager sharedManager];
|
|
|
|
|
[storageManager clearFirstPrekeyUpdateFailureDate];
|
|
|
|
|
[storageManager clearPrekeyUpdateFailureCount];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We should never dispatch sync to this queue.
|
|
|
|
|
+ (dispatch_queue_t)prekeyQueue
|
|
|
|
|
{
|
|
|
|
@ -99,17 +142,32 @@ static NSDate *lastPreKeyCheckTimestamp = nil;
|
|
|
|
|
|
|
|
|
|
[[TSNetworkManager sharedManager] makeRequest:request
|
|
|
|
|
success:^(NSURLSessionDataTask *task, id responseObject) {
|
|
|
|
|
DDLogInfo(@"%@ Successfully registered %@.", self.tag, description);
|
|
|
|
|
OWSAnalyticsInfo(@"Prekey update success: %@", description);
|
|
|
|
|
|
|
|
|
|
if (modeCopy == RefreshPreKeysMode_SignedAndOneTime) {
|
|
|
|
|
[storageManager storePreKeyRecords:preKeys];
|
|
|
|
|
}
|
|
|
|
|
[storageManager storeSignedPreKey:signedPreKey.Id signedPreKeyRecord:signedPreKey];
|
|
|
|
|
|
|
|
|
|
successHandler();
|
|
|
|
|
|
|
|
|
|
[TSPreKeyManager clearPreKeyUpdateFailureCount];
|
|
|
|
|
}
|
|
|
|
|
failure:^(NSURLSessionDataTask *task, NSError *error) {
|
|
|
|
|
DDLogError(@"%@ Failed to register %@.", self.tag, description);
|
|
|
|
|
OWSAnalyticsError(@"Prekey update failed (%@): %@", description, error);
|
|
|
|
|
|
|
|
|
|
failureHandler(error);
|
|
|
|
|
|
|
|
|
|
NSInteger statusCode = 0;
|
|
|
|
|
if ([task.response isKindOfClass:[NSHTTPURLResponse class]]) {
|
|
|
|
|
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)task.response;
|
|
|
|
|
statusCode = httpResponse.statusCode;
|
|
|
|
|
}
|
|
|
|
|
if (statusCode >= 400 && statusCode <= 599) {
|
|
|
|
|
// Only treat 4xx and 5xx errors from the service as failures.
|
|
|
|
|
// Ignore network failures, for example.
|
|
|
|
|
[TSPreKeyManager incrementPreKeyUpdateFailureCount];
|
|
|
|
|
}
|
|
|
|
|
}];
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
@ -137,7 +195,7 @@ static NSDate *lastPreKeyCheckTimestamp = nil;
|
|
|
|
|
[self clearSignedPreKeyRecords];
|
|
|
|
|
}
|
|
|
|
|
failure:^(NSError *error) {
|
|
|
|
|
DDLogWarn(@"%@ Failed to update prekeys with the server", self.tag);
|
|
|
|
|
DDLogWarn(@"%@ Failed to update prekeys with the server: %@", self.tag, error);
|
|
|
|
|
}];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -158,7 +216,7 @@ static NSDate *lastPreKeyCheckTimestamp = nil;
|
|
|
|
|
OWSAssert(currentRecord);
|
|
|
|
|
|
|
|
|
|
BOOL shouldUpdateSignedPrekey
|
|
|
|
|
= fabs([currentRecord.generatedAt timeIntervalSinceNow]) >= kSignedPreKeysRotationTime;
|
|
|
|
|
= fabs([currentRecord.generatedAt timeIntervalSinceNow]) >= kSignedPreKeyRotationTime;
|
|
|
|
|
if (shouldUpdateSignedPrekey) {
|
|
|
|
|
DDLogInfo(@"%@ Updating signed prekey due to rotation period.", self.tag);
|
|
|
|
|
updatePreKeys(RefreshPreKeysMode_SignedOnly);
|
|
|
|
@ -236,9 +294,8 @@ static NSDate *lastPreKeyCheckTimestamp = nil;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DDLogInfo(@"%@ Deleting old signed prekey: %@",
|
|
|
|
|
self.tag,
|
|
|
|
|
[dateFormatter stringFromDate:deletionCandidate.generatedAt]);
|
|
|
|
|
OWSAnalyticsInfo(
|
|
|
|
|
@"Deleting old signed prekey: %@", [dateFormatter stringFromDate:deletionCandidate.generatedAt]);
|
|
|
|
|
[storageManager removeSignedPreKey:deletionCandidate.Id];
|
|
|
|
|
deletedCount++;
|
|
|
|
|
}
|
|
|
|
|