Warn unknown devices: Add the screen that list unknown devices (UsersDevicesViewController)

This commit is contained in:
manuroe 2017-02-14 18:21:46 +01:00
parent 235b47078e
commit 58ad0516ab
8 changed files with 356 additions and 10 deletions

View file

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
320FFB781E531520007F5277 /* UsersDevicesViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 320FFB771E531520007F5277 /* UsersDevicesViewController.m */; };
3235CD851C341FAA0084EA40 /* HomeMessagesSearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3235CD841C341FAA0084EA40 /* HomeMessagesSearchViewController.m */; };
323A520B1C3183CC00010773 /* UIViewController+VectorSearch.m in Sources */ = {isa = PBXBuildFile; fileRef = 323A520A1C3183CC00010773 /* UIViewController+VectorSearch.m */; };
32492DB21C293C8900035C79 /* PublicRoomTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 32492DB11C293C8900035C79 /* PublicRoomTableViewCell.m */; };
@ -407,6 +408,8 @@
/* Begin PBXFileReference section */
11865E69C29698A4179E1F3F /* Pods-Vector.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Vector.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Vector/Pods-Vector.debug.xcconfig"; sourceTree = "<group>"; };
320FFB761E531520007F5277 /* UsersDevicesViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UsersDevicesViewController.h; sourceTree = "<group>"; };
320FFB771E531520007F5277 /* UsersDevicesViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UsersDevicesViewController.m; sourceTree = "<group>"; };
3235CD831C341FAA0084EA40 /* HomeMessagesSearchViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HomeMessagesSearchViewController.h; sourceTree = "<group>"; };
3235CD841C341FAA0084EA40 /* HomeMessagesSearchViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HomeMessagesSearchViewController.m; sourceTree = "<group>"; };
323A52091C3183CC00010773 /* UIViewController+VectorSearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+VectorSearch.h"; sourceTree = "<group>"; };
@ -1589,6 +1592,8 @@
7165A2581C05CD42003635D7 /* SegmentedViewController.h */,
7165A2591C05CD42003635D7 /* SegmentedViewController.m */,
7165A25A1C05CD42003635D7 /* SegmentedViewController.xib */,
320FFB761E531520007F5277 /* UsersDevicesViewController.h */,
320FFB771E531520007F5277 /* UsersDevicesViewController.m */,
);
path = ViewController;
sourceTree = "<group>";
@ -2149,6 +2154,7 @@
32C52BF61CBE4B0A00863B33 /* RoomEmailInvitation.m in Sources */,
F047DBB91C576F6600952DA2 /* AuthInputsView.m in Sources */,
323A520B1C3183CC00010773 /* UIViewController+VectorSearch.m in Sources */,
320FFB781E531520007F5277 /* UsersDevicesViewController.m in Sources */,
32A887211C89B9580037DC17 /* SimpleRoomTitleView.m in Sources */,
F056417B1C7C9FD7002276ED /* TableViewCellWithButton.m in Sources */,
F0CC4DC01C4E26FA003BBE45 /* MediaAlbumTableCell.m in Sources */,

View file

@ -210,6 +210,7 @@
"unknown_devices_alert_title" = "Room contains unknown devices";
"unknown_devices_alert" = "This room contains unknown devices which have not been verified.\nThis means there is no guarantee that the devices belong to the users they claim to.\nWe recommend you go through the verification process for each device before continuing, but you can resend the message without verifying if you prefer.";
"unknown_devices_verify" = "Verify...";
"unknown_devices_title" = "Unknown devices";
// Room Title
"room_title_new_room" = "New room";

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="H1p-Uh-vWS">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="H1p-Uh-vWS">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
@ -14,6 +14,7 @@
<objects>
<navigationController title="Messages" id="RMx-3f-FxP" userLabel="HomeNav" sceneMemberID="viewController">
<navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="Pmd-2v-anx">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
@ -43,11 +44,12 @@
<segue destination="KDg-aD-xlK" kind="show" identifier="showRoomSearch" id="hdA-V1-9AF"/>
<segue destination="nDS-pp-sWM" kind="show" identifier="showMemberDetails" id="cUw-vU-gJq"/>
<segue destination="gkO-rP-nGK" kind="show" identifier="showContactDetails" action="showDetailViewController:sender:" id="f5u-Y1-7nt"/>
<segue destination="5CG-x5-eo5" kind="presentation" identifier="showUnknownDevices" id="HmV-62-pdU"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="94y-cU-qQD" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1384" y="-1063"/>
<point key="canvasLocation" x="1385" y="-1082"/>
</scene>
<!--Room Member Details View Controller-->
<scene sceneID="eq5-qi-gDd">
@ -135,7 +137,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="mvZ-se-pqQ" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="414" y="1356"/>
<point key="canvasLocation" x="1364" y="-3090"/>
</scene>
<!--Settings-->
<scene sceneID="3md-j7-Qex">
@ -172,7 +174,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ndh-yC-OwR" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1359" y="71"/>
<point key="canvasLocation" x="2364" y="-3089"/>
</scene>
<!--RecentsSplitVC-->
<scene sceneID="Nki-YV-4Qg">
@ -265,6 +267,7 @@
<objects>
<navigationController title="RoomNav" id="vC3-pB-5Vb" sceneMemberID="viewController">
<navigationBar key="navigationBar" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" id="DjV-YW-jjY">
<rect key="frame" x="0.0" y="0.0" width="1000" height="1000"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
@ -312,6 +315,39 @@
</objects>
<point key="canvasLocation" x="3346" y="-3935"/>
</scene>
<!--Users Devices View Controller-->
<scene sceneID="RSF-rj-bxv">
<objects>
<tableViewController id="yAK-cH-GIm" customClass="UsersDevicesViewController" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="44" sectionHeaderHeight="68" sectionFooterHeight="28" id="cJ1-UB-ddI">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</tableView>
<navigationItem key="navigationItem" id="bz4-QB-4ei"/>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="y4A-Q3-hqH" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2558" y="74"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="EdH-bW-mhE">
<objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="5CG-x5-eo5" sceneMemberID="viewController">
<toolbarItems/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="VxF-jf-H2t">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<nil name="viewControllers"/>
<connections>
<segue destination="yAK-cH-GIm" kind="relationship" relationship="rootViewController" id="2ox-mq-u3b"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="WZ3-dq-2aK" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="1385" y="74"/>
</scene>
</scenes>
<resources>
<image name="search_icon.png" width="22" height="22"/>
@ -319,7 +355,7 @@
</resources>
<inferredMetricsTieBreakers>
<segue reference="agy-3r-khl"/>
<segue reference="ziz-Xl-QVg"/>
<segue reference="fNQ-S3-DbZ"/>
<segue reference="cUw-vU-gJq"/>
<segue reference="f5u-Y1-7nt"/>
</inferredMetricsTieBreakers>
</document>

View file

@ -45,6 +45,8 @@
#import "RoomSearchViewController.h"
#import "UsersDevicesViewController.h"
#import "RoomIncomingTextMsgBubbleCell.h"
#import "RoomIncomingTextMsgWithoutSenderInfoBubbleCell.h"
#import "RoomIncomingTextMsgWithPaginationTitleBubbleCell.h"
@ -137,6 +139,9 @@
// Potential encryption details view.
EncryptionInfoView *encryptionInfoView;
// The list of unknown devices that prevent outgoing messages from being sent
MXUsersDevicesMap<MXDeviceInfo*> *unknownDevices;
// Observe kAppDelegateDidTapStatusBarNotification to handle tap on clock status bar.
id kAppDelegateDidTapStatusBarNotificationObserver;
@ -2247,6 +2252,16 @@
selectedContact = nil;
}
}
else if ([[segue identifier] isEqualToString:@"showUnknownDevices"])
{
if (unknownDevices)
{
UsersDevicesViewController *usersDevicesViewController = (UsersDevicesViewController *)segue.destinationViewController.childViewControllers.firstObject;
[usersDevicesViewController displayUsersDevices:unknownDevices andMatrixSession:self.roomDataSource.mxSession];
unknownDevices = nil;
}
}
// Hide back button title
self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
@ -3117,16 +3132,15 @@
style:MXKAlertStyleAlert];
currentAlert.cancelButtonIndex = [currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"cancel"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
typeof(self) self = weakSelf;
self->currentAlert = nil;
}];
[currentAlert addActionWithTitle:[NSBundle mxk_localizedStringForKey:@"unknown_devices_verify"] style:MXKAlertActionStyleDefault handler:^(MXKAlert *alert) {
// @TODO
typeof(self) self = weakSelf;
self->currentAlert = nil;
[self showUnknownDevices];
}];
currentAlert.mxkAccessibilityIdentifier = @"RoomVCUnknownDevicesAlert";
@ -3134,6 +3148,27 @@
}
}
- (void)showUnknownDevices
{
// List all unknown devices
unknownDevices = [[MXUsersDevicesMap alloc] init];
NSArray<MXEvent*> *outgoingMsgs = self.roomDataSource.room.outgoingMessages;
for (MXEvent *event in outgoingMsgs)
{
if (event.sentState == MXEventSentStateFailed
&& [event.sentError.domain isEqualToString:MXEncryptingErrorDomain]
&& event.sentError.code == MXEncryptingErrorUnknownDeviceCode)
{
MXUsersDevicesMap<MXDeviceInfo*> *eventUnknownDevices = event.sentError.userInfo[MXEncryptingErrorUnknownDeviceDevicesKey];
[unknownDevices addEntriesFromMap:eventUnknownDevices];
}
}
[self performSegueWithIdentifier:@"showUnknownDevices" sender:self];
}
- (void)resendAllUnsentMessages
{
// List unsent event ids

View file

@ -0,0 +1,30 @@
/*
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 <MatrixKit/MatrixKit.h>
#import "DeviceTableViewCell.h"
@interface UsersDevicesViewController : MXKTableViewController <UITableViewDelegate, UITableViewDataSource, DeviceTableViewCellDelegate>
/**
Display a map of users/devices.
@param usersDevices the map to display.
*/
- (void)displayUsersDevices:(MXUsersDevicesMap<MXDeviceInfo*>*)usersDevices andMatrixSession:(MXSession*)mxSession;
@end

View file

@ -0,0 +1,236 @@
/*
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 "UsersDevicesViewController.h"
#import "AppDelegate.h"
#import "RageShakeManager.h"
#import "VectorDesignValues.h"
#import "EncryptionInfoView.h"
@interface UsersDevicesViewController ()
{
MXUsersDevicesMap<MXDeviceInfo*> *usersDevices;
MXSession *mxSession;
EncryptionInfoView *encryptionInfoView;
}
@end
@implementation UsersDevicesViewController
- (void)finalizeInit
{
[super finalizeInit];
// Setup `MXKViewControllerHandling` properties
self.defaultBarTintColor = kVectorNavBarTintColor;
self.enableBarTintColorStatusChange = NO;
self.rageShakeManager = [RageShakeManager sharedManager];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.title = NSLocalizedStringFromTable(@"unknown_devices_title", @"Vector", nil);
self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onCancel:)];
self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(onDone:)];
self.tableView.delegate = self;
self.tableView.dataSource = self;
// Register collection view cell class
[self.tableView registerClass:DeviceTableViewCell.class forCellReuseIdentifier:[DeviceTableViewCell defaultReuseIdentifier]];
// Hide line separators of empty cells
self.tableView.tableFooterView = [[UIView alloc] init];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Screen tracking (via Google Analytics)
id<GAITracker> tracker = [[GAI sharedInstance] defaultTracker];
if (tracker)
{
[tracker set:kGAIScreenName value:@"UnknowDevices"];
[tracker send:[[GAIDictionaryBuilder createScreenView] build]];
}
[self.tableView reloadData];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)displayUsersDevices:(MXUsersDevicesMap<MXDeviceInfo*>*)theUsersDevices andMatrixSession:(MXSession*)matrixSession;
{
usersDevices = theUsersDevices;
mxSession = matrixSession;
}
#pragma mark - UITableViewDataSource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return usersDevices.userIds.count;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
{
return usersDevices.userIds[section];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
NSString *userId = usersDevices.userIds[section];
return [usersDevices deviceIdsForUser:userId].count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
MXDeviceInfo *device = [self deviceAtIndexPath:indexPath];
if (device)
{
DeviceTableViewCell *deviceCell = [tableView dequeueReusableCellWithIdentifier:[DeviceTableViewCell defaultReuseIdentifier] forIndexPath:indexPath];
deviceCell.selectionStyle = UITableViewCellSelectionStyleNone;
[deviceCell render:device];
deviceCell.delegate = self;
cell = deviceCell;
}
return cell;
}
#pragma mark - UITableViewDelegate
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
MXDeviceInfo *device = [self deviceAtIndexPath:indexPath];
return [DeviceTableViewCell cellHeightWithDeviceInfo:device andCellWidth:self.tableView.frame.size.width];
}
#pragma mark - DeviceTableViewCellDelegate
- (void)deviceTableViewCell:(DeviceTableViewCell *)deviceTableViewCell updateDeviceVerification:(MXDeviceVerification)verificationStatus
{
if (verificationStatus == MXDeviceVerified)
{
// Prompt the user before marking as verified the device.
encryptionInfoView = [[EncryptionInfoView alloc] initWithDeviceInfo:deviceTableViewCell.deviceInfo andMatrixSession:mxSession];
[encryptionInfoView onButtonPressed:encryptionInfoView.verifyButton];
// 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
[self.view addSubview:encryptionInfoView];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:encryptionInfoView
attribute:NSLayoutAttributeTop
relatedBy:NSLayoutRelationEqual
toItem:self.tableView
attribute:NSLayoutAttributeTop
multiplier:1.0f
constant:10.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:encryptionInfoView
attribute:NSLayoutAttributeBottom
relatedBy:NSLayoutRelationEqual
toItem:self.tableView
attribute:NSLayoutAttributeBottom
multiplier:1.0f
constant:-10.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView
attribute:NSLayoutAttributeLeading
relatedBy:NSLayoutRelationEqual
toItem:encryptionInfoView
attribute:NSLayoutAttributeLeading
multiplier:1.0f
constant:-10.0f]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.tableView
attribute:NSLayoutAttributeTrailing
relatedBy:NSLayoutRelationEqual
toItem:encryptionInfoView
attribute:NSLayoutAttributeTrailing
multiplier:1.0f
constant:10.0f]];
[self.view setNeedsUpdateConstraints];
}
else
{
[mxSession.crypto setDeviceVerification:verificationStatus
forDevice:deviceTableViewCell.deviceInfo.deviceId
ofUser:deviceTableViewCell.deviceInfo.userId
success:^{
deviceTableViewCell.deviceInfo.verified = verificationStatus;
[self.tableView reloadData];
} failure:nil];
}
}
#pragma mark - User actions
- (IBAction)onCancel:(id)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)onDone:(id)sender
{
// Acknowledge the existence of all devices before leaving this screen
[mxSession.crypto setDevicesKnown:usersDevices complete:^{
[self dismissViewControllerAnimated:YES completion:nil];
}];
}
#pragma mark - Private methods
- (MXDeviceInfo*)deviceAtIndexPath:(NSIndexPath *)indexPath
{
NSString *userId = usersDevices.userIds[indexPath.section];
NSString *deviceId = [usersDevices deviceIdsForUser:userId][indexPath.row];
return [usersDevices objectForDevice:deviceId forUser:userId];
}
@end

View file

@ -1,5 +1,6 @@
/*
Copyright 2015 OpenMarket Ltd
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.

View file

@ -1,6 +1,7 @@
/*
Copyright 2015 OpenMarket Ltd
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