From 8b1d5ec26d97b64fa2ad2e8764fda3f1f7761ab5 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 9 May 2019 12:19:12 +1000 Subject: [PATCH 1/3] Add OWSFriendRequestMessage. Re-organised files. This is just a subclass of TSOutgoingMessage so it will work as any message would. --- Pods | 2 +- Signal/src/Signal-Bridging-Header.h | 1 + SignalServiceKit/src/Loki/{ => Api}/JSON.swift | 0 SignalServiceKit/src/Loki/{ => Api}/LokiAPI.swift | 0 .../src/Loki/{ => Api}/LokiMessage.swift | 0 .../src/Loki/{ => Api}/SignalMessage.swift | 0 .../Loki/{ => Crypto}/FallbackSessionCipher.swift | 0 .../src/Loki/{ => Crypto}/ProofOfWork.swift | 0 .../src/Loki/{ => Extensions}/ECKeyPair.h | 0 .../src/Loki/{ => Extensions}/ECKeyPair.m | 0 .../src/Loki/{ => Extensions}/ECKeyPair.swift | 0 .../src/Loki/Messages/OWSFriendRequestMessage.h | 10 ++++++++++ .../src/Loki/Messages/OWSFriendRequestMessage.m | 13 +++++++++++++ .../src/Loki/{ => Util}/BuildConfiguration.swift | 0 .../src/Loki/{ => Util}/Mnemonic/Mnemonic.swift | 0 .../src/Loki/{ => Util}/Mnemonic/english.txt | 0 .../src/Loki/{ => Util}/Mnemonic/japanese.txt | 0 .../src/Loki/{ => Util}/Mnemonic/portuguese.txt | 0 .../src/Loki/{ => Util}/Mnemonic/spanish.txt | 0 .../Messages/Interactions/OWSEndSessionMessage.m | 8 ++++++++ .../src/Messages/Interactions/TSOutgoingMessage.h | 6 ++++++ .../src/Messages/Interactions/TSOutgoingMessage.m | 8 +++++++- SignalServiceKit/src/Messages/OWSMessageSender.m | 3 +++ 23 files changed, 49 insertions(+), 2 deletions(-) rename SignalServiceKit/src/Loki/{ => Api}/JSON.swift (100%) rename SignalServiceKit/src/Loki/{ => Api}/LokiAPI.swift (100%) rename SignalServiceKit/src/Loki/{ => Api}/LokiMessage.swift (100%) rename SignalServiceKit/src/Loki/{ => Api}/SignalMessage.swift (100%) rename SignalServiceKit/src/Loki/{ => Crypto}/FallbackSessionCipher.swift (100%) rename SignalServiceKit/src/Loki/{ => Crypto}/ProofOfWork.swift (100%) rename SignalServiceKit/src/Loki/{ => Extensions}/ECKeyPair.h (100%) rename SignalServiceKit/src/Loki/{ => Extensions}/ECKeyPair.m (100%) rename SignalServiceKit/src/Loki/{ => Extensions}/ECKeyPair.swift (100%) create mode 100644 SignalServiceKit/src/Loki/Messages/OWSFriendRequestMessage.h create mode 100644 SignalServiceKit/src/Loki/Messages/OWSFriendRequestMessage.m rename SignalServiceKit/src/Loki/{ => Util}/BuildConfiguration.swift (100%) rename SignalServiceKit/src/Loki/{ => Util}/Mnemonic/Mnemonic.swift (100%) rename SignalServiceKit/src/Loki/{ => Util}/Mnemonic/english.txt (100%) rename SignalServiceKit/src/Loki/{ => Util}/Mnemonic/japanese.txt (100%) rename SignalServiceKit/src/Loki/{ => Util}/Mnemonic/portuguese.txt (100%) rename SignalServiceKit/src/Loki/{ => Util}/Mnemonic/spanish.txt (100%) diff --git a/Pods b/Pods index de364c557..51a2b3e86 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit de364c557a6e2f70e187b1c4a7852b4ea4b9b68a +Subproject commit 51a2b3e8610c1083db88502aaa76da1f352757da diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index 3f7d3287f..501679afb 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -92,6 +92,7 @@ #import #import #import +#import #import #import #import diff --git a/SignalServiceKit/src/Loki/JSON.swift b/SignalServiceKit/src/Loki/Api/JSON.swift similarity index 100% rename from SignalServiceKit/src/Loki/JSON.swift rename to SignalServiceKit/src/Loki/Api/JSON.swift diff --git a/SignalServiceKit/src/Loki/LokiAPI.swift b/SignalServiceKit/src/Loki/Api/LokiAPI.swift similarity index 100% rename from SignalServiceKit/src/Loki/LokiAPI.swift rename to SignalServiceKit/src/Loki/Api/LokiAPI.swift diff --git a/SignalServiceKit/src/Loki/LokiMessage.swift b/SignalServiceKit/src/Loki/Api/LokiMessage.swift similarity index 100% rename from SignalServiceKit/src/Loki/LokiMessage.swift rename to SignalServiceKit/src/Loki/Api/LokiMessage.swift diff --git a/SignalServiceKit/src/Loki/SignalMessage.swift b/SignalServiceKit/src/Loki/Api/SignalMessage.swift similarity index 100% rename from SignalServiceKit/src/Loki/SignalMessage.swift rename to SignalServiceKit/src/Loki/Api/SignalMessage.swift diff --git a/SignalServiceKit/src/Loki/FallbackSessionCipher.swift b/SignalServiceKit/src/Loki/Crypto/FallbackSessionCipher.swift similarity index 100% rename from SignalServiceKit/src/Loki/FallbackSessionCipher.swift rename to SignalServiceKit/src/Loki/Crypto/FallbackSessionCipher.swift diff --git a/SignalServiceKit/src/Loki/ProofOfWork.swift b/SignalServiceKit/src/Loki/Crypto/ProofOfWork.swift similarity index 100% rename from SignalServiceKit/src/Loki/ProofOfWork.swift rename to SignalServiceKit/src/Loki/Crypto/ProofOfWork.swift diff --git a/SignalServiceKit/src/Loki/ECKeyPair.h b/SignalServiceKit/src/Loki/Extensions/ECKeyPair.h similarity index 100% rename from SignalServiceKit/src/Loki/ECKeyPair.h rename to SignalServiceKit/src/Loki/Extensions/ECKeyPair.h diff --git a/SignalServiceKit/src/Loki/ECKeyPair.m b/SignalServiceKit/src/Loki/Extensions/ECKeyPair.m similarity index 100% rename from SignalServiceKit/src/Loki/ECKeyPair.m rename to SignalServiceKit/src/Loki/Extensions/ECKeyPair.m diff --git a/SignalServiceKit/src/Loki/ECKeyPair.swift b/SignalServiceKit/src/Loki/Extensions/ECKeyPair.swift similarity index 100% rename from SignalServiceKit/src/Loki/ECKeyPair.swift rename to SignalServiceKit/src/Loki/Extensions/ECKeyPair.swift diff --git a/SignalServiceKit/src/Loki/Messages/OWSFriendRequestMessage.h b/SignalServiceKit/src/Loki/Messages/OWSFriendRequestMessage.h new file mode 100644 index 000000000..906459e79 --- /dev/null +++ b/SignalServiceKit/src/Loki/Messages/OWSFriendRequestMessage.h @@ -0,0 +1,10 @@ +#import + +NS_ASSUME_NONNULL_BEGIN + +NS_SWIFT_NAME(FriendRequestMessage) +@interface OWSFriendRequestMessage : TSOutgoingMessage + +@end + +NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Loki/Messages/OWSFriendRequestMessage.m b/SignalServiceKit/src/Loki/Messages/OWSFriendRequestMessage.m new file mode 100644 index 000000000..0f744d5dc --- /dev/null +++ b/SignalServiceKit/src/Loki/Messages/OWSFriendRequestMessage.m @@ -0,0 +1,13 @@ +#import "OWSFriendRequestMessage.h" + +@implementation OWSFriendRequestMessage + +- (SSKProtoContentBuilder *)contentBuilder { + SSKProtoContentBuilder *builder = [super contentBuilder]; + + // TODO: Attach pre-key bundle here + + return builder; +} + +@end diff --git a/SignalServiceKit/src/Loki/BuildConfiguration.swift b/SignalServiceKit/src/Loki/Util/BuildConfiguration.swift similarity index 100% rename from SignalServiceKit/src/Loki/BuildConfiguration.swift rename to SignalServiceKit/src/Loki/Util/BuildConfiguration.swift diff --git a/SignalServiceKit/src/Loki/Mnemonic/Mnemonic.swift b/SignalServiceKit/src/Loki/Util/Mnemonic/Mnemonic.swift similarity index 100% rename from SignalServiceKit/src/Loki/Mnemonic/Mnemonic.swift rename to SignalServiceKit/src/Loki/Util/Mnemonic/Mnemonic.swift diff --git a/SignalServiceKit/src/Loki/Mnemonic/english.txt b/SignalServiceKit/src/Loki/Util/Mnemonic/english.txt similarity index 100% rename from SignalServiceKit/src/Loki/Mnemonic/english.txt rename to SignalServiceKit/src/Loki/Util/Mnemonic/english.txt diff --git a/SignalServiceKit/src/Loki/Mnemonic/japanese.txt b/SignalServiceKit/src/Loki/Util/Mnemonic/japanese.txt similarity index 100% rename from SignalServiceKit/src/Loki/Mnemonic/japanese.txt rename to SignalServiceKit/src/Loki/Util/Mnemonic/japanese.txt diff --git a/SignalServiceKit/src/Loki/Mnemonic/portuguese.txt b/SignalServiceKit/src/Loki/Util/Mnemonic/portuguese.txt similarity index 100% rename from SignalServiceKit/src/Loki/Mnemonic/portuguese.txt rename to SignalServiceKit/src/Loki/Util/Mnemonic/portuguese.txt diff --git a/SignalServiceKit/src/Loki/Mnemonic/spanish.txt b/SignalServiceKit/src/Loki/Util/Mnemonic/spanish.txt similarity index 100% rename from SignalServiceKit/src/Loki/Mnemonic/spanish.txt rename to SignalServiceKit/src/Loki/Util/Mnemonic/spanish.txt diff --git a/SignalServiceKit/src/Messages/Interactions/OWSEndSessionMessage.m b/SignalServiceKit/src/Messages/Interactions/OWSEndSessionMessage.m index fbb515334..cc5d236f1 100644 --- a/SignalServiceKit/src/Messages/Interactions/OWSEndSessionMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/OWSEndSessionMessage.m @@ -46,6 +46,14 @@ NS_ASSUME_NONNULL_BEGIN return builder; } +- (SSKProtoContentBuilder *)contentBuilder { + SSKProtoContentBuilder *builder = [super contentBuilder]; + + // TODO Loki: Attach pre key bundle here + + return builder; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h index 1610e14d0..41e188eec 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.h @@ -155,6 +155,12 @@ typedef NS_ENUM(NSInteger, TSGroupMetaMessage) { */ - (nullable SSKProtoDataMessageBuilder *)dataMessageBuilder; +/** + * Intermediate protobuf representation + * Subclasses can augment if they want to manipulate the content message before building. + */ +- (SSKProtoContentBuilder *)contentBuilder; + /** * Should this message be synced to the users other registered devices? This is * generally always true, except in the case of the sync messages themseleves diff --git a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m index 4def76fa9..aa41254ab 100644 --- a/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m +++ b/SignalServiceKit/src/Messages/Interactions/TSOutgoingMessage.m @@ -1113,6 +1113,12 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt return dataProto; } +- (SSKProtoContentBuilder *)contentBuilder +{ + SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; + return contentBuilder; +} + - (nullable NSData *)buildPlainTextData:(SignalRecipient *)recipient { NSError *error; @@ -1122,7 +1128,7 @@ NSString *NSStringForOutgoingMessageRecipientState(OWSOutgoingMessageRecipientSt return nil; } - SSKProtoContentBuilder *contentBuilder = [SSKProtoContent builder]; + SSKProtoContentBuilder *contentBuilder = [self contentBuilder]; [contentBuilder setDataMessage:dataMessage]; NSData *_Nullable contentData = [contentBuilder buildSerializedDataAndReturnError:&error]; if (error || !contentData) { diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 0df033cfe..22975ca86 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -42,6 +42,7 @@ #import "TSRequest.h" #import "TSSocketManager.h" #import "TSThread.h" +#import "OWSFriendRequestMessage.h" #import #import #import @@ -1547,6 +1548,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; // This may involve blocking network requests, so we do it _before_ // we open a transaction. // TODO: Replace this when we add in friend request stuff + // Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; Boolean isFriendRequest = true; if (!isFriendRequest) { [self throws_ensureRecipientHasSessionForMessageSend:messageSend deviceId:deviceId]; @@ -1783,6 +1785,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; OWSAssertDebug(recipientId.length > 0); // TODO: Change this when we have friend request support + // Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; Boolean isFriendRequest = true; if (isFriendRequest) { return [self throws_encryptedFriendMessageForMessageSend:messageSend deviceId:deviceId plainText:plainText]; From 09157673feab7dd1bb4180657ae1ab61e5a41aa3 Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 9 May 2019 14:00:40 +1000 Subject: [PATCH 2/3] Added friend request states in TSThread. Automatically send a OWSFriendRequest if we are not friend with the person. --- SignalMessaging/utils/ThreadUtil.m | 51 ++++++++++++++----- SignalServiceKit/src/Contacts/TSThread.h | 34 +++++++++++++ SignalServiceKit/src/Contacts/TSThread.m | 34 +++++++++++++ .../src/Messages/OWSMessageSender.m | 12 ++--- 4 files changed, 113 insertions(+), 18 deletions(-) diff --git a/SignalMessaging/utils/ThreadUtil.m b/SignalMessaging/utils/ThreadUtil.m index d21e5a708..39c97a1d8 100644 --- a/SignalMessaging/utils/ThreadUtil.m +++ b/SignalMessaging/utils/ThreadUtil.m @@ -85,6 +85,27 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess #pragma mark - Durable Message Enqueue +// Loki: TODO We may change this? ++ (TSOutgoingMessage *)enqueueFriendRequestAcceptMessageInThread:(TSThread *)thread +{ + TSOutgoingMessage *message = + [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] + inThread:thread + messageBody:@"" + attachmentIds:[NSMutableArray new] + expiresInSeconds:0 + expireStartedAt:0 + isVoiceMessage:NO + groupMetaMessage:TSGroupMetaMessageUnspecified + quotedMessage:nil + contactShare:nil + linkPreview:nil]; + [self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + [self.messageSenderJobQueue addMessage:message transaction:transaction]; + }]; + return message; +} + + (TSOutgoingMessage *)enqueueMessageWithText:(NSString *)fullMessageText inThread:(TSThread *)thread quotedReplyModel:(nullable OWSQuotedReplyModel *)quotedReplyModel @@ -129,6 +150,7 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess }]; } +// Loki: TODO Disable attachment and link preview for now + (TSOutgoingMessage *)buildOutgoingMessageWithText:(nullable NSString *)fullMessageText mediaAttachments:(NSArray *)mediaAttachments thread:(TSThread *)thread @@ -172,19 +194,24 @@ typedef void (^BuildOutgoingMessageCompletionBlock)(TSOutgoingMessage *savedMess } BOOL isVoiceMessage = (attachments.count == 1 && attachments.lastObject.isVoiceMessage); - + + // Loki: If we're not friends then always set the message to a friend request message + // If we're friends then the assumption is that we have the other users pre-key bundle + NSString *messageClassString = [thread isFriend] ? @"TSOutgoingMessage" : @"OWSFriendRequestMessage"; + Class messageClass = NSClassFromString(messageClassString); + TSOutgoingMessage *message = - [[TSOutgoingMessage alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] - inThread:thread - messageBody:truncatedText - attachmentIds:[NSMutableArray new] - expiresInSeconds:expiresInSeconds - expireStartedAt:0 - isVoiceMessage:isVoiceMessage - groupMetaMessage:TSGroupMetaMessageUnspecified - quotedMessage:[quotedReplyModel buildQuotedMessageForSending] - contactShare:nil - linkPreview:nil]; + [[messageClass alloc] initOutgoingMessageWithTimestamp:[NSDate ows_millisecondTimeStamp] + inThread:thread + messageBody:truncatedText + attachmentIds:[NSMutableArray new] + expiresInSeconds:expiresInSeconds + expireStartedAt:0 + isVoiceMessage:isVoiceMessage + groupMetaMessage:TSGroupMetaMessageUnspecified + quotedMessage:[quotedReplyModel buildQuotedMessageForSending] + contactShare:nil + linkPreview:nil]; [BenchManager benchAsyncWithTitle:@"Saving outgoing message" diff --git a/SignalServiceKit/src/Contacts/TSThread.h b/SignalServiceKit/src/Contacts/TSThread.h index fa4527b12..1d5a7a4bf 100644 --- a/SignalServiceKit/src/Contacts/TSThread.h +++ b/SignalServiceKit/src/Contacts/TSThread.h @@ -29,6 +29,22 @@ extern ConversationColorName const ConversationColorNameSteel; extern ConversationColorName const kConversationColorName_Default; +// Loki: Friend request state +typedef NS_ENUM(NSInteger, TSThreadFriendRequestState) { + // New conversation, no messages sent or received + TSThreadFriendRequestStateNone, + // This state is used to lock the input early while sending + TSThreadFriendRequestStatePendingSend, + // Friend request send, awaiting response + TSThreadFriendRequestStateRequestSent, + // Friend request received, awaiting user input + TSThreadFriendRequestStateRequestReceived, + // We are friends with the user of this thread + TSThreadFriendRequestStateFriends, + // Friend request sent but it timed out (user didn't accept within x time) + TSThreadFriendRequestStateRequestExpired, +}; + /** * TSThread is the superclass of TSContactThread and TSGroupThread */ @@ -38,6 +54,9 @@ extern ConversationColorName const kConversationColorName_Default; @property (nonatomic, readonly) NSDate *creationDate; @property (nonatomic, readonly) BOOL isArchivedByLegacyTimestampForSorting; +// Loki: The current friend request state with this thread +@property (atomic, readonly) TSThreadFriendRequestState friendRequestState; + /** * Whether the object is a group thread or not. * @@ -170,6 +189,21 @@ extern ConversationColorName const kConversationColorName_Default; - (void)updateWithMutedUntilDate:(NSDate *)mutedUntilDate transaction:(YapDatabaseReadWriteTransaction *)transaction; +#pragma mark - Loki Friend Request + +/// Check if this thread is a friend +- (BOOL)isFriend; + +/// Check if a friend request is pending +- (BOOL)isPendingFriendRequest; + +/// Check if a friend request has been sent to this thread +- (BOOL)hasSentFriendRequest; + +/// Check if a friend request has been received from this thread +- (BOOL)hasReceivedFriendRequest; + @end + NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Contacts/TSThread.m b/SignalServiceKit/src/Contacts/TSThread.m index 744e7c655..895985a66 100644 --- a/SignalServiceKit/src/Contacts/TSThread.m +++ b/SignalServiceKit/src/Contacts/TSThread.m @@ -50,6 +50,8 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa @property (nonatomic, copy, nullable) NSString *messageDraft; @property (atomic, nullable) NSDate *mutedUntilDate; +@property (atomic) TSThreadFriendRequestState friendRequestState; + // DEPRECATED - not used since migrating to sortId // but keeping these properties around to ease any pain in the back-forth // migration while testing. Eventually we can safely delete these as they aren't used anywhere. @@ -84,6 +86,9 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa if (self) { _creationDate = [NSDate date]; _messageDraft = nil; + + // We are initially not friends + _friendRequestState = TSThreadFriendRequestStateNone; NSString *_Nullable contactId = self.contactIdentifier; if (contactId.length > 0) { @@ -694,6 +699,35 @@ ConversationColorName const kConversationColorName_Default = ConversationColorNa }]; } +# pragma mark - Loki Friend Request + +- (BOOL)isFriend +{ + return _friendRequestState == TSThreadFriendRequestStateFriends; +} + +- (BOOL)isPendingFriendRequest +{ + return ( + _friendRequestState == TSThreadFriendRequestStatePendingSend || + _friendRequestState == TSThreadFriendRequestStateRequestSent || + _friendRequestState == TSThreadFriendRequestStateRequestReceived + ); +} + +- (BOOL)hasSentFriendRequest +{ + return ( + _friendRequestState == TSThreadFriendRequestStateRequestSent || + _friendRequestState == TSThreadFriendRequestStateRequestExpired + ); +} + +- (BOOL)hasReceivedFriendRequest +{ + return _friendRequestState == TSThreadFriendRequestStateRequestReceived; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 22975ca86..9b0b7052f 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1547,9 +1547,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; @try { // This may involve blocking network requests, so we do it _before_ // we open a transaction. - // TODO: Replace this when we add in friend request stuff - // Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; - Boolean isFriendRequest = true; + + // Friend requests means we don't have a session with the person + // There's no point to check for it + Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; if (!isFriendRequest) { [self throws_ensureRecipientHasSessionForMessageSend:messageSend deviceId:deviceId]; } @@ -1784,9 +1785,8 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; NSString *recipientId = recipient.recipientId; OWSAssertDebug(recipientId.length > 0); - // TODO: Change this when we have friend request support - // Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; - Boolean isFriendRequest = true; + // Loki: Handle friend requests differently + Boolean isFriendRequest = [messageSend.message isKindOfClass:[OWSFriendRequestMessage class]]; if (isFriendRequest) { return [self throws_encryptedFriendMessageForMessageSend:messageSend deviceId:deviceId plainText:plainText]; } From 787e2c1cb70982414affd1f7fa38e2ca4444900f Mon Sep 17 00:00:00 2001 From: Mikunj Date: Thu, 9 May 2019 16:44:30 +1000 Subject: [PATCH 3/3] Send correct data to storage server. Data -> Envelope -> WebSocket --- .../translations/en.lproj/Localizable.strings | 2 + SignalServiceKit/src/Loki/Api/LokiAPI.swift | 8 +- .../src/Loki/Api/LokiMessage.swift | 88 +++++++++++++++++-- .../src/Messages/OWSMessageSender.m | 2 +- 4 files changed, 92 insertions(+), 8 deletions(-) diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index c1c50bf36..84fb46c33 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -2570,3 +2570,5 @@ "No search results" = "No search results"; "Calculating proof of work" = "Calculating proof of work"; "Failed to calculate proof of work." = "Failed to calculate proof of work."; +"Failed to wrap data in an Envelope" = "Failed to wrap data in an Envelope."; +"Failed to wrap data in an WebSocket" = "Failed to wrap data in an WebSocket."; diff --git a/SignalServiceKit/src/Loki/Api/LokiAPI.swift b/SignalServiceKit/src/Loki/Api/LokiAPI.swift index 08df47ded..491644e2c 100644 --- a/SignalServiceKit/src/Loki/Api/LokiAPI.swift +++ b/SignalServiceKit/src/Loki/Api/LokiAPI.swift @@ -21,10 +21,14 @@ import PromiseKit public enum Error : LocalizedError { case proofOfWorkCalculationFailed + case failedToWrapInEnvelope + case failedToWrapInWebSocket public var errorDescription: String? { switch self { case .proofOfWorkCalculationFailed: return NSLocalizedString("Failed to calculate proof of work.", comment: "") + case .failedToWrapInEnvelope: return NSLocalizedString("Failed to wrap data in an Envelope", comment: "") + case .failedToWrapInWebSocket: return NSLocalizedString("Failed to wrap data in an WebSocket", comment: "") } } } @@ -73,8 +77,8 @@ import PromiseKit return anyPromise } - @objc public static func objc_sendSignalMessage(_ signalMessage: SignalMessage, to destination: String, requiringPoW isPoWRequired: Bool) -> AnyPromise { - let promise = LokiMessage.fromSignalMessage(signalMessage, requiringPoW: isPoWRequired) + @objc public static func objc_sendSignalMessage(_ signalMessage: SignalMessage, to destination: String, timestamp: UInt64, requiringPoW isPoWRequired: Bool) -> AnyPromise { + let promise = LokiMessage.from(signalMessage: signalMessage, timestamp: timestamp, requiringPoW: isPoWRequired) .then(sendMessage) .recoverNetworkError(on: DispatchQueue.global()) let anyPromise = AnyPromise(promise) diff --git a/SignalServiceKit/src/Loki/Api/LokiMessage.swift b/SignalServiceKit/src/Loki/Api/LokiMessage.swift index 889960a49..53730a66e 100644 --- a/SignalServiceKit/src/Loki/Api/LokiMessage.swift +++ b/SignalServiceKit/src/Loki/Api/LokiMessage.swift @@ -22,17 +22,40 @@ public struct LokiMessage { self.nonce = nonce } - public static func fromSignalMessage(_ signalMessage: SignalMessage, requiringPoW isPoWRequired: Bool) -> Promise { + /// Build a LokiMessage from a SignalMessage + /// + /// - Parameters: + /// - signalMessage: the signal message + /// - timestamp: the original message timestamp (TSOutgoingMessage.timestamp) + /// - isPoWRequired: Should we calculate proof of work + /// - Returns: The loki message + public static func from(signalMessage: SignalMessage, timestamp: UInt64, requiringPoW isPoWRequired: Bool) -> Promise { + // To match the desktop application we have to take the data + // wrap it in an envelope, then + // wrap it in a websocket return Promise { seal in DispatchQueue.global(qos: .default).async { + guard let envelope = buildEnvelope(fromSignalMessage: signalMessage, timestamp: timestamp) else { + seal.reject(LokiAPI.Error.failedToWrapInEnvelope) + return + } + + // Make the data + guard let websocket = wrapInWebsocket(envelope: envelope), + let serialized = try? websocket.serializedData() else { + seal.reject(LokiAPI.Error.failedToWrapInWebSocket) + return; + } + + let data = serialized.base64EncodedString() let destination = signalMessage["destination"] as! String - let data = signalMessage["content"] as! String let ttl = LokiAPI.defaultMessageTTL + if isPoWRequired { // timeIntervalSince1970 returns timestamp in seconds but the storage server only accepts timestamp in milliseconds - let timestamp = UInt64(Date().timeIntervalSince1970 * 1000) - if let nonce = ProofOfWork.calculate(data: data, pubKey: destination, timestamp: timestamp, ttl: ttl) { - let result = LokiMessage(destination: destination, data: data, ttl: ttl, timestamp: timestamp, nonce: nonce) + let now = UInt64(Date().timeIntervalSince1970 * 1000) + if let nonce = ProofOfWork.calculate(data: data, pubKey: destination, timestamp: now, ttl: ttl) { + let result = LokiMessage(destination: destination, data: data, ttl: ttl, timestamp: now, nonce: nonce) seal.fulfill(result) } else { seal.reject(LokiAPI.Error.proofOfWorkCalculationFailed) @@ -45,6 +68,61 @@ public struct LokiMessage { } } + /// Wrap EnvelopeProto in a WebSocketProto + /// This is needed because it is done automatically on the desktop + private static func wrapInWebsocket(envelope: SSKProtoEnvelope) -> WebSocketProtoWebSocketMessage? { + do { + // This request is just a copy of the one on desktop + let requestBuilder = WebSocketProtoWebSocketRequestMessage.builder(verb: "PUT", path: "/api/v1/message", requestID: UInt64.random(in: 1.. SSKProtoEnvelope? { + guard let ourKeys = SSKEnvironment.shared.identityManager.identityKeyPair() else { + owsFailDebug("error building envelope: identityManager.identityKeyPair() is invalid") + return nil; + } + + do { + let ourPubKey = ourKeys.hexEncodedPublicKey + + let params = ParamParser(dictionary: signalMessage) + + let typeInt: Int32 = try params.required(key: "type") + guard let type: SSKProtoEnvelope.SSKProtoEnvelopeType = SSKProtoEnvelope.SSKProtoEnvelopeType(rawValue: typeInt) else { + Logger.error("`type` was invalid: \(typeInt)") + throw ParamParser.ParseError.invalidFormat("type") + } + + let builder = SSKProtoEnvelope.builder(type: type, timestamp: timestamp) + builder.setSource(ourPubKey) + builder.setSourceDevice(OWSDevicePrimaryDeviceId) + + if let content = try params.optionalBase64EncodedData(key: "content") { + builder.setContent(content) + } + + return try builder.build() + } catch { + owsFailDebug("Loki Message: error building envelope: \(error)") + return nil + } + } + public func toJSON() -> JSON { var result = [ "pubKey" : destination, "data" : data.description, "ttl" : String(ttl) ] if let timestamp = timestamp, let nonce = nonce { diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m index 9b0b7052f..21ac2ea47 100644 --- a/SignalServiceKit/src/Messages/OWSMessageSender.m +++ b/SignalServiceKit/src/Messages/OWSMessageSender.m @@ -1112,7 +1112,7 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException"; // Convert the message to a Loki message and send it using the Loki messaging API NSDictionary *signalMessage = deviceMessages.firstObject; BOOL isPoWRequired = YES; // TODO: Base on message type - [[LokiAPI objc_sendSignalMessage:signalMessage to:recipient.recipientId requiringPoW:isPoWRequired] + [[LokiAPI objc_sendSignalMessage:signalMessage to:recipient.recipientId timestamp:message.timestamp requiringPoW:isPoWRequired] .thenOn(OWSDispatch.sendingQueue, ^(id result) { [self messageSendDidSucceed:messageSend deviceMessages:deviceMessages