diff --git a/CHANGES.md b/CHANGES.md index 88c0155eb..9e42b90fc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,15 @@ +## Changes in 1.9.7 (2022-09-28) + +🙌 Improvements + +- Upgrade MatrixSDK version ([v0.23.19](https://github.com/matrix-org/matrix-ios-sdk/releases/tag/v0.23.19)). + +🐛 Bugfixes + +- Missing decoration for events decrypted with untrusted Megolm sessions ([Security advisory](https://github.com/vector-im/element-ios/security/advisories/GHSA-fm8m-99j7-323g)) +- Fix crash when scrolling chat list ([#6749](https://github.com/vector-im/element-ios/issues/6749)) + + ## Changes in 1.9.6 (2022-09-20) 🙌 Improvements diff --git a/Config/AppVersion.xcconfig b/Config/AppVersion.xcconfig index 160b9dc81..7e347c68e 100644 --- a/Config/AppVersion.xcconfig +++ b/Config/AppVersion.xcconfig @@ -15,5 +15,5 @@ // // Version -MARKETING_VERSION = 1.9.6 -CURRENT_PROJECT_VERSION = 1.9.6 +MARKETING_VERSION = 1.9.7 +CURRENT_PROJECT_VERSION = 1.9.7 diff --git a/Podfile b/Podfile index 78aaa6b7e..ff30fcb7b 100644 --- a/Podfile +++ b/Podfile @@ -16,7 +16,7 @@ use_frameworks! # - `{ :specHash => {sdk spec hash}` to depend on specific pod options (:git => …, :podspec => …) for MatrixSDK repo. Used by Fastfile during CI # # Warning: our internal tooling depends on the name of this variable name, so be sure not to change it -$matrixSDKVersion = '= 0.23.18' +$matrixSDKVersion = '= 0.23.19' # $matrixSDKVersion = :local # $matrixSDKVersion = { :branch => 'develop'} # $matrixSDKVersion = { :specHash => { git: 'https://git.io/fork123', branch: 'fix' } } diff --git a/Riot/Assets/Images.xcassets/Encryption/Contents.json b/Riot/Assets/Images.xcassets/Encryption/Contents.json index da4a164c9..73c00596a 100644 --- a/Riot/Assets/Images.xcassets/Encryption/Contents.json +++ b/Riot/Assets/Images.xcassets/Encryption/Contents.json @@ -1,6 +1,6 @@ { "info" : { - "version" : 1, - "author" : "xcode" + "author" : "xcode", + "version" : 1 } -} \ No newline at end of file +} diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/Contents.json b/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/Contents.json new file mode 100644 index 000000000..d309a9a02 --- /dev/null +++ b/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "encryption_untrusted.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "encryption_untrusted@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "encryption_untrusted@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted.png b/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted.png new file mode 100644 index 000000000..830f9fc3c Binary files /dev/null and b/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted.png differ diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted@2x.png b/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted@2x.png new file mode 100644 index 000000000..f75d4e074 Binary files /dev/null and b/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted@2x.png differ diff --git a/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted@3x.png b/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted@3x.png new file mode 100644 index 000000000..884106c1f Binary files /dev/null and b/Riot/Assets/Images.xcassets/Encryption/encryption_untrusted.imageset/encryption_untrusted@3x.png differ diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 1a55df6d0..98ed00528 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -2573,6 +2573,7 @@ To enable access, tap Settings> Location and select Always"; "room_event_encryption_info_unverify" = "Unverify"; "room_event_encryption_info_block" = "Blacklist"; "room_event_encryption_info_unblock" = "Unblacklist"; +"room_event_encryption_info_key_authenticity_not_guaranteed" = "The authenticity of this encrypted message can't be guaranteed on this device."; "room_event_encryption_verify_title" = "Verify session\n\n"; "room_event_encryption_verify_message" = "To verify that this session can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this session matches the key below:\n\n\tSession name: %@\n\tSession ID: %@\n\tSession key: %@\n\nIf it matches, press the verify button below. If it doesnt, then someone else is intercepting this session and you probably want to press the blacklist button instead.\n\nIn future this verification process will be more sophisticated."; "room_event_encryption_verify_ok" = "Verify"; diff --git a/Riot/Generated/Images.swift b/Riot/Generated/Images.swift index 6fc13773b..af237d6da 100644 --- a/Riot/Generated/Images.swift +++ b/Riot/Generated/Images.swift @@ -112,6 +112,7 @@ internal class Asset: NSObject { internal static let e2eWarning = ImageAsset(name: "e2e_warning") internal static let encryptionNormal = ImageAsset(name: "encryption_normal") internal static let encryptionTrusted = ImageAsset(name: "encryption_trusted") + internal static let encryptionUntrusted = ImageAsset(name: "encryption_untrusted") internal static let encryptionWarning = ImageAsset(name: "encryption_warning") internal static let favouritesEmptyScreenArtwork = ImageAsset(name: "favourites_empty_screen_artwork") internal static let favouritesEmptyScreenArtworkDark = ImageAsset(name: "favourites_empty_screen_artwork_dark") diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 94a7f4631..0a21da1ed 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -5623,6 +5623,10 @@ public class VectorL10n: NSObject { public static var roomEventEncryptionInfoEventUserId: String { return VectorL10n.tr("Vector", "room_event_encryption_info_event_user_id") } + /// The authenticity of this encrypted message can't be guaranteed on this device. + public static var roomEventEncryptionInfoKeyAuthenticityNotGuaranteed: String { + return VectorL10n.tr("Vector", "room_event_encryption_info_key_authenticity_not_guaranteed") + } /// End-to-end encryption information\n\n public static var roomEventEncryptionInfoTitle: String { return VectorL10n.tr("Vector", "room_event_encryption_info_title") diff --git a/Riot/Modules/Home/AllChats/AllChatsViewController.swift b/Riot/Modules/Home/AllChats/AllChatsViewController.swift index d1feec95a..291ea8322 100644 --- a/Riot/Modules/Home/AllChats/AllChatsViewController.swift +++ b/Riot/Modules/Home/AllChats/AllChatsViewController.swift @@ -352,7 +352,7 @@ class AllChatsViewController: HomeViewController { private var initialScrollPosition: Double = 0 private func scrollPosition(of scrollView: UIScrollView) -> Double { - return scrollView.contentOffset.y + scrollView.adjustedContentInset.top + scrollView.adjustedContentInset.bottom + return scrollView.contentOffset.y + scrollView.adjustedContentInset.top } override func scrollViewWillBeginDragging(_ scrollView: UIScrollView) { diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m index 8ee0a6190..c91d51e7a 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m @@ -920,7 +920,7 @@ { for (MXKRoomBubbleComponent *component in bubbleComponents) { - if (component.showEncryptionBadge) + if (component.encryptionDecoration != EventEncryptionDecorationNone) { containsBubbleComponentWithEncryptionBadge = YES; break; diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h index e2f94423e..36bf173e9 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.h @@ -18,6 +18,7 @@ #import "MXKEventFormatter.h" #import "MXKURLPreviewDataProtocol.h" +#import "EventEncryptionDecoration.h" @protocol MXThreadProtocol; @@ -101,9 +102,9 @@ typedef enum : NSUInteger { @property (nonatomic) MXEventScan *eventScan; /** - Indicate if an encryption badge should be shown. + Type of encryption decoration (if any) for this event */ -@property (nonatomic, readonly) BOOL showEncryptionBadge; +@property (nonatomic, readonly) EventEncryptionDecoration encryptionDecoration; /** Thread for the bubble component. Should only exist for thread root events. diff --git a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m index 2e3cf29b8..6d231262c 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m @@ -73,7 +73,7 @@ } } - _showEncryptionBadge = [self shouldShowWarningBadgeForEvent:event roomState:(MXRoomState*)roomState session:session]; + _encryptionDecoration = [self encryptionDecorationForEvent:event roomState:(MXRoomState*)roomState session:session]; [self updateLinkWithRoomState:roomState]; @@ -116,7 +116,7 @@ andLatestRoomState:latestRoomState error:&error]; - _showEncryptionBadge = [self shouldShowWarningBadgeForEvent:event roomState:roomState session:session]; + _encryptionDecoration = [self encryptionDecorationForEvent:event roomState:roomState session:session]; [self updateLinkWithRoomState:roomState]; } @@ -167,24 +167,24 @@ self.link = url; } -- (BOOL)shouldShowWarningBadgeForEvent:(MXEvent*)event roomState:(MXRoomState*)roomState session:(MXSession*)session +- (EventEncryptionDecoration)encryptionDecorationForEvent:(MXEvent*)event roomState:(MXRoomState*)roomState session:(MXSession*)session { // Warning badges are unnecessary in unencrypted rooms if (!roomState.isEncrypted) { - return NO; + return EventEncryptionDecorationNone; } // Not all events are encrypted (e.g. state/reactions/redactions) and we only have encrypted cell subclasses for messages and attachments. if (event.eventType != MXEventTypeRoomMessage && !event.isMediaAttachment) { - return NO; + return EventEncryptionDecorationNone; } // Always show a warning badge if there was a decryption error. if (event.decryptionError) { - return YES; + return EventEncryptionDecorationDecryptionError; } // Unencrypted message events should show a warning unless they're pending local echoes @@ -193,10 +193,10 @@ if (event.isLocalEvent || event.contentHasBeenEdited) // Local echo for an edit is clear but uses a true event id, the one of the edited event { - return NO; + return EventEncryptionDecorationNone; } - return YES; + return EventEncryptionDecorationNotEncrypted; } // The encryption is in a good state. @@ -208,12 +208,17 @@ if (userTrustLevel.isVerified && !deviceInfo.trustLevel.isVerified) { - return YES; + return EventEncryptionDecorationUntrustedDevice; } } + if (event.isUntrusted) + { + return EventEncryptionDecorationUnsafeKey; + } + // Everything was fine - return NO; + return EventEncryptionDecorationNone; } @end diff --git a/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m b/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m index cbaea4f84..878742076 100644 --- a/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m +++ b/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m @@ -192,7 +192,7 @@ static NSAttributedString *verticalWhitespace = nil; NSString *claimedKey = _mxEvent.keysClaimed[@"ed25519"]; NSString *algorithm = _mxEvent.wireContent[@"algorithm"]; NSString *sessionId = _mxEvent.wireContent[@"session_id"]; - NSString *untrusted = _mxEvent.isUntrusted ? [VectorL10n userVerificationSessionsListSessionUntrusted] : [VectorL10n userVerificationSessionsListSessionTrusted]; + NSString *untrusted = _mxEvent.isUntrusted ? [VectorL10n roomEventEncryptionInfoKeyAuthenticityNotGuaranteed] : [VectorL10n userVerificationSessionsListSessionTrusted]; NSString *decryptionError; if (_mxEvent.decryptionError) diff --git a/Riot/Modules/Room/TimelineCells/Encryption/EventEncryptionDecoration.h b/Riot/Modules/Room/TimelineCells/Encryption/EventEncryptionDecoration.h new file mode 100644 index 000000000..f6d4264bd --- /dev/null +++ b/Riot/Modules/Room/TimelineCells/Encryption/EventEncryptionDecoration.h @@ -0,0 +1,30 @@ +// +// Copyright 2022 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. +// + +#ifndef EventEncryptionDecoration_h +#define EventEncryptionDecoration_h + +typedef NS_ENUM(NSUInteger, EventEncryptionDecoration) +{ + EventEncryptionDecorationNone, + EventEncryptionDecorationUnsafeKey, + EventEncryptionDecorationDecryptionError, + EventEncryptionDecorationNotEncrypted, + EventEncryptionDecorationUntrustedDevice +}; + + +#endif /* EventEncryptionDecoration_h */ diff --git a/Riot/Modules/Room/TimelineCells/Encryption/RoomEncryptedDataBubbleCell.m b/Riot/Modules/Room/TimelineCells/Encryption/RoomEncryptedDataBubbleCell.m index 7a5e50ff9..07d23f209 100644 --- a/Riot/Modules/Room/TimelineCells/Encryption/RoomEncryptedDataBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Encryption/RoomEncryptedDataBubbleCell.m @@ -24,12 +24,18 @@ NSString *const kRoomEncryptedDataBubbleCellTapOnEncryptionIcon = @"kRoomEncrypt + (UIImage*)encryptionIconForBubbleComponent:(MXKRoomBubbleComponent *)bubbleComponent { - if (!bubbleComponent.showEncryptionBadge) - { - return nil; + switch (bubbleComponent.encryptionDecoration) { + case EventEncryptionDecorationNone: + return nil; + case EventEncryptionDecorationUnsafeKey: + return AssetImages.encryptionUntrusted.image; + case EventEncryptionDecorationDecryptionError: + case EventEncryptionDecorationNotEncrypted: + case EventEncryptionDecorationUntrustedDevice: + return AssetImages.encryptionWarning.image; + default: + return nil; } - - return AssetImages.encryptionWarning.image; } + (void)addEncryptionStatusFromBubbleData:(MXKRoomBubbleCellData *)bubbleData inContainerView:(UIView *)containerView diff --git a/Riot/Modules/SetPinCode/PinCodePreferences.swift b/Riot/Modules/SetPinCode/PinCodePreferences.swift index a55530f1f..7d73a98ff 100644 --- a/Riot/Modules/SetPinCode/PinCodePreferences.swift +++ b/Riot/Modules/SetPinCode/PinCodePreferences.swift @@ -71,7 +71,15 @@ final class PinCodePreferences: NSObject { } var isBiometricsAvailable: Bool { - return LAContext().canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: nil) + var error: NSError? + let result = LAContext().canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) + + // While in lockout they're still techincally available + if error?.code == LAError.Code.biometryLockout.rawValue { + return true + } + + return result } /// Allowed number of PIN trials before showing forgot help alert