element-ios/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m

492 lines
25 KiB
Objective-C

/*
Copyright 2016 OpenMarket Ltd
Copyright 2017 Vector Creations Ltd
Copyright 2018 New Vector 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 "MXKEncryptionInfoView.h"
#import "NSBundle+MatrixKit.h"
#import "MXKConstants.h"
#import "MXKSwiftHeader.h"
static NSAttributedString *verticalWhitespace = nil;
@interface MXKEncryptionInfoView ()
{
/**
Current request in progress.
*/
MXHTTPOperation *mxCurrentOperation;
}
@end
@implementation MXKEncryptionInfoView
+ (UINib *)nib
{
// Check whether a nib file is available
NSBundle *mainBundle = [NSBundle mxk_bundleForClass:self.class];
NSString *path = [mainBundle pathForResource:NSStringFromClass([self class]) ofType:@"nib"];
if (path)
{
return [UINib nibWithNibName:NSStringFromClass([self class]) bundle:mainBundle];
}
return [UINib nibWithNibName:NSStringFromClass([MXKEncryptionInfoView class]) bundle:[NSBundle mxk_bundleForClass:[MXKEncryptionInfoView class]]];
}
- (void)awakeFromNib
{
[super awakeFromNib];
// Localize string
[_cancelButton setTitle:[MatrixKitL10n ok] forState:UIControlStateNormal];
[_cancelButton setTitle:[MatrixKitL10n ok] forState:UIControlStateHighlighted];
[_confirmVerifyButton setTitle:[MatrixKitL10n roomEventEncryptionVerifyOk] forState:UIControlStateNormal];
[_confirmVerifyButton setTitle:[MatrixKitL10n roomEventEncryptionVerifyOk] forState:UIControlStateHighlighted];
}
- (void)layoutSubviews
{
[super layoutSubviews];
// Scroll to the top the text view content
self.textView.contentOffset = CGPointZero;
}
- (void)removeFromSuperview
{
if (mxCurrentOperation)
{
[mxCurrentOperation cancel];
mxCurrentOperation = nil;
}
[super removeFromSuperview];
}
#pragma mark - Override MXKView
-(void)customizeViewRendering
{
[super customizeViewRendering];
_defaultTextColor = [UIColor blackColor];
}
#pragma mark -
- (instancetype)initWithEvent:(MXEvent*)event andMatrixSession:(MXSession*)session
{
self = [[[self class] nib] instantiateWithOwner:nil options:nil].firstObject;
if (self)
{
_mxEvent = event;
_mxSession = session;
_mxDeviceInfo = nil;
[self setTranslatesAutoresizingMaskIntoConstraints: NO];
[self updateTextViewText];
}
return self;
}
- (instancetype)initWithDeviceInfo:(MXDeviceInfo*)deviceInfo andMatrixSession:(MXSession*)session
{
self = [[[self class] nib] instantiateWithOwner:nil options:nil].firstObject;
if (self)
{
_mxEvent = nil;
_mxDeviceInfo = deviceInfo;
_mxSession = session;
[self setTranslatesAutoresizingMaskIntoConstraints: NO];
[self updateTextViewText];
}
return self;
}
- (void)dealloc
{
_mxEvent = nil;
_mxSession = nil;
_mxDeviceInfo = nil;
}
#pragma mark -
- (void)updateTextViewText
{
// Prepare the text view content
NSMutableAttributedString *textViewAttributedString = [[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoTitle]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:17]}];
if (_mxEvent)
{
NSString *senderId = _mxEvent.sender;
if (_mxSession && _mxSession.crypto && !_mxDeviceInfo)
{
_mxDeviceInfo = [_mxSession.crypto eventDeviceInfo:_mxEvent];
if (!_mxDeviceInfo)
{
// Trigger a server request to get the device information for the event sender
mxCurrentOperation = [_mxSession.crypto downloadKeys:@[senderId] forceDownload:NO success:^(MXUsersDevicesMap<MXDeviceInfo *> *usersDevicesInfoMap, NSDictionary<NSString *,MXCrossSigningInfo *> *crossSigningKeysMap) {
self->mxCurrentOperation = nil;
// Sanity check: check whether some device information has been retrieved.
self->_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent];
if (self.mxDeviceInfo)
{
[self updateTextViewText];
}
} failure:^(NSError *error) {
self->mxCurrentOperation = nil;
MXLogDebug(@"[MXKEncryptionInfoView] Crypto failed to download device info for user: %@", self.mxEvent.sender);
// Notify MatrixKit user
NSString *myUserId = self.mxSession.myUser.userId;
[[NSNotificationCenter defaultCenter] postNotificationName:kMXKErrorNotification object:error userInfo:myUserId ? @{kMXKErrorUserIdKey: myUserId} : nil];
}];
}
}
// Event information
NSMutableAttributedString *eventInformationString = [[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoEvent]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:15]}];
[eventInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
NSString *senderKey = _mxEvent.senderKey;
NSString *claimedKey = _mxEvent.keysClaimed[@"ed25519"];
NSString *algorithm = _mxEvent.wireContent[@"algorithm"];
NSString *sessionId = _mxEvent.wireContent[@"session_id"];
NSString *decryptionError;
if (_mxEvent.decryptionError)
{
decryptionError = [NSString stringWithFormat:@"** %@ **", _mxEvent.decryptionError.localizedDescription];
}
if (!senderKey.length)
{
senderKey = [MatrixKitL10n roomEventEncryptionInfoEventNone];
}
if (!claimedKey.length)
{
claimedKey = [MatrixKitL10n roomEventEncryptionInfoEventNone];
}
if (!algorithm.length)
{
algorithm = [MatrixKitL10n roomEventEncryptionInfoEventUnencrypted];
}
if (!sessionId.length)
{
sessionId = [MatrixKitL10n roomEventEncryptionInfoEventNone];
}
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoEventUserId] attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:senderId
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoEventIdentityKey]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:senderKey
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoEventFingerprintKey]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:claimedKey
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoEventAlgorithm]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:algorithm
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
if (decryptionError.length)
{
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoEventDecryptionError]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:decryptionError
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
}
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoEventSessionId]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:sessionId
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[eventInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
[textViewAttributedString appendAttributedString:eventInformationString];
}
// Device information
NSMutableAttributedString *deviceInformationString = [[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDevice]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:15]}];
[deviceInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
if (_mxDeviceInfo)
{
NSString *name = _mxDeviceInfo.displayName;
NSString *deviceId = _mxDeviceInfo.deviceId;
NSMutableAttributedString *verification;
NSString *fingerprint = _mxDeviceInfo.fingerprint;
// Display here the Verify and Block buttons except if the device is the current one.
_verifyButton.hidden = _blockButton.hidden = [_mxDeviceInfo.deviceId isEqualToString:_mxSession.matrixRestClient.credentials.deviceId];
switch (_mxDeviceInfo.trustLevel.localVerificationStatus)
{
case MXDeviceUnknown:
case MXDeviceUnverified:
{
verification = [[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDeviceNotVerified]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}];
[_verifyButton setTitle:[MatrixKitL10n roomEventEncryptionInfoVerify] forState:UIControlStateNormal];
[_verifyButton setTitle:[MatrixKitL10n roomEventEncryptionInfoVerify] forState:UIControlStateHighlighted];
[_blockButton setTitle:[MatrixKitL10n roomEventEncryptionInfoBlock] forState:UIControlStateNormal];
[_blockButton setTitle:[MatrixKitL10n roomEventEncryptionInfoBlock] forState:UIControlStateHighlighted];
break;
}
case MXDeviceVerified:
{
verification = [[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDeviceVerified]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}];
[_verifyButton setTitle:[MatrixKitL10n roomEventEncryptionInfoUnverify] forState:UIControlStateNormal];
[_verifyButton setTitle:[MatrixKitL10n roomEventEncryptionInfoUnverify] forState:UIControlStateHighlighted];
[_blockButton setTitle:[MatrixKitL10n roomEventEncryptionInfoBlock] forState:UIControlStateNormal];
[_blockButton setTitle:[MatrixKitL10n roomEventEncryptionInfoBlock] forState:UIControlStateHighlighted];
break;
}
case MXDeviceBlocked:
{
verification = [[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDeviceBlocked]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}];
[_verifyButton setTitle:[MatrixKitL10n roomEventEncryptionInfoVerify] forState:UIControlStateNormal];
[_verifyButton setTitle:[MatrixKitL10n roomEventEncryptionInfoVerify] forState:UIControlStateHighlighted];
[_blockButton setTitle:[MatrixKitL10n roomEventEncryptionInfoUnblock] forState:UIControlStateNormal];
[_blockButton setTitle:[MatrixKitL10n roomEventEncryptionInfoUnblock] forState:UIControlStateHighlighted];
break;
}
default:
break;
}
[deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDeviceName]
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:(name.length ? name : @"")
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[deviceInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
[deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDeviceId] attributes:@{NSForegroundColorAttributeName: _defaultTextColor, NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:deviceId
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[deviceInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
[deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDeviceVerification] attributes:@{NSForegroundColorAttributeName: _defaultTextColor, NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[deviceInformationString appendAttributedString:verification];
[deviceInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
[deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDeviceFingerprint] attributes:@{NSForegroundColorAttributeName: _defaultTextColor, NSFontAttributeName: [UIFont boldSystemFontOfSize:14]}]];
[deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:fingerprint
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
[deviceInformationString appendAttributedString:[MXKEncryptionInfoView verticalWhitespace]];
}
else
{
// Unknown device
[deviceInformationString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionInfoDeviceUnknown] attributes:@{NSForegroundColorAttributeName: _defaultTextColor, NSFontAttributeName: [UIFont italicSystemFontOfSize:14]}]];
}
[textViewAttributedString appendAttributedString:deviceInformationString];
self.textView.attributedText = textViewAttributedString;
}
+ (NSAttributedString *)verticalWhitespace
{
if (verticalWhitespace == nil)
{
verticalWhitespace = [[NSAttributedString alloc] initWithString:@"\n\n" attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:4]}];
}
return verticalWhitespace;
}
#pragma mark - Actions
- (IBAction)onButtonPressed:(id)sender
{
if (sender == _cancelButton)
{
[self removeFromSuperview];
if ([_delegate respondsToSelector:@selector(encryptionInfoViewDidClose:)])
{
[_delegate encryptionInfoViewDidClose:self];
}
}
// Note: Verify and Block buttons are hidden when the deviceInfo is not available
else if (sender == _confirmVerifyButton && _mxDeviceInfo)
{
[_mxSession.crypto setDeviceVerification:MXDeviceVerified forDevice:_mxDeviceInfo.deviceId ofUser:_mxDeviceInfo.userId success:^{
// Refresh data
_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent];
if (self->_delegate)
{
[self->_delegate encryptionInfoView:self didDeviceInfoVerifiedChange:self.mxDeviceInfo];
}
[self removeFromSuperview];
} failure:^(NSError *error) {
[self removeFromSuperview];
}];
}
else if (_mxDeviceInfo)
{
MXDeviceVerification verificationStatus;
if (sender == _verifyButton)
{
verificationStatus = ((_mxDeviceInfo.trustLevel.localVerificationStatus == MXDeviceVerified) ? MXDeviceUnverified : MXDeviceVerified);
}
else if (sender == _blockButton)
{
verificationStatus = ((_mxDeviceInfo.trustLevel.localVerificationStatus == MXDeviceBlocked) ? MXDeviceUnverified : MXDeviceBlocked);
}
else
{
// Unexpected case
MXLogDebug(@"[MXKEncryptionInfoView] Invalid button pressed.");
return;
}
if (verificationStatus == MXDeviceVerified)
{
// Prompt user
NSMutableAttributedString *textViewAttributedString = [[NSMutableAttributedString alloc]
initWithString:[MatrixKitL10n roomEventEncryptionVerifyTitle] attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont boldSystemFontOfSize:17]}];
NSString *message = [MatrixKitL10n roomEventEncryptionVerifyMessage:_mxDeviceInfo.displayName :_mxDeviceInfo.deviceId :_mxDeviceInfo.fingerprint];
[textViewAttributedString appendAttributedString:[[NSMutableAttributedString alloc]
initWithString:message
attributes:@{NSForegroundColorAttributeName: _defaultTextColor,
NSFontAttributeName: [UIFont systemFontOfSize:14]}]];
self.textView.attributedText = textViewAttributedString;
[_cancelButton setTitle:[MatrixKitL10n cancel] forState:UIControlStateNormal];
[_cancelButton setTitle:[MatrixKitL10n cancel] forState:UIControlStateHighlighted];
_verifyButton.hidden = _blockButton.hidden = YES;
_confirmVerifyButton.hidden = NO;
}
else
{
[_mxSession.crypto setDeviceVerification:verificationStatus forDevice:_mxDeviceInfo.deviceId ofUser:_mxDeviceInfo.userId success:^{
// Refresh data
_mxDeviceInfo = [self.mxSession.crypto eventDeviceInfo:self.mxEvent];
if (self->_delegate)
{
[self->_delegate encryptionInfoView:self didDeviceInfoVerifiedChange:self.mxDeviceInfo];
}
[self removeFromSuperview];
} failure:^(NSError *error) {
[self removeFromSuperview];
}];
}
}
}
@end