Merge pull request #1652 from vector-im/e2e_key_sharing

E2e key sharing: Show the dialog on incoming key requests
This commit is contained in:
manuroe 2017-11-15 14:38:15 +01:00 committed by GitHub
commit dce2167f0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 403 additions and 1 deletions

View file

@ -65,6 +65,7 @@
327382C21F276AED00356143 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382BC1F276AED00356143 /* InfoPlist.strings */; };
327382C31F276AED00356143 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382BE1F276AED00356143 /* Localizable.strings */; };
327382C41F276AED00356143 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = 327382C01F276AED00356143 /* Vector.strings */; };
3284D7FF1FBB34B70090AA80 /* RoomKeyRequestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3284D7FE1FBB34B70090AA80 /* RoomKeyRequestViewController.m */; };
32918EA91F473BDB0076CA16 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 32918EA51F473BDB0076CA16 /* Localizable.strings */; };
32918EAA1F473BDB0076CA16 /* Vector.strings in Resources */ = {isa = PBXBuildFile; fileRef = 32918EA71F473BDB0076CA16 /* Vector.strings */; };
32935CB11F6056FD006888C8 /* IntegrationManagerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 32935CB01F6056FD006888C8 /* IntegrationManagerViewController.m */; };
@ -668,6 +669,8 @@
327382BD1F276AED00356143 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = InfoPlist.strings; sourceTree = "<group>"; };
327382BF1F276AED00356143 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = "<group>"; };
327382C11F276AED00356143 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Vector.strings; sourceTree = "<group>"; };
3284D7FD1FBB34B70090AA80 /* RoomKeyRequestViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RoomKeyRequestViewController.h; sourceTree = "<group>"; };
3284D7FE1FBB34B70090AA80 /* RoomKeyRequestViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RoomKeyRequestViewController.m; sourceTree = "<group>"; };
32918EA61F473BDB0076CA16 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Localizable.strings; sourceTree = "<group>"; };
32918EA81F473BDB0076CA16 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Vector.strings; sourceTree = "<group>"; };
32935CAF1F6056FD006888C8 /* IntegrationManagerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IntegrationManagerViewController.h; sourceTree = "<group>"; };
@ -2074,6 +2077,8 @@
F083BC3B1E7009EC00A9B29C /* RoomFilesSearchViewController.m */,
F083BC3C1E7009EC00A9B29C /* RoomFilesViewController.h */,
F083BC3D1E7009EC00A9B29C /* RoomFilesViewController.m */,
3284D7FD1FBB34B70090AA80 /* RoomKeyRequestViewController.h */,
3284D7FE1FBB34B70090AA80 /* RoomKeyRequestViewController.m */,
F083BC3E1E7009EC00A9B29C /* RoomMemberDetailsViewController.h */,
F083BC3F1E7009EC00A9B29C /* RoomMemberDetailsViewController.m */,
F083BC401E7009EC00A9B29C /* RoomMemberDetailsViewController.xib */,
@ -3300,6 +3305,7 @@
F083BE111E7009ED00A9B29C /* DirectoryViewController.m in Sources */,
F0B4CBB11F4215E3008E99C5 /* EventDetailsView.m in Sources */,
F083BE1E1E7009ED00A9B29C /* RoomMessagesSearchViewController.m in Sources */,
3284D7FF1FBB34B70090AA80 /* RoomKeyRequestViewController.m in Sources */,
F083BE231E7009ED00A9B29C /* RoomViewController.m in Sources */,
F083BE9E1E7009ED00A9B29C /* TableViewCellWithCheckBoxes.m in Sources */,
32AE61E41F0A971B007255F4 /* RoomMembershipBubbleCell.m in Sources */,

View file

@ -32,6 +32,7 @@
#import "ContactDetailsViewController.h"
#import "BugReportViewController.h"
#import "RoomKeyRequestViewController.h"
#import "NSBundle+MatrixKit.h"
#import "MatrixSDK/MatrixSDK.h"
@ -108,7 +109,18 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
The current call view controller (if any).
*/
CallViewController *currentCallViewController;
/**
Incoming room key requests observers
*/
id roomKeyRequestObserver;
id roomKeyRequestCancellationObserver;
/**
If any the currently displayed sharing key dialog
*/
RoomKeyRequestViewController *roomKeyRequestViewController;
/**
Account picker used in case of multiple account.
*/
@ -552,6 +564,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
}
[self handleLaunchAnimation];
// Check if we need to display a key share dialog
[self checkPendingRoomKeyRequests];
}
- (void)applicationWillTerminate:(UIApplication *)application
@ -2059,6 +2074,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Add an array to handle incoming push
self.incomingPushEventIds[@(mxSession.hash)] = [NSMutableArray array];
// Enable listening of incoming key share requests
[self enableRoomKeyRequestObserver:mxSession];
}
}
@ -2077,6 +2095,9 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
// Disable local notifications from this session
[self disableLocalNotificationsFromMatrixSession:mxSession];
// Disable listening of incoming key share requests
[self disableRoomKeyRequestObserver:mxSession];
[mxSessionArray removeObject:mxSession];
@ -3288,4 +3309,109 @@ NSString *const kAppDelegateNetworkStatusDidChangeNotification = @"kAppDelegateN
[callEventsListeners removeObjectForKey:@(mxSession.hash)];
}
#pragma mark - Incoming room key requests handling
- (void)enableRoomKeyRequestObserver:(MXSession*)mxSession
{
roomKeyRequestObserver =
[[NSNotificationCenter defaultCenter] addObserverForName:kMXCryptoRoomKeyRequestNotification
object:mxSession.crypto
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notif)
{
[self checkPendingRoomKeyRequestsInSession:mxSession];
}];
roomKeyRequestCancellationObserver =
[[NSNotificationCenter defaultCenter] addObserverForName:kMXCryptoRoomKeyRequestCancellationNotification
object:mxSession.crypto
queue:[NSOperationQueue mainQueue]
usingBlock:^(NSNotification *notif)
{
[self checkPendingRoomKeyRequestsInSession:mxSession];
}];
}
- (void)disableRoomKeyRequestObserver:(MXSession*)mxSession
{
if (roomKeyRequestObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:roomKeyRequestObserver];
roomKeyRequestObserver = nil;
}
if (roomKeyRequestCancellationObserver)
{
[[NSNotificationCenter defaultCenter] removeObserver:roomKeyRequestCancellationObserver];
roomKeyRequestCancellationObserver = nil;
}
}
// Check if a key share dialog must be displayed for the given session
- (void)checkPendingRoomKeyRequestsInSession:(MXSession*)mxSession
{
if ([UIApplication sharedApplication].applicationState != UIApplicationStateActive)
{
NSLog(@"[AppDelegate] checkPendingRoomKeyRequestsInSession called while the app is not active. Ignore it.");
return;
}
[mxSession.crypto pendingKeyRequests:^(MXUsersDevicesMap<NSArray<MXIncomingRoomKeyRequest *> *> *pendingKeyRequests) {
NSLog(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: pendingKeyRequests.count: %@. Already displayed: %@",
@(pendingKeyRequests.count),
roomKeyRequestViewController ? @"YES" : @"NO");
if (roomKeyRequestViewController)
{
// Check if the current RoomKeyRequestViewController is still valid
MXSession *currentMXSession = roomKeyRequestViewController.mxSession;
NSString *currentUser = roomKeyRequestViewController.device.userId;
NSString *currentDevice = roomKeyRequestViewController.device.deviceId;
NSArray<MXIncomingRoomKeyRequest *> *currentPendingRequest = [pendingKeyRequests objectForDevice:currentDevice forUser:currentUser];
if (currentMXSession == mxSession && currentPendingRequest.count == 0)
{
NSLog(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: Cancel current dialog");
// The key request has been probably cancelled, remove the popup
[roomKeyRequestViewController hide];
roomKeyRequestViewController = nil;
}
}
if (!roomKeyRequestViewController && pendingKeyRequests.count)
{
// Pick the first coming user/device pair
NSString *user = pendingKeyRequests.userIds.firstObject;
NSString *device = [pendingKeyRequests deviceIdsForUser:user].firstObject;
[mxSession.crypto deviceWithDeviceId:device ofUser:user complete:^(MXDeviceInfo *device) {
NSLog(@"[AppDelegate] checkPendingRoomKeyRequestsInSession: Open dialog");
roomKeyRequestViewController = [[RoomKeyRequestViewController alloc] initWithDeviceInfo:device andMatrixSession:mxSession onComplete:^{
roomKeyRequestViewController = nil;
// Check next pending key request, if any
[self checkPendingRoomKeyRequests];
}];
[roomKeyRequestViewController show];
}];
}
}];
}
// Check all opened MXSessions for key share dialog
- (void)checkPendingRoomKeyRequests
{
for (MXSession *mxSession in mxSessionArray)
{
[self checkPendingRoomKeyRequestsInSession:mxSession];
}
}
@end

View file

@ -541,3 +541,10 @@
"share_extension_auth_prompt" = "Login in the main app to share content";
"share_extension_failed_to_encrypt" = "Failed to send. Check in the main app the encryption settings for this room";
// Room key request dialog
"e2e_room_key_request_title" = "Encryption key request";
"e2e_room_key_request_message" = "Your unverified device '%@' is requesting encryption keys.";
"e2e_room_key_request_start_verification" = "Start verification...";
"e2e_room_key_request_share_without_verifying" = "Share without verifying";
"e2e_room_key_request_ignore_request" = "Ignore request";

View file

@ -0,0 +1,57 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import <UIKit/UIKit.h>
#import <MatrixSDK/MatrixSDK.h>
#import <MatrixKit/MatrixKit.h>
/**
The `RoomKeyRequestViewController` display a modal dialog at the top of the
application asking the user if he wants to share room keys with a user's device.
For the moment, the user is himself.
*/
@interface RoomKeyRequestViewController : NSObject <MXKEncryptionInfoViewDelegate>
/**
The UIAlertController instance which handles the dialog.
*/
@property (nonatomic, readonly) UIAlertController *alertController;
@property (nonatomic, readonly) MXSession *mxSession;
@property (nonatomic, readonly) MXDeviceInfo *device;
/**
Initialise an `RoomKeyRequestViewController` instance.
@param deviceInfo the device to share keys to.
@param session the related matrix session.
@param onComplete a block called when the the dialog is closed.
@return the newly created instance.
*/
- (instancetype)initWithDeviceInfo:(MXDeviceInfo*)deviceInfo andMatrixSession:(MXSession*)session onComplete:(void (^)())onComplete;
/**
Show the dialog in a modal way.
*/
- (void)show;
/**
Hide the dialog.
*/
- (void)hide;
@end

View file

@ -0,0 +1,206 @@
/*
Copyright 2017 Vector Creations Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#import "RoomKeyRequestViewController.h"
#import "AppDelegate.h"
#import "EncryptionInfoView.h"
@interface RoomKeyRequestViewController ()
{
void (^onComplete)();
EncryptionInfoView *encryptionInfoView;
}
@end
@implementation RoomKeyRequestViewController
- (instancetype)initWithDeviceInfo:(MXDeviceInfo *)deviceInfo andMatrixSession:(MXSession *)session onComplete:(void (^)())onCompleteBlock
{
self = [super init];
if (self)
{
_mxSession = session;
_device = deviceInfo;
onComplete = onCompleteBlock;
}
return self;
}
- (void)show
{
// Show it modally on the root view controller
UIViewController *rootViewController = [AppDelegate theDelegate].window.rootViewController;
if (rootViewController)
{
NSString *title = NSLocalizedStringFromTable(@"e2e_room_key_request_title", @"Vector", nil);
NSString *message = [NSString stringWithFormat:NSLocalizedStringFromTable(@"e2e_room_key_request_message", @"Vector", nil), _device.displayName];
_alertController = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleAlert];
__weak typeof(self) weakSelf = self;
[_alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"e2e_room_key_request_start_verification", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->_alertController = nil;
[self showVerificationView];
}
}]];
[_alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"e2e_room_key_request_share_without_verifying", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->_alertController = nil;
// Accept the received requests from this device
[self.mxSession.crypto acceptAllPendingKeyRequestsFromUser:self.device.userId andDevice:self.device.deviceId onComplete:^{
onComplete();
}];
}
}]];
[_alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedStringFromTable(@"e2e_room_key_request_ignore_request", @"Vector", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {
if (weakSelf)
{
typeof(self) self = weakSelf;
self->_alertController = nil;
// Ignore all pending requests from this device
[self.mxSession.crypto ignoreAllPendingKeyRequestsFromUser:self.device.userId andDevice:self.device.deviceId onComplete:^{
onComplete();
}];
}
}]];
[rootViewController presentViewController:_alertController animated:YES completion:nil];
}
}
- (void)hide
{
if (_alertController)
{
[_alertController dismissViewControllerAnimated:YES completion:nil];
_alertController = nil;
}
if (encryptionInfoView)
{
[encryptionInfoView removeFromSuperview];
encryptionInfoView = nil;
}
}
- (void)showVerificationView
{
// Show it modally on the root view controller
UIViewController *rootViewController = [AppDelegate theDelegate].window.rootViewController;
if (rootViewController)
{
encryptionInfoView = [[EncryptionInfoView alloc] initWithDeviceInfo:_device andMatrixSession:_mxSession];
[encryptionInfoView onButtonPressed:encryptionInfoView.verifyButton];
encryptionInfoView.delegate = self;
// Add shadow on added view
encryptionInfoView.layer.cornerRadius = 5;
encryptionInfoView.layer.shadowOffset = CGSizeMake(0, 1);
encryptionInfoView.layer.shadowOpacity = 0.5f;
// Add the view and define edge constraints
[rootViewController.view addSubview:encryptionInfoView];
[rootViewController.view addConstraint:[NSLayoutConstraint constraintWithItem:encryptionInfoView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:rootViewController.topLayoutGuide
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:10.0f]];
[rootViewController.view addConstraint:[NSLayoutConstraint constraintWithItem:encryptionInfoView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:rootViewController.bottomLayoutGuide
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:-10.0f]];
[rootViewController.view addConstraint:[NSLayoutConstraint constraintWithItem:rootViewController.view
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:encryptionInfoView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:-10.0f]];
[rootViewController.view addConstraint:[NSLayoutConstraint constraintWithItem:rootViewController.view
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:encryptionInfoView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:10.0f]];
[rootViewController.view setNeedsUpdateConstraints];
}
}
#pragma mark - MXKEncryptionInfoViewDelegate
- (void)encryptionInfoView:(MXKEncryptionInfoView *)theEncryptionInfoView didDeviceInfoVerifiedChange:(MXDeviceInfo *)deviceInfo
{
encryptionInfoView = nil;
if (deviceInfo.verified == MXDeviceVerified)
{
// Accept the received requests from this device
// As the device is now verified, all other key requests will be automatically accepted.
[self.mxSession.crypto acceptAllPendingKeyRequestsFromUser:self.device.userId andDevice:self.device.deviceId onComplete:^{
onComplete();
}];
}
}
- (void)encryptionInfoViewDidClose:(MXKEncryptionInfoView *)theEncryptionInfoView
{
encryptionInfoView = nil;
// Come back to self.alertController - ie, reopen it
[self show];
}
@end