diff --git a/CHANGES.md b/CHANGES.md index 88c0155ebe..9e42b90fcb 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 160b9dc810..7e347c68e6 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 78aaa6b7e7..ff30fcb7b2 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/Podfile.lock b/Podfile.lock index 7f62c51f70..0b53f1a916 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -56,9 +56,9 @@ PODS: - LoggerAPI (1.9.200): - Logging (~> 1.1) - Logging (1.4.0) - - MatrixSDK (0.23.18): - - MatrixSDK/Core (= 0.23.18) - - MatrixSDK/Core (0.23.18): + - MatrixSDK (0.23.19): + - MatrixSDK/Core (= 0.23.19) + - MatrixSDK/Core (0.23.19): - AFNetworking (~> 4.0.0) - GZIP (~> 1.3.0) - libbase58 (~> 0.1.4) @@ -66,9 +66,9 @@ PODS: - OLMKit (~> 3.2.5) - Realm (= 10.27.0) - SwiftyBeaver (= 1.9.5) - - MatrixSDK/CryptoSDK (0.23.18): + - MatrixSDK/CryptoSDK (0.23.19): - MatrixSDKCrypto (= 0.1.0) - - MatrixSDK/JingleCallStack (0.23.18): + - MatrixSDK/JingleCallStack (0.23.19): - JitsiMeetSDK (= 5.0.2) - MatrixSDK/Core - MatrixSDKCrypto (0.1.0) @@ -123,8 +123,8 @@ DEPENDENCIES: - KeychainAccess (~> 4.2.2) - KTCenterFlowLayout (~> 1.3.1) - libPhoneNumber-iOS (~> 0.9.13) - - MatrixSDK (= 0.23.18) - - MatrixSDK/JingleCallStack (= 0.23.18) + - MatrixSDK (= 0.23.19) + - MatrixSDK/JingleCallStack (= 0.23.19) - OLMKit - PostHog (~> 1.4.4) - ReadMoreTextView (~> 3.0.1) @@ -221,7 +221,7 @@ SPEC CHECKSUMS: libPhoneNumber-iOS: 0a32a9525cf8744fe02c5206eb30d571e38f7d75 LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d Logging: beeb016c9c80cf77042d62e83495816847ef108b - MatrixSDK: 26da2e3a9f3b02fc6ea67f5bc311d30f06f9ffba + MatrixSDK: a60a00635006c539dce654253e8f0544ea996111 MatrixSDKCrypto: 4b9146d5ef484550341be056a164c6930038028e OLMKit: da115f16582e47626616874e20f7bb92222c7a51 PostHog: 4b6321b521569092d4ef3a02238d9435dbaeb99f @@ -241,6 +241,6 @@ SPEC CHECKSUMS: zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb -PODFILE CHECKSUM: 45176df406c18b0c23321a308f58535fbe425a93 +PODFILE CHECKSUM: 400334cf1580361b831a632dcc025f2029e56b6e COCOAPODS: 1.11.2 diff --git a/Riot/Assets/Images.xcassets/Encryption/Contents.json b/Riot/Assets/Images.xcassets/Encryption/Contents.json index da4a164c91..73c00596a7 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 0000000000..d309a9a020 --- /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 0000000000..830f9fc3c6 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 0000000000..f75d4e0744 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 0000000000..884106c1f1 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 1a55df6d0f..98ed005285 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 6fc13773b2..af237d6da5 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 94a7f46312..0a21da1ed8 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 d1feec95a5..291ea8322b 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 8ee0a6190f..c91d51e7a3 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleCellData.m @@ -920,7 +920,7 @@ - (BOOL)containsBubbleComponentWithEncryptionBadge { 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 e2f94423e1..36bf173e97 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 2e3cf29b83..6d231262c9 100644 --- a/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m +++ b/Riot/Modules/MatrixKit/Models/Room/MXKRoomBubbleComponent.m @@ -73,7 +73,7 @@ - (instancetype)initWithEvent:(MXEvent*)event } } - _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 @@ - (void)updateWithEvent:(MXEvent*)event 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 @@ - (void)updateLinkWithRoomState:(MXRoomState*)roomState 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 @@ - (BOOL)shouldShowWarningBadgeForEvent:(MXEvent*)event roomState:(MXRoomState*)r 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 @@ - (BOOL)shouldShowWarningBadgeForEvent:(MXEvent*)event roomState:(MXRoomState*)r 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 cbaea4f845..8787420763 100644 --- a/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m +++ b/Riot/Modules/MatrixKit/Views/EncryptionInfoView/MXKEncryptionInfoView.m @@ -192,7 +192,7 @@ - (void)updateTextViewText 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 0000000000..f6d4264bd3 --- /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 7a5e50ff9b..07d23f2098 100644 --- a/Riot/Modules/Room/TimelineCells/Encryption/RoomEncryptedDataBubbleCell.m +++ b/Riot/Modules/Room/TimelineCells/Encryption/RoomEncryptedDataBubbleCell.m @@ -24,12 +24,18 @@ @implementation RoomEncryptedDataBubbleCell + (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 a55530f1f3..7d73a98ff9 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