From 96afe1b1b0fe9dab8782f3d400c4e660957cb15f Mon Sep 17 00:00:00 2001 From: manuroe Date: Fri, 3 Mar 2017 13:07:18 +0100 Subject: [PATCH] e2e: Add global and per-room settings to blacklist unverified devices --- Vector/Assets/en.lproj/Vector.strings | 2 + .../RoomSettingsViewController.m | 176 +++++++++++++----- .../ViewController/SettingsViewController.m | 85 ++++++--- 3 files changed, 189 insertions(+), 74 deletions(-) diff --git a/Vector/Assets/en.lproj/Vector.strings b/Vector/Assets/en.lproj/Vector.strings index eefc5e945..ed464f413 100644 --- a/Vector/Assets/en.lproj/Vector.strings +++ b/Vector/Assets/en.lproj/Vector.strings @@ -309,6 +309,7 @@ "settings_crypto_device_id" = "\nDevice ID: "; "settings_crypto_device_key" = "\nDevice key: "; "settings_crypto_export" = "Export keys"; +"settings_crypto_blacklist_unverified_devices" = "Encrypt to verified devices only"; // Room Details "room_details_title" = "Room Details"; @@ -348,6 +349,7 @@ "room_details_advanced_enable_e2e_encryption"="Enable encryption (warning: cannot be disabled again!)"; "room_details_advanced_e2e_encryption_enabled"="Encryption is enabled in this room"; "room_details_advanced_e2e_encryption_disabled"="Encryption is not enabled in this room."; +"room_details_advanced_e2e_encryption_blacklist_unverified_devices"="Encrypt to verified devices only"; "room_details_advanced_e2e_encryption_prompt_title"="Warning!"; "room_details_advanced_e2e_encryption_prompt_message"="End-to-end encryption is experimental and may not be reliable.\n\nYou should not yet trust it to secure data.\n\nDevices will not yet be able to decrypt history from before they joined the room.\n\nOnce encryption is enabled for a room it cannot be turned off again (for now).\n\nEncrypted messages will not be visible on clients that do not yet implement encryption."; "room_details_fail_to_update_avatar" = "Fail to update the room photo"; diff --git a/Vector/ViewController/RoomSettingsViewController.m b/Vector/ViewController/RoomSettingsViewController.m index 57ddce349..074a0f5bd 100644 --- a/Vector/ViewController/RoomSettingsViewController.m +++ b/Vector/ViewController/RoomSettingsViewController.m @@ -81,6 +81,7 @@ NSString *const kRoomSettingsNewAliasesKey = @"kRoomSettingsNewAliasesKey"; NSString *const kRoomSettingsRemovedAliasesKey = @"kRoomSettingsRemovedAliasesKey"; NSString *const kRoomSettingsCanonicalAliasKey = @"kRoomSettingsCanonicalAliasKey"; NSString *const kRoomSettingsEncryptionKey = @"kRoomSettingsEncryptionKey"; +NSString *const kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey = @"kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey"; NSString *const kRoomSettingsNameCellViewIdentifier = @"kRoomSettingsNameCellViewIdentifier"; NSString *const kRoomSettingsTopicCellViewIdentifier = @"kRoomSettingsTopicCellViewIdentifier"; @@ -142,6 +143,7 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti // switches UISwitch *roomNotifSwitch; UISwitch *roomEncryptionSwitch; + UISwitch *roomEncryptionBlacklistUnverifiedDevicesSwitch; // Observe kAppDelegateDidTapStatusBarNotification to handle tap on clock status bar. id appDelegateDidTapStatusBarNotificationObserver; @@ -1632,6 +1634,13 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti return; } + + // Room settings on blacklist unverified devices + if ([updatedItemsDict objectForKey:kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) + { + BOOL blacklistUnverifiedDevices = [((NSNumber*)updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) boolValue]; + [mxRoom.mxSession.crypto setBlacklistUnverifiedDevicesInRoom:mxRoom.roomId blacklist:blacklistUnverifiedDevices]; + } } [self getNavigationItem].rightBarButtonItem.enabled = NO; @@ -1749,6 +1758,11 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti if (mxRoom.mxSession.crypto) { count++; + + if (mxRoom.state.isEncrypted) + { + count++; + } } } @@ -2068,6 +2082,10 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti { roomNotifSwitch = nil; } + else if (roomEncryptionBlacklistUnverifiedDevicesSwitch == directoryVisibilitySwitch) + { + roomEncryptionBlacklistUnverifiedDevicesSwitch = nil; + } [directoryVisibilitySwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; directoryVisibilitySwitch.onTintColor = kVectorColorGreen; @@ -2330,9 +2348,54 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti cell.selectionStyle = UITableViewCellSelectionStyleNone; } - else if (indexPath.row == 1) + else if (mxRoom.state.isEncrypted) { - if (mxRoom.state.isEncrypted) + if (indexPath.row == 1) + { + MXKTableViewCellWithLabelAndSwitch *roomBlacklistUnverifiedDevicesCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; + + roomBlacklistUnverifiedDevicesCell.mxkLabelLeadingConstraint.constant = roomBlacklistUnverifiedDevicesCell.separatorInset.left; + roomBlacklistUnverifiedDevicesCell.mxkSwitchTrailingConstraint.constant = 15; + + [roomBlacklistUnverifiedDevicesCell.mxkSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; + roomBlacklistUnverifiedDevicesCell.mxkSwitch.onTintColor = kVectorColorGreen; + + roomBlacklistUnverifiedDevicesCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_blacklist_unverified_devices", @"Vector", nil); + roomBlacklistUnverifiedDevicesCell.mxkLabel.textColor = kVectorTextColorBlack; + + roomEncryptionBlacklistUnverifiedDevicesSwitch = roomBlacklistUnverifiedDevicesCell.mxkSwitch; + + // Workaround to avoid mixing between switches + // TODO: this is a design issue with switch within UITableViewCell that must fix everywhere + if (directoryVisibilitySwitch == roomEncryptionBlacklistUnverifiedDevicesSwitch) + { + directoryVisibilitySwitch = nil; + } + else if (roomNotifSwitch == roomEncryptionBlacklistUnverifiedDevicesSwitch) + { + roomNotifSwitch = nil; + } + else if (roomEncryptionSwitch == roomEncryptionBlacklistUnverifiedDevicesSwitch) + { + roomEncryptionSwitch = nil; + } + + // For the switch value, use first the changed value made by the user, then the value used by the crypto + BOOL blacklistUnverifiedDevices; + if ([updatedItemsDict objectForKey:kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) + { + blacklistUnverifiedDevices = [((NSNumber*)updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]) boolValue]; + } + else + { + blacklistUnverifiedDevices = [mxRoom.mxSession.crypto isBlacklistUnverifiedDevicesInRoom:mxRoom.roomId]; + } + + roomEncryptionBlacklistUnverifiedDevicesSwitch.on = blacklistUnverifiedDevices; + + cell = roomBlacklistUnverifiedDevicesCell; + } + else if (indexPath.row == 2) { cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier]; if (!cell) @@ -2347,57 +2410,61 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti cell.selectionStyle = UITableViewCellSelectionStyleNone; } + } + else + { + // Check user's power level to know whether the user is allowed to turn on the encryption mode + MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels]; + NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; + + if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomEncryption]) + { + MXKTableViewCellWithLabelAndSwitch *roomEncryptionCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; + + roomEncryptionCell.mxkLabelLeadingConstraint.constant = roomEncryptionCell.separatorInset.left; + roomEncryptionCell.mxkSwitchTrailingConstraint.constant = 15; + + [roomEncryptionCell.mxkSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; + roomEncryptionCell.mxkSwitch.onTintColor = kVectorColorGreen; + + roomEncryptionCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_enable_e2e_encryption", @"Vector", nil); + roomEncryptionCell.mxkLabel.textColor = kVectorTextColorBlack; + + roomEncryptionSwitch = roomEncryptionCell.mxkSwitch; + + // Workaround to avoid mixing between switches + // TODO: this is a design issue with switch within UITableViewCell that must fix everywhere + if (directoryVisibilitySwitch == roomEncryptionSwitch) + { + directoryVisibilitySwitch = nil; + } + else if (roomNotifSwitch == roomEncryptionSwitch) + { + roomNotifSwitch = nil; + } + else if (roomEncryptionBlacklistUnverifiedDevicesSwitch == roomEncryptionSwitch) + { + roomEncryptionBlacklistUnverifiedDevicesSwitch = nil; + } + + roomEncryptionSwitch.on = ([updatedItemsDict objectForKey:kRoomSettingsEncryptionKey] != nil); + + cell = roomEncryptionCell; + } else { - // Check user's power level to know whether the user is allowed to turn on the encryption mode - MXRoomPowerLevels *powerLevels = [mxRoom.state powerLevels]; - NSInteger oneSelfPowerLevel = [powerLevels powerLevelOfUserWithUserID:self.mainSession.myUser.userId]; - - if (oneSelfPowerLevel >= [powerLevels minimumPowerLevelForSendingEventAsStateEvent:kMXEventTypeStringRoomEncryption]) + cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier]; + if (!cell) { - MXKTableViewCellWithLabelAndSwitch *roomEncryptionCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithLabelAndSwitch defaultReuseIdentifier] forIndexPath:indexPath]; - - roomEncryptionCell.mxkLabelLeadingConstraint.constant = roomEncryptionCell.separatorInset.left; - roomEncryptionCell.mxkSwitchTrailingConstraint.constant = 15; - - [roomEncryptionCell.mxkSwitch addTarget:self action:@selector(onSwitchUpdate:) forControlEvents:UIControlEventValueChanged]; - roomEncryptionCell.mxkSwitch.onTintColor = kVectorColorGreen; - - roomEncryptionCell.mxkLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_enable_e2e_encryption", @"Vector", nil); - roomEncryptionCell.mxkLabel.textColor = kVectorTextColorBlack; - - roomEncryptionSwitch = roomEncryptionCell.mxkSwitch; - - // Workaround to avoid mixing between switches - // TODO: this is a design issue with switch within UITableViewCell that must fix everywhere - if (directoryVisibilitySwitch == roomEncryptionSwitch) - { - directoryVisibilitySwitch = nil; - } - else if (roomNotifSwitch == roomEncryptionSwitch) - { - roomNotifSwitch = nil; - } - - roomEncryptionSwitch.on = ([updatedItemsDict objectForKey:kRoomSettingsEncryptionKey] != nil); - - cell = roomEncryptionCell; - } - else - { - cell = [tableView dequeueReusableCellWithIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier]; - if (!cell) - { - cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier]; - } - - cell.textLabel.font = [UIFont systemFontOfSize:17]; - cell.textLabel.numberOfLines = 0; - cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_disabled", @"Vector", nil); - cell.textLabel.textColor = kVectorTextColorBlack; - - cell.selectionStyle = UITableViewCellSelectionStyleNone; + cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:kRoomSettingsAdvancedE2eEnabledCellViewIdentifier]; } + + cell.textLabel.font = [UIFont systemFontOfSize:17]; + cell.textLabel.numberOfLines = 0; + cell.textLabel.text = NSLocalizedStringFromTable(@"room_details_advanced_e2e_encryption_disabled", @"Vector", nil); + cell.textLabel.textColor = kVectorTextColorBlack; + + cell.selectionStyle = UITableViewCellSelectionStyleNone; } } } @@ -3010,6 +3077,17 @@ NSString *const kRoomSettingsAdvancedE2eEnabledCellViewIdentifier = @"kRoomSetti [updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionKey]; } } + else if (theSwitch == roomEncryptionBlacklistUnverifiedDevicesSwitch) + { + if ([mxRoom.mxSession.crypto isBlacklistUnverifiedDevicesInRoom:mxRoom.roomId] != roomEncryptionBlacklistUnverifiedDevicesSwitch.on) + { + updatedItemsDict[kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey] = @(roomEncryptionBlacklistUnverifiedDevicesSwitch.on); + } + else + { + [updatedItemsDict removeObjectForKey:kRoomSettingsEncryptionBlacklistUnverifiedDevicesKey]; + } + } [self getNavigationItem].rightBarButtonItem.enabled = (updatedItemsDict.count != 0); } diff --git a/Vector/ViewController/SettingsViewController.m b/Vector/ViewController/SettingsViewController.m index 79b07a850..c2c5571ca 100644 --- a/Vector/ViewController/SettingsViewController.m +++ b/Vector/ViewController/SettingsViewController.m @@ -40,7 +40,8 @@ NSString* const kSettingsViewControllerPhoneBookCountryCellId = @"kSettingsViewControllerPhoneBookCountryCellId"; -enum { +enum +{ SETTINGS_SECTION_SIGN_OUT_INDEX = 0, SETTINGS_SECTION_USER_SETTINGS_INDEX, SETTINGS_SECTION_NOTIFICATIONS_SETTINGS_INDEX, @@ -54,33 +55,45 @@ enum { SETTINGS_SECTION_COUNT }; -#define NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX 0 -#define NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX 1 -//#define NOTIFICATION_SETTINGS_CONTAINING_MY_USER_NAME_INDEX 1 -//#define NOTIFICATION_SETTINGS_CONTAINING_MY_DISPLAY_NAME_INDEX 2 -//#define NOTIFICATION_SETTINGS_SENT_TO_ME_INDEX 3 -//#define NOTIFICATION_SETTINGS_INVITED_TO_ROOM_INDEX 4 -//#define NOTIFICATION_SETTINGS_PEOPLE_LEAVE_JOIN_INDEX 5 -//#define NOTIFICATION_SETTINGS_CALL_INVITATION_INDEX 6 -#define NOTIFICATION_SETTINGS_COUNT 2 +enum +{ + NOTIFICATION_SETTINGS_ENABLE_PUSH_INDEX = 0, + NOTIFICATION_SETTINGS_GLOBAL_SETTINGS_INDEX, + //NOTIFICATION_SETTINGS_CONTAINING_MY_USER_NAME_INDEX, + //NOTIFICATION_SETTINGS_CONTAINING_MY_DISPLAY_NAME_INDEX, + //NOTIFICATION_SETTINGS_SENT_TO_ME_INDEX, + //NOTIFICATION_SETTINGS_INVITED_TO_ROOM_INDEX, + //NOTIFICATION_SETTINGS_PEOPLE_LEAVE_JOIN_INDEX, + //NOTIFICATION_SETTINGS_CALL_INVITATION_INDEX, + NOTIFICATION_SETTINGS_COUNT +}; -#define OTHER_VERSION_INDEX 0 -#define OTHER_OLM_VERSION_INDEX 1 -#define OTHER_COPYRIGHT_INDEX 2 -#define OTHER_TERM_CONDITIONS_INDEX 3 -#define OTHER_PRIVACY_INDEX 4 -#define OTHER_THIRD_PARTY_INDEX 5 -#define OTHER_CRASH_REPORT_INDEX 6 -#define OTHER_MARK_ALL_AS_READ_INDEX 7 -#define OTHER_CLEAR_CACHE_INDEX 8 -#define OTHER_COUNT 9 +enum +{ + OTHER_VERSION_INDEX = 0, + OTHER_OLM_VERSION_INDEX, + OTHER_COPYRIGHT_INDEX, + OTHER_TERM_CONDITIONS_INDEX, + OTHER_PRIVACY_INDEX, + OTHER_THIRD_PARTY_INDEX, + OTHER_CRASH_REPORT_INDEX, + OTHER_MARK_ALL_AS_READ_INDEX, + OTHER_CLEAR_CACHE_INDEX, + OTHER_COUNT +}; -#define LABS_CRYPTO_INDEX 0 -#define LABS_COUNT 1 +enum +{ + LABS_CRYPTO_INDEX = 0, + LABS_COUNT +}; -#define CRYPTOGRAPHY_INFO_INDEX 0 -#define CRYPTOGRAPHY_EXPORT_INDEX 1 -#define CRYPTOGRAPHY_COUNT 2 +enum { + CRYPTOGRAPHY_INFO_INDEX = 0, + CRYPTOGRAPHY_BLACKLIST_UNVERIFIED_DEVICES_INDEX, + CRYPTOGRAPHY_EXPORT_INDEX, + CRYPTOGRAPHY_COUNT +}; #define SECTION_TITLE_PADDING_WHEN_HIDDEN 0.01f @@ -1665,6 +1678,18 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); cell = cryptoCell; } + else if (row == CRYPTOGRAPHY_BLACKLIST_UNVERIFIED_DEVICES_INDEX) + { + MXKTableViewCellWithLabelAndSwitch* labelAndSwitchCell = [self getLabelAndSwitchCell:tableView forIndexPath:indexPath]; + + labelAndSwitchCell.mxkLabel.text = NSLocalizedStringFromTable(@"settings_crypto_blacklist_unverified_devices", @"Vector", nil); + labelAndSwitchCell.mxkSwitch.on = account.mxSession.crypto.globalBlacklistUnverifiedDevices; + labelAndSwitchCell.mxkSwitch.enabled = YES; + [labelAndSwitchCell.mxkSwitch removeTarget:self action:nil forControlEvents:UIControlEventTouchUpInside]; + [labelAndSwitchCell.mxkSwitch addTarget:self action:@selector(toggleBlacklistUnverifiedDevices:) forControlEvents:UIControlEventTouchUpInside]; + + cell = labelAndSwitchCell; + } else if (row == CRYPTOGRAPHY_EXPORT_INDEX) { MXKTableViewCellWithButton *exportKeysBtnCell = [tableView dequeueReusableCellWithIdentifier:[MXKTableViewCellWithButton defaultReuseIdentifier]]; @@ -2357,6 +2382,16 @@ typedef void (^blockSettingsViewController_onReadyToDestroy)(); } } +- (void)toggleBlacklistUnverifiedDevices:(id)sender +{ + UISwitch *switchButton = (UISwitch*)sender; + + MXKAccount* account = [MXKAccountManager sharedManager].activeAccounts.firstObject; + account.mxSession.crypto.globalBlacklistUnverifiedDevices = switchButton.on; + + [self.tableView reloadData]; +} + - (void)markAllAsRead:(id)sender { // Feedback: disable button and run activity indicator