Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

End of the removal of decryption on the main thread #1095

Merged
merged 12 commits into from
May 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,17 @@ Changes to be released in next version
* MXCrypto: Decrypt events asynchronously and no more on the main thread )(vector-im/element-ios/issues/4306).
* MXSession: Add the decryptEvents method to decypt a bunch of events asynchronously.
* MXSession: Make the eventWithEventId method decrypt the event if needed.
* MXEventTimeline: Add NSCopying implementation so that another pagination can be done on the same set of data.
* MXCrypto: eventDeviceInfo: Do not synchronise anymore the operation with the decryption queue.

🐛 Bugfix
* MXRoomSummary: Fix decryption of the last message when it is edited (vector-im/element-ios/issues/4322).

⚠️ API Changes
*
* MXRoom: MXRoom.outgoingMessages does not decrypt messages anymore. Use MXSession.decryptEvents to get decrypted events.
* MXSession: [MXSession decryptEvent:inTimeline:] is deprecated, use [MXSession decryptEvents:inTimeline:onComplete:] instead.
* MXCrypto: [MXCrypto decryptEvent:inTimeline:] is deprecated, use [MXCrypto decryptEvents:inTimeline:onComplete:] instead.
* MXCrypto: [MXCrypto hasKeysToDecryptEvent:] is now asynchronous.

🗣 Translations
*
Expand Down
10 changes: 5 additions & 5 deletions MatrixSDK/Crypto/Algorithms/Megolm/MXMegolmDecryption.m
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ - (BOOL)hasKeysToDecryptEvent:(MXEvent *)event

NSString *senderKey, *sessionId;

MXJSONModelSetString(senderKey, event.content[@"sender_key"]);
MXJSONModelSetString(sessionId, event.content[@"session_id"]);
MXJSONModelSetString(senderKey, event.wireContent[@"sender_key"]);
MXJSONModelSetString(sessionId, event.wireContent[@"session_id"]);
if (senderKey && sessionId)
{
hasKeys = ([crypto.store inboundGroupSessionWithId:sessionId andSenderKey:senderKey] != nil);
Expand All @@ -83,9 +83,9 @@ - (MXEventDecryptionResult *)decryptEvent:(MXEvent*)event inTimeline:(NSString*)
MXEventDecryptionResult *result;
NSString *senderKey, *ciphertext, *sessionId;

MXJSONModelSetString(senderKey, event.content[@"sender_key"]);
MXJSONModelSetString(ciphertext, event.content[@"ciphertext"]);
MXJSONModelSetString(sessionId, event.content[@"session_id"]);
MXJSONModelSetString(senderKey, event.wireContent[@"sender_key"]);
MXJSONModelSetString(ciphertext, event.wireContent[@"ciphertext"]);
MXJSONModelSetString(sessionId, event.wireContent[@"session_id"]);

if (!senderKey || !sessionId || !ciphertext)
{
Expand Down
4 changes: 2 additions & 2 deletions MatrixSDK/Crypto/Algorithms/Olm/MXOlmDecryption.m
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ - (MXEventDecryptionResult *)decryptEvent:(MXEvent *)event inTimeline:(NSString
NSString *deviceKey;
NSDictionary *ciphertext;

MXJSONModelSetString(deviceKey, event.content[@"sender_key"]);
MXJSONModelSetDictionary(ciphertext, event.content[@"ciphertext"]);
MXJSONModelSetString(deviceKey, event.wireContent[@"sender_key"]);
MXJSONModelSetDictionary(ciphertext, event.wireContent[@"ciphertext"]);

if (!ciphertext)
{
Expand Down
2 changes: 1 addition & 1 deletion MatrixSDK/Crypto/CrossSigning/MXCrossSigning.m
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,7 @@ - (void)refreshStateWithSuccess:(nullable void (^)(BOOL stateUpdated))success
NSLog(@"[MXCrossSigning] refreshState for device %@: Current state: %@", self.crypto.store.deviceId, @(self.state));

// Refresh user's keys
[self.crypto.deviceList downloadKeys:@[myUserId] forceDownload:YES success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap, NSDictionary<NSString *,MXCrossSigningInfo *> *crossSigningKeysMap) {
[self.crypto downloadKeys:@[myUserId] forceDownload:YES success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap, NSDictionary<NSString *,MXCrossSigningInfo *> *crossSigningKeysMap) {

BOOL sameCrossSigningKeys = [myUserCrossSigningKeysBefore hasSameKeysAsCrossSigningInfo:crossSigningKeysMap[myUserId]];
self.myUserCrossSigningKeys = crossSigningKeysMap[myUserId];
Expand Down
9 changes: 6 additions & 3 deletions MatrixSDK/Crypto/MXCrypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,20 +173,23 @@ extern NSString *const MXDeviceListDidUpdateUsersDevicesNotification;

@param event the event to decrypt.

@return YES if keys are present.
@param onComplete the block called when the operations completes. It returns the result
*/
- (BOOL)hasKeysToDecryptEvent:(MXEvent*)event;
- (void)hasKeysToDecryptEvent:(MXEvent*)event
onComplete:(void (^)(BOOL))onComplete;

/**
Decrypt a received event.

@warning This method is deprecated, use -[MXCrypto decryptEvents:inTimeline:onComplete:] instead.

@param event the raw event.
@param timeline the id of the timeline where the event is decrypted. It is used
to prevent replay attack.

@return The decryption result.
*/
- (MXEventDecryptionResult *)decryptEvent:(MXEvent*)event inTimeline:(NSString*)timeline;
- (MXEventDecryptionResult *)decryptEvent:(MXEvent*)event inTimeline:(NSString*)timeline __attribute__((deprecated("use -[MXCrypto decryptEvents:inTimeline:onComplete:] instead")));

/**
Decrypt events asynchronously.
Expand Down
36 changes: 14 additions & 22 deletions MatrixSDK/Crypto/MXCrypto.m
Original file line number Diff line number Diff line change
Expand Up @@ -507,23 +507,21 @@ - (MXHTTPOperation *)encryptEventContent:(NSDictionary *)eventContent withType:(
#endif
}

- (BOOL)hasKeysToDecryptEvent:(MXEvent *)event
- (void)hasKeysToDecryptEvent:(MXEvent *)event onComplete:(void (^)(BOOL))onComplete
{
__block BOOL hasKeys = NO;

#ifdef MX_CRYPTO

// We need to go to decryptionQueue only to use getRoomDecryptor
// Other subsequent calls are thread safe because of the implementation of MXCryptoStore
dispatch_sync(decryptionQueue, ^{
id<MXDecrypting> alg = [self getRoomDecryptor:event.roomId algorithm:event.content[@"algorithm"]];
dispatch_async(decryptionQueue, ^{
NSString *algorithm = event.wireContent[@"algorithm"];
id<MXDecrypting> alg = [self getRoomDecryptor:event.roomId algorithm:algorithm];

hasKeys = [alg hasKeysToDecryptEvent:event];
BOOL hasKeys = [alg hasKeysToDecryptEvent:event];
onComplete(hasKeys);
});

#endif

return hasKeys;
}

- (MXEventDecryptionResult *)decryptEvent:(MXEvent *)event inTimeline:(NSString*)timeline
Expand Down Expand Up @@ -558,17 +556,18 @@ - (MXEventDecryptionResult *)decryptEvent2:(MXEvent *)event inTimeline:(NSString
return result;
}

id<MXDecrypting> alg = [self getRoomDecryptor:event.roomId algorithm:event.content[@"algorithm"]];
NSString *algorithm = event.wireContent[@"algorithm"];
id<MXDecrypting> alg = [self getRoomDecryptor:event.roomId algorithm:algorithm];
if (!alg)
{
NSLog(@"[MXCrypto] decryptEvent: Unable to decrypt %@ with algorithm %@. Event: %@", event.eventId, event.content[@"algorithm"], event.JSONDictionary);
NSLog(@"[MXCrypto] decryptEvent: Unable to decrypt %@ with algorithm %@. Event: %@", event.eventId, algorithm, event.JSONDictionary);

result = [MXEventDecryptionResult new];
result.error = [NSError errorWithDomain:MXDecryptingErrorDomain
code:MXDecryptingErrorUnableToDecryptCode
userInfo:@{
NSLocalizedDescriptionKey: MXDecryptingErrorUnableToDecrypt,
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:MXDecryptingErrorUnableToDecryptReason, event, event.content[@"algorithm"]]
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:MXDecryptingErrorUnableToDecryptReason, event, algorithm]
}];
}
else
Expand Down Expand Up @@ -876,17 +875,10 @@ - (MXDeviceInfo *)eventDeviceInfo:(MXEvent *)event

if (event.isEncrypted)
{
// Use decryptionQueue because this is a simple read in the db
// AND we do it synchronously
// @TODO: dispatch_async
MXWeakify(self);
dispatch_sync(decryptionQueue, ^{
MXStrongifyAndReturnIfNil(self);

NSString *algorithm = event.wireContent[@"algorithm"];
device = [self.deviceList deviceWithIdentityKey:event.senderKey andAlgorithm:algorithm];

});
// This is a simple read in the db which is thread safe.
// Return synchronously
NSString *algorithm = event.wireContent[@"algorithm"];
device = [self.deviceList deviceWithIdentityKey:event.senderKey andAlgorithm:algorithm];
}

#endif
Expand Down
6 changes: 3 additions & 3 deletions MatrixSDK/Data/MXEventTimeline.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ typedef void (^MXOnRoomEvent)(MXEvent *event, MXTimelineDirection direction, MXR
with events on calls of [MXEventTimeline paginate] in backwards or forwards direction.
Events are stored in a in-memory store (MXMemoryStore) (@TODO: To be confirmed once they will be implemented). So, they are not permanent.
*/
@interface MXEventTimeline : NSObject
@interface MXEventTimeline : NSObject <NSCopying>

/**
The id of this timeline.
Expand Down Expand Up @@ -100,7 +100,7 @@ typedef void (^MXOnRoomEvent)(MXEvent *event, MXTimelineDirection direction, MXR
@param initialEventId the initial event for the timeline. A nil value will create a live timeline.
@return a MXEventTimeline instance.
*/
- (id)initWithRoom:(MXRoom*)room andInitialEventId:(NSString*)initialEventId;
- (instancetype)initWithRoom:(MXRoom*)room andInitialEventId:(NSString*)initialEventId;

/**
Create a timeline instance for a room and force it to use the given MXStore to store events.
Expand All @@ -110,7 +110,7 @@ typedef void (^MXOnRoomEvent)(MXEvent *event, MXTimelineDirection direction, MXR
@param store the store to use to store timeline events.
@return a MXEventTimeline instance.
*/
- (id)initWithRoom:(MXRoom*)room initialEventId:(NSString*)initialEventId andStore:(id<MXStore>)store;
- (instancetype)initWithRoom:(MXRoom*)room initialEventId:(NSString*)initialEventId andStore:(id<MXStore>)store;

/**
Initialise the room evenTimeline state.
Expand Down
69 changes: 51 additions & 18 deletions MatrixSDK/Data/MXEventTimeline.m
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,19 @@ @interface MXEventTimeline ()
@implementation MXEventTimeline

#pragma mark - Initialisation
- (id)initWithRoom:(MXRoom*)theRoom andInitialEventId:(NSString*)initialEventId

- (instancetype)init
{
self = [super init];
if (self)
{
_timelineId = [[NSUUID UUID] UUIDString];
eventListeners = [NSMutableArray array];
}
return self;
}

- (instancetype)initWithRoom:(MXRoom*)theRoom andInitialEventId:(NSString*)initialEventId
{
// Is it a past or live timeline?
if (initialEventId)
Expand All @@ -88,16 +100,14 @@ - (id)initWithRoom:(MXRoom*)theRoom andInitialEventId:(NSString*)initialEventId
return self;
}

- (id)initWithRoom:(MXRoom*)theRoom initialEventId:(NSString*)initialEventId andStore:(id<MXStore>)theStore
- (instancetype)initWithRoom:(MXRoom*)theRoom initialEventId:(NSString*)initialEventId andStore:(id<MXStore>)theStore
{
self = [super init];
self = [self init];
if (self)
{
_timelineId = [[NSUUID UUID] UUIDString];
_initialEventId = initialEventId;
room = theRoom;
store = theStore;
eventListeners = [NSMutableArray array];

if (!initialEventId)
{
Expand Down Expand Up @@ -289,29 +299,35 @@ - (MXHTTPOperation *)paginate:(NSUInteger)numItems direction:(MXTimelineDirectio

if (onlyFromStore && eventsFromStoreCount)
{
complete();
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"[MXEventTimeline] paginate : is done from the store");
complete();
});

NSLog(@"[MXEventTimeline] paginate : is done from the store");
return;
}

if (0 == remainingNumItems || YES == [self->store hasReachedHomeServerPaginationEndForRoom:self.state.roomId])
{
// Nothing more to do
complete();

NSLog(@"[MXEventTimeline] paginate: is done");
dispatch_async(dispatch_get_main_queue(), ^{
// Nothing more to do
NSLog(@"[MXEventTimeline] paginate: is done");
complete();
});

return;
}
}

// Do not try to paginate forward if end has been reached
if (direction == MXTimelineDirectionForwards && YES == self->hasReachedHomeServerForwardsPaginationEnd)
{
// Nothing more to do
complete();
dispatch_async(dispatch_get_main_queue(), ^{
// Nothing more to do
NSLog(@"[MXEventTimeline] paginate: is done");
complete();
});

NSLog(@"[MXEventTimeline] paginate: is done");
return;
}

Expand Down Expand Up @@ -345,18 +361,17 @@ - (MXHTTPOperation *)paginate:(NSUInteger)numItems direction:(MXTimelineDirectio
|| [self->room.mxSession isPeekingInRoomWithRoomId:self->room.roomId])
{
[self handlePaginationResponse:paginatedResponse direction:direction onComplete:^{
NSLog(@"[MXEventTimeline] paginate: is done");

// Inform the method caller
complete();

NSLog(@"[MXEventTimeline] paginate: is done");
}];
}
else
{
NSLog(@"[MXEventTimeline] paginate: is done");
// Inform the method caller
complete();

NSLog(@"[MXEventTimeline] paginate: is done");
}

} failure:^(NSError *error) {
Expand Down Expand Up @@ -935,4 +950,22 @@ - (void)decryptEvents:(NSArray<MXEvent*>*)events onComplete:(void (^)(void))onCo
}];
}


#pragma mark - NSCopying

- (nonnull id)copyWithZone:(nullable NSZone *)zone
{
MXEventTimeline *timeline = [[self class] allocWithZone:zone];
timeline->_initialEventId = _initialEventId;
timeline->_roomEventFilter = _roomEventFilter;
timeline->_state = [_state copyWithZone:zone];
timeline->room = room;
timeline->store = store;

// There can be only a single live timeline
timeline->_isLiveTimeline = NO;

return timeline;
}

@end
13 changes: 0 additions & 13 deletions MatrixSDK/Data/MXRoom.m
Original file line number Diff line number Diff line change
Expand Up @@ -2377,19 +2377,6 @@ - (void)updateOutgoingMessage:(NSString *)outgoingMessageEventId withOutgoingMes
if ([mxSession.store respondsToSelector:@selector(outgoingMessagesInRoom:)])
{
NSArray<MXEvent*> *outgoingMessages = [mxSession.store outgoingMessagesInRoom:self.roomId];

for (MXEvent *event in outgoingMessages)
{
// Decrypt event if necessary
if (event.eventType == MXEventTypeRoomEncrypted)
{
if (![self.mxSession decryptEvent:event inTimeline:nil])
{
NSLog(@"[MXRoom] outgoingMessages: Warning: Unable to decrypt outgoing event: %@", event.decryptionError);
}
}
}

return outgoingMessages;
}
else
Expand Down
Loading