From ad0fc7944e7a2aaf197cbb84a249d8caee639e3e Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 6 May 2019 12:38:36 +1000 Subject: [PATCH 1/4] Made ProofOfWork work in objective c. Added proof of work calculation when sending message. --- SignalServiceKit/src/Loki/ProofOfWork.swift | 46 ++--- .../src/Messages/OWSMessageSender.m | 163 ++++++++++++------ .../Network/API/Requests/OWSRequestFactory.h | 5 + .../Network/API/Requests/OWSRequestFactory.m | 52 ++++++ 4 files changed, 182 insertions(+), 84 deletions(-) diff --git a/SignalServiceKit/src/Loki/ProofOfWork.swift b/SignalServiceKit/src/Loki/ProofOfWork.swift index a1a89291b..245de1daf 100644 --- a/SignalServiceKit/src/Loki/ProofOfWork.swift +++ b/SignalServiceKit/src/Loki/ProofOfWork.swift @@ -43,7 +43,8 @@ private extension MutableCollection where Element == UInt8, Index == Int { * This was copied from the desktop messenger. * Ref: libloki/proof-of-work.js */ -public enum ProofOfWork { +@objc public class ProofOfWork: NSObject { + private override init() {} // If this changes then we also have to use something other than UInt64 to support the new length private static let nonceLength = 8 @@ -55,36 +56,19 @@ public enum ProofOfWork { } }() - public struct Configuration { - var pubKey: String - var data: String - var timestamp: Date - var ttl: Int - - var payload: [UInt8] { - let timestampString = String(Int(timestamp.timeIntervalSince1970)) - let ttlString = String(ttl) - let payloadString = timestampString + ttlString + pubKey + data - return payloadString.bytes - } - - public init(pubKey: String, data: String, timestamp: Date, ttl: Int) { - self.pubKey = pubKey - self.data = data - self.timestamp = timestamp - self.ttl = ttl - } - } - /// Calculate a proof of work with the given configuration /// /// Ref: https://bitmessage.org/wiki/Proof_of_work /// - /// - Parameter config: The configuration + /// - Parameters: + /// - data: The message data + /// - pubKey: The message recipient + /// - timestamp: The timestamp + /// - ttl: The message time to live /// - Returns: A nonce string or nil if it failed - public static func calculate(with config: Configuration) -> String? { - let payload = config.payload - let target = calcTarget(ttl: config.ttl, payloadLength: payload.count, nonceTrials: nonceTrialCount) + @objc public class func calculate(forData data: String, pubKey: String, timestamp: UInt64, ttl: Int) -> String? { + let payload = getPayload(pubKey: pubKey, data: data, timestamp: timestamp, ttl: ttl) + let target = calcTarget(ttl: ttl, payloadLength: payload.count, nonceTrials: nonceTrialCount) // Start with the max value var trialValue = UInt64.max @@ -105,8 +89,16 @@ public enum ProofOfWork { return nonce.toBase64() } + /// Get the proof of work payload + private class func getPayload(pubKey: String, data: String, timestamp: UInt64, ttl: Int) -> [UInt8] { + let timestampString = String(timestamp) + let ttlString = String(ttl) + let payloadString = timestampString + ttlString + pubKey + data + return payloadString.bytes + } + /// Calculate the target we need to reach - private static func calcTarget(ttl: Int, payloadLength: Int, nonceTrials: Int) -> UInt64 { + private class func calcTarget(ttl: Int, payloadLength: Int, nonceTrials: Int) -> UInt64 { let two16 = UInt64(pow(2, 16) - 1) let two64 = UInt64(pow(2, 64) - 1) diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index ad3703552..0697213f2 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -915,6 +915,38 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; return deviceMessages; } +- (AnyPromise *)calculateProofOfWorkForDeviceMessages:(NSArray *)deviceMessages + ttl:(NSNumber *)ttl +{ + // LOKI: Calculate the proof of work for each device message + NSMutableArray *promises = [[NSMutableArray alloc] init]; + for (NSDictionary *deviceMessage in deviceMessages) { + AnyPromise *promise = [AnyPromise promiseWithValue:deviceMessage] + .thenOn(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(NSDictionary *message) { + NSTimeInterval timestampInterval = [[NSDate date] timeIntervalSince1970]; + NSNumber *timestamp = [NSNumber numberWithDouble:timestampInterval]; + + NSString *destination = message[@"destination"]; + NSString *data = message[@"content"]; + + NSString *_Nullable nonce = [ProofOfWork calculateForData:data pubKey:destination timestamp:timestamp.unsignedIntegerValue ttl:ttl.integerValue]; + + // Return our timestamp along with the nonce + // These will help us identify which nonce belongs to which message + return @{ + @"destination": destination, + @"deviceId": message[@"destinationDeviceId"], + @"timestamp": timestamp, + @"nonce": nonce + }; + }); + [promises addObject:promise]; + } + + // Wait for all the PoW Calculations to finish + return PMKWhen(promises); +} + - (void)sendMessageToRecipient:(OWSMessageSend *)messageSend { OWSAssertDebug(messageSend); @@ -1087,65 +1119,82 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; // linked devices that we don't know about. OWSLogWarn(@"Sending a message with no device messages."); } - - OWSRequestMaker *requestMaker = [[OWSRequestMaker alloc] initWithLabel:@"Message Send" - requestFactoryBlock:^(SMKUDAccessKey *_Nullable udAccessKey) { - return [OWSRequestFactory submitMessageRequestWithRecipient:recipient.recipientId - messages:deviceMessages - timeStamp:message.timestamp - udAccessKey:udAccessKey]; - } - udAuthFailureBlock:^{ - // Note the UD auth failure so subsequent retries - // to this recipient also use basic auth. - [messageSend setHasUDAuthFailed]; - } - websocketFailureBlock:^{ - // Note the websocket failure so subsequent retries - // to this recipient also use REST. - messageSend.hasWebsocketSendFailed = YES; - } - recipientId:recipient.recipientId - udAccess:messageSend.udAccess - canFailoverUDAuth:NO]; - [[requestMaker makeRequestObjc] - .then(^(OWSRequestMakerResult *result) { - dispatch_async([OWSDispatch sendingQueue], ^{ - [self messageSendDidSucceed:messageSend - deviceMessages:deviceMessages - wasSentByUD:result.wasSentByUD - wasSentByWebsocket:result.wasSentByWebsocket]; - }); - }) - .catch(^(NSError *error) { - dispatch_async([OWSDispatch sendingQueue], ^{ - NSUInteger statusCode = 0; - NSData *_Nullable responseData = nil; - if ([error.domain isEqualToString:@"SignalServiceKit.RequestMakerUDAuthError"]) { - // Try again. - OWSLogInfo(@"UD request auth failed; failing over to non-UD request."); - [error setIsRetryable:YES]; - } else if ([error.domain isEqualToString:TSNetworkManagerErrorDomain]) { - statusCode = error.code; - - NSError *_Nullable underlyingError = error.userInfo[NSUnderlyingErrorKey]; - if (underlyingError) { - responseData - = underlyingError.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; - } else { - OWSFailDebug(@"Missing underlying error: %@", error); - } + + // TODO: Update message here to show the pow cog icon + + // LOKI: Calculate the proof of work for each device message + NSNumber *ttl = [NSNumber numberWithInteger:@(4 * 24 * 60 * 60)]; + AnyPromise *PoWPromise = [self calculateProofOfWorkForDeviceMessages:deviceMessages ttl:ttl]; + [PoWPromise + .thenOn([OWSDispatch sendingQueue], ^(NSArray *nonceArray) { + OWSRequestMaker *requestMaker = [[OWSRequestMaker alloc] initWithLabel:@"Message Send" + requestFactoryBlock:^(SMKUDAccessKey *_Nullable udAccessKey) { + // Loki Changes: + return [OWSRequestFactory submitLokiMessageRequestWithRecipient:recipient.recipientId + messages:deviceMessages + nonceArray:nonceArray + ttl:ttl]; + /* Original Code: + return [OWSRequestFactory submitMessageRequestWithRecipient:recipient.recipientId + messages:deviceMessages + timeStamp:message.timestamp + udAccessKey:udAccessKey]; + */ + } + udAuthFailureBlock:^{ + // Note the UD auth failure so subsequent retries + // to this recipient also use basic auth. + [messageSend setHasUDAuthFailed]; + } + websocketFailureBlock:^{ + // Note the websocket failure so subsequent retries + // to this recipient also use REST. + messageSend.hasWebsocketSendFailed = YES; + } + recipientId:recipient.recipientId + udAccess:messageSend.udAccess + canFailoverUDAuth:NO]; + return requestMaker; + }) + .thenOn([OWSDispatch sendingQueue], ^(OWSRequestMaker *requestMaker) { + return [requestMaker makeRequestObjc]; + }).then(^(OWSRequestMakerResult *result) { + dispatch_async([OWSDispatch sendingQueue], ^{ + [self messageSendDidSucceed:messageSend + deviceMessages:deviceMessages + wasSentByUD:result.wasSentByUD + wasSentByWebsocket:result.wasSentByWebsocket]; + }); + }) + .catch(^(NSError *error) { + dispatch_async([OWSDispatch sendingQueue], ^{ + NSUInteger statusCode = 0; + NSData *_Nullable responseData = nil; + if ([error.domain isEqualToString:@"SignalServiceKit.RequestMakerUDAuthError"]) { + // Try again. + OWSLogInfo(@"UD request auth failed; failing over to non-UD request."); + [error setIsRetryable:YES]; + } else if ([error.domain isEqualToString:TSNetworkManagerErrorDomain]) { + statusCode = error.code; + + NSError *_Nullable underlyingError = error.userInfo[NSUnderlyingErrorKey]; + if (underlyingError) { + responseData + = underlyingError.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; } else { - OWSFailDebug(@"Unexpected error: %@", error); + OWSFailDebug(@"Missing underlying error: %@", error); } - - [self messageSendDidFail:messageSend - deviceMessages:deviceMessages - statusCode:statusCode - error:error - responseData:responseData]; - }); - }) retainUntilComplete]; + } else { + OWSFailDebug(@"Unexpected error: %@", error); + } + + [self messageSendDidFail:messageSend + deviceMessages:deviceMessages + statusCode:statusCode + error:error + responseData:responseData]; + }); + }) retainUntilComplete]; } - (void)messageSendDidSucceed:(OWSMessageSend *)messageSend diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h index a83c9f7ef..71eeb07f3 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h @@ -59,6 +59,11 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo captchaToken:(nullable NSString *)captchaToken transport:(TSVerificationTransport)transport; ++ (TSRequest *)submitLokiMessageRequestWithRecipient:(NSString *)recipientId + messages:(NSArray *)messages + nonceArray:(NSArray *)nonceArray + ttl: (NSNumber *)ttl; + + (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId messages:(NSArray *)messages timeStamp:(uint64_t)timeStamp diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m index 68214a7d7..fdb6ea50e 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -354,6 +354,58 @@ NS_ASSUME_NONNULL_BEGIN return [accountAttributes copy]; } +// LOKI: Convert Signal JSON messages to Loki messages ++ (NSDictionary *)lokiMessagesFromMessages:(NSArray *)messages + nonceArray:(NSArray *)nonceArray + ttl:(NSNumber *)ttl { + NSMutableArray *modifiedMessages = [[NSMutableArray alloc] init]; + for (NSDictionary *message in messages) { + NSMutableDictionary *lokiMessage = [[NSMutableDictionary alloc] init]; + + // Params for our message server + lokiMessage[@"pubKey"] = message[@"destination"]; + lokiMessage[@"data"] = message[@"content"]; + lokiMessage[@"ttl"] = ttl; + + NSDictionary *_Nullable nonce = [self getNonceFromArray:nonceArray forMessage:message]; + if (nonce) { + lokiMessage[@"timestamp"] = nonce[@"timestmap"]; + lokiMessage[@"nonce"] = nonce[@"nonce"]; + } + + [modifiedMessages addObject:lokiMessage]; + } + + return modifiedMessages; +} + + ++ (NSDictionary *_Nullable)getNonceFromArray:(NSArray *)nonceArray forMessage:(NSDictionary *)message { + NSPredicate *predicate = [NSPredicate predicateWithFormat:@"destination == %@ AND deviceId == %d", message[@"destination"], message[@"destinationDeviceId"]]; + NSArray *filtered = [nonceArray filteredArrayUsingPredicate:predicate]; + return filtered.count > 0 ? [filtered objectAtIndex:0] : nil; +} + +// LOKI: This is the function below with our changes ++ (TSRequest *)submitLokiMessageRequestWithRecipient:(NSString *)recipientId + messages:(NSArray *)messages + nonceArray:(NSArray *)nonceArray + ttl: (NSNumber *)ttl +{ + // NOTE: messages may be empty; See comments in OWSDeviceManager. + OWSAssertDebug(recipientId.length > 0); + + NSDictionary *lokiMessages = [self lokiMessagesFromMessages:messages nonceArray:nonceArray ttl:ttl]; + + NSString *path = [textSecureMessagesAPI stringByAppendingString:recipientId]; + NSDictionary *parameters = @{ + @"messages" : lokiMessages, + }; + + TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:parameters]; + return request; +} + + (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId messages:(NSArray *)messages timeStamp:(uint64_t)timeStamp From 0c711d549ad8b926bb1cc5552e310d3362c9aaf0 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 6 May 2019 13:58:35 +1000 Subject: [PATCH 2/4] Added small note. --- SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m | 1 + 1 file changed, 1 insertion(+) diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m index fdb6ea50e..e0fc4ad5f 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -355,6 +355,7 @@ NS_ASSUME_NONNULL_BEGIN } // LOKI: Convert Signal JSON messages to Loki messages +// Refer to OWSMessageServiceParams for the Signal JSON params + (NSDictionary *)lokiMessagesFromMessages:(NSArray *)messages nonceArray:(NSArray *)nonceArray ttl:(NSNumber *)ttl { From e4d612a58e0bf83b870a5cf0c962740046666e49 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Mon, 6 May 2019 14:22:34 +1000 Subject: [PATCH 3/4] Only send message to the primary device. Fail send if sending message to self. We do this because loki doesn't support multi-device sending at the moment. --- .../src/Messages/OWSMessageSender.m | 12 ++++++++++++ .../Network/API/Requests/OWSRequestFactory.m | 17 ++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 0697213f2..7170e9d91 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1118,6 +1118,12 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; // so that we can learn from the service whether or not there are // linked devices that we don't know about. OWSLogWarn(@"Sending a message with no device messages."); + + // LOKI: We don't handle linked devices yet so it's better to just exit early + // This would only occur if we're sending a message to ourself + NSError *error = OWSErrorMakeFailedToSendOutgoingMessageError(); + [error setIsRetryable:NO]; + return messageSend.failure(error); } // TODO: Update message here to show the pow cog icon @@ -1514,7 +1520,13 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; messageSend.isLocalNumber, messageSend.isUDSend); + // LOKI: Since we don't support multi-device sending yet, just send it to the primary device + NSMutableArray *deviceIds = @[@(OWSDevicePrimaryDeviceId)]; + + /* Original code NSMutableArray *deviceIds = [recipient.devices mutableCopy]; + */ + OWSAssertDebug(deviceIds); if (messageSend.isLocalNumber) { diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m index e0fc4ad5f..88357240e 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -356,7 +356,7 @@ NS_ASSUME_NONNULL_BEGIN // LOKI: Convert Signal JSON messages to Loki messages // Refer to OWSMessageServiceParams for the Signal JSON params -+ (NSDictionary *)lokiMessagesFromMessages:(NSArray *)messages ++ (NSArray *)lokiMessagesFromMessages:(NSArray *)messages nonceArray:(NSArray *)nonceArray ttl:(NSNumber *)ttl { NSMutableArray *modifiedMessages = [[NSMutableArray alloc] init]; @@ -394,15 +394,18 @@ NS_ASSUME_NONNULL_BEGIN ttl: (NSNumber *)ttl { // NOTE: messages may be empty; See comments in OWSDeviceManager. + // This doesn't apply to loki since we don't have linked device support. OWSAssertDebug(recipientId.length > 0); + OWSAssertDebug(messages.count > 0); - NSDictionary *lokiMessages = [self lokiMessagesFromMessages:messages nonceArray:nonceArray ttl:ttl]; - - NSString *path = [textSecureMessagesAPI stringByAppendingString:recipientId]; - NSDictionary *parameters = @{ - @"messages" : lokiMessages, - }; + // Convert to loki json format + NSArray *lokiMessages = [self lokiMessagesFromMessages:messages nonceArray:nonceArray ttl:ttl]; + OWSAssertDebug(lokiMessages.count > 0); + // Just send the first message + NSString *path = [textSecureMessagesAPI stringByAppendingString:recipientId]; + NSDictionary *parameters = [lokiMessages objectAtIndex:0]; + TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:parameters]; return request; } From dd18e65e3ea4fa66149165948db35bc8cb8b814d Mon Sep 17 00:00:00 2001 From: Niels Andriesse Date: Mon, 6 May 2019 14:23:44 +1000 Subject: [PATCH 4/4] Fix minor code style issues --- SignalServiceKit/src/Loki/ProofOfWork.swift | 11 ++-- .../src/Messages/OWSMessageSender.m | 56 ++++++++++--------- .../Network/API/Requests/OWSRequestFactory.h | 2 +- .../Network/API/Requests/OWSRequestFactory.m | 16 +++--- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/SignalServiceKit/src/Loki/ProofOfWork.swift b/SignalServiceKit/src/Loki/ProofOfWork.swift index 245de1daf..55b0838dc 100644 --- a/SignalServiceKit/src/Loki/ProofOfWork.swift +++ b/SignalServiceKit/src/Loki/ProofOfWork.swift @@ -43,8 +43,7 @@ private extension MutableCollection where Element == UInt8, Index == Int { * This was copied from the desktop messenger. * Ref: libloki/proof-of-work.js */ -@objc public class ProofOfWork: NSObject { - private override init() {} +@objc public class ProofOfWork : NSObject { // If this changes then we also have to use something other than UInt64 to support the new length private static let nonceLength = 8 @@ -55,6 +54,8 @@ private extension MutableCollection where Element == UInt8, Index == Int { case .production: return 100 } }() + + private override init() { } /// Calculate a proof of work with the given configuration /// @@ -66,7 +67,7 @@ private extension MutableCollection where Element == UInt8, Index == Int { /// - timestamp: The timestamp /// - ttl: The message time to live /// - Returns: A nonce string or nil if it failed - @objc public class func calculate(forData data: String, pubKey: String, timestamp: UInt64, ttl: Int) -> String? { + @objc public static func calculate(data: String, pubKey: String, timestamp: UInt64, ttl: Int) -> String? { let payload = getPayload(pubKey: pubKey, data: data, timestamp: timestamp, ttl: ttl) let target = calcTarget(ttl: ttl, payloadLength: payload.count, nonceTrials: nonceTrialCount) @@ -90,7 +91,7 @@ private extension MutableCollection where Element == UInt8, Index == Int { } /// Get the proof of work payload - private class func getPayload(pubKey: String, data: String, timestamp: UInt64, ttl: Int) -> [UInt8] { + private static func getPayload(pubKey: String, data: String, timestamp: UInt64, ttl: Int) -> [UInt8] { let timestampString = String(timestamp) let ttlString = String(ttl) let payloadString = timestampString + ttlString + pubKey + data @@ -98,7 +99,7 @@ private extension MutableCollection where Element == UInt8, Index == Int { } /// Calculate the target we need to reach - private class func calcTarget(ttl: Int, payloadLength: Int, nonceTrials: Int) -> UInt64 { + private static func calcTarget(ttl: Int, payloadLength: Int, nonceTrials: Int) -> UInt64 { let two16 = UInt64(pow(2, 16) - 1) let two64 = UInt64(pow(2, 64) - 1) diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 0697213f2..89070d10b 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -918,27 +918,27 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; - (AnyPromise *)calculateProofOfWorkForDeviceMessages:(NSArray *)deviceMessages ttl:(NSNumber *)ttl { - // LOKI: Calculate the proof of work for each device message - NSMutableArray *promises = [[NSMutableArray alloc] init]; + // Loki: Calculate the proof of work for each device message + NSMutableArray *promises = [NSMutableArray new]; for (NSDictionary *deviceMessage in deviceMessages) { AnyPromise *promise = [AnyPromise promiseWithValue:deviceMessage] .thenOn(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(NSDictionary *message) { - NSTimeInterval timestampInterval = [[NSDate date] timeIntervalSince1970]; + NSTimeInterval timestampInterval = [[NSDate new] timeIntervalSince1970]; NSNumber *timestamp = [NSNumber numberWithDouble:timestampInterval]; NSString *destination = message[@"destination"]; NSString *data = message[@"content"]; - - NSString *_Nullable nonce = [ProofOfWork calculateForData:data pubKey:destination timestamp:timestamp.unsignedIntegerValue ttl:ttl.integerValue]; + + NSString *_Nullable nonce = [ProofOfWork calculateWithData:data pubKey:destination timestamp:timestamp.unsignedIntegerValue ttl:ttl.integerValue]; // Return our timestamp along with the nonce // These will help us identify which nonce belongs to which message return @{ - @"destination": destination, - @"deviceId": message[@"destinationDeviceId"], - @"timestamp": timestamp, - @"nonce": nonce - }; + @"destination" : destination, + @"deviceId" : message[@"destinationDeviceId"], + @"timestamp" : timestamp, + @"nonce" : nonce + }; }); [promises addObject:promise]; } @@ -1122,38 +1122,40 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; // TODO: Update message here to show the pow cog icon - // LOKI: Calculate the proof of work for each device message + // Loki: Calculate the proof of work for each device message NSNumber *ttl = [NSNumber numberWithInteger:@(4 * 24 * 60 * 60)]; - AnyPromise *PoWPromise = [self calculateProofOfWorkForDeviceMessages:deviceMessages ttl:ttl]; - [PoWPromise + AnyPromise *powPromise = [self calculateProofOfWorkForDeviceMessages:deviceMessages ttl:ttl]; + [powPromise .thenOn([OWSDispatch sendingQueue], ^(NSArray *nonceArray) { OWSRequestMaker *requestMaker = [[OWSRequestMaker alloc] initWithLabel:@"Message Send" - requestFactoryBlock:^(SMKUDAccessKey *_Nullable udAccessKey) { - // Loki Changes: - return [OWSRequestFactory submitLokiMessageRequestWithRecipient:recipient.recipientId + requestFactoryBlock:^(SMKUDAccessKey *_Nullable udAccessKey) { + // Loki + // ======== + return [OWSRequestFactory submitLokiMessageRequestWithRecipient:recipient.recipientId messages:deviceMessages nonceArray:nonceArray ttl:ttl]; - /* Original Code: - return [OWSRequestFactory submitMessageRequestWithRecipient:recipient.recipientId + // ======== + /* Original code: + return [OWSRequestFactory submitMessageRequestWithRecipient:recipient.recipientId messages:deviceMessages timeStamp:message.timestamp udAccessKey:udAccessKey]; */ - } + } udAuthFailureBlock:^{ // Note the UD auth failure so subsequent retries // to this recipient also use basic auth. [messageSend setHasUDAuthFailed]; } - websocketFailureBlock:^{ - // Note the websocket failure so subsequent retries - // to this recipient also use REST. - messageSend.hasWebsocketSendFailed = YES; - } - recipientId:recipient.recipientId - udAccess:messageSend.udAccess - canFailoverUDAuth:NO]; + websocketFailureBlock:^{ + // Note the websocket failure so subsequent retries + // to this recipient also use REST. + messageSend.hasWebsocketSendFailed = YES; + } + recipientId:recipient.recipientId + udAccess:messageSend.udAccess + canFailoverUDAuth:NO]; return requestMaker; }) .thenOn([OWSDispatch sendingQueue], ^(OWSRequestMaker *requestMaker) { diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h index 71eeb07f3..3056b30ad 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h @@ -62,7 +62,7 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo + (TSRequest *)submitLokiMessageRequestWithRecipient:(NSString *)recipientId messages:(NSArray *)messages nonceArray:(NSArray *)nonceArray - ttl: (NSNumber *)ttl; + ttl:(NSNumber *)ttl; + (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId messages:(NSArray *)messages diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m index e0fc4ad5f..427dc75a3 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -354,14 +354,14 @@ NS_ASSUME_NONNULL_BEGIN return [accountAttributes copy]; } -// LOKI: Convert Signal JSON messages to Loki messages +// Loki: Convert Signal JSON messages to Loki messages // Refer to OWSMessageServiceParams for the Signal JSON params + (NSDictionary *)lokiMessagesFromMessages:(NSArray *)messages nonceArray:(NSArray *)nonceArray ttl:(NSNumber *)ttl { - NSMutableArray *modifiedMessages = [[NSMutableArray alloc] init]; + NSMutableArray *modifiedMessages = [NSMutableArray new]; for (NSDictionary *message in messages) { - NSMutableDictionary *lokiMessage = [[NSMutableDictionary alloc] init]; + NSMutableDictionary *lokiMessage = [NSMutableDictionary new]; // Params for our message server lokiMessage[@"pubKey"] = message[@"destination"]; @@ -387,21 +387,19 @@ NS_ASSUME_NONNULL_BEGIN return filtered.count > 0 ? [filtered objectAtIndex:0] : nil; } -// LOKI: This is the function below with our changes +// Loki: This is the function below with our changes + (TSRequest *)submitLokiMessageRequestWithRecipient:(NSString *)recipientId messages:(NSArray *)messages nonceArray:(NSArray *)nonceArray - ttl: (NSNumber *)ttl + ttl:(NSNumber *)ttl { - // NOTE: messages may be empty; See comments in OWSDeviceManager. + // Messages may be empty; see comments in OWSDeviceManager OWSAssertDebug(recipientId.length > 0); NSDictionary *lokiMessages = [self lokiMessagesFromMessages:messages nonceArray:nonceArray ttl:ttl]; NSString *path = [textSecureMessagesAPI stringByAppendingString:recipientId]; - NSDictionary *parameters = @{ - @"messages" : lokiMessages, - }; + NSDictionary *parameters = @{ @"messages" : lokiMessages }; TSRequest *request = [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:parameters]; return request;