Merge branch 'develop' into ismail/6181_auth_soft_logout

This commit is contained in:
ismailgulek
2022-06-09 15:46:29 +03:00
16 changed files with 127 additions and 52 deletions
+5 -5
View File
@@ -563,7 +563,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
self.setPinCoordinatorBridgePresenter = [[SetPinCoordinatorBridgePresenter alloc] initWithSession:mxSessionArray.firstObject viewMode:SetPinCoordinatorViewModeInactive];
self.setPinCoordinatorBridgePresenter.delegate = self;
[self.setPinCoordinatorBridgePresenter presentIn:self.window];
[self.setPinCoordinatorBridgePresenter presentWithMainAppWindow:self.window];
}
}
@@ -663,12 +663,12 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
{
self.setPinCoordinatorBridgePresenter = [[SetPinCoordinatorBridgePresenter alloc] initWithSession:mxSessionArray.firstObject viewMode:SetPinCoordinatorViewModeUnlock];
self.setPinCoordinatorBridgePresenter.delegate = self;
[self.setPinCoordinatorBridgePresenter presentIn:self.window];
[self.setPinCoordinatorBridgePresenter presentWithMainAppWindow:self.window];
}
}
else
{
[self.setPinCoordinatorBridgePresenter dismiss];
[self.setPinCoordinatorBridgePresenter dismissWithMainAppWindow:self.window];
self.setPinCoordinatorBridgePresenter = nil;
[self afterAppUnlockedByPin:application];
}
@@ -4476,7 +4476,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
- (void)setPinCoordinatorBridgePresenterDelegateDidComplete:(SetPinCoordinatorBridgePresenter *)coordinatorBridgePresenter
{
[coordinatorBridgePresenter dismiss];
[coordinatorBridgePresenter dismissWithMainAppWindow:self.window];
self.setPinCoordinatorBridgePresenter = nil;
[self afterAppUnlockedByPin:[UIApplication sharedApplication]];
}
@@ -4490,7 +4490,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
}
else
{
[coordinatorBridgePresenter dismiss];
[coordinatorBridgePresenter dismissWithMainAppWindow:self.window];
self.setPinCoordinatorBridgePresenter = nil;
[self logoutWithConfirmation:NO completion:nil];
}
@@ -149,6 +149,10 @@ extension LegacyAuthenticationCoordinator: AuthenticationServiceDelegate {
authenticationViewController.showCustomHomeserver(homeserver, andIdentityServer: identityServer)
}
}
func authenticationService(_ service: AuthenticationService, needsPromptFor unrecognizedCertificate: Data?, completion: @escaping (Bool) -> Void) {
// Handled internally in AuthenticationViewController
}
}
// MARK: - AuthenticationViewControllerDelegate
@@ -34,10 +34,6 @@
{
[super awakeFromNib];
// Round room image view
[_roomAvatar.layer setCornerRadius:_roomAvatar.frame.size.width / 2];
_roomAvatar.clipsToBounds = YES;
// Disable the user interaction on the room avatar.
self.roomAvatar.userInteractionEnabled = NO;
@@ -73,6 +69,9 @@
- (void)layoutSubviews
{
[super layoutSubviews];
[self.roomAvatar.layer setCornerRadius:self.roomAvatar.frame.size.width / 2.0];
[self.roomAvatar setClipsToBounds: YES];
}
- (void)render:(MXKCellData *)cellData
@@ -223,23 +223,11 @@ typedef enum : NSUInteger {
@param htmlString the HTLM string to render.
@param event the event associated to the string.
@param roomState the room state right before the event.
@param roomState the room state right before the event. If nil, replies will not get constructed or formatted.
@return an attributed string.
*/
- (NSAttributedString*)renderHTMLString:(NSString*)htmlString forEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState;
/**
Render a random html string into an attributed string with the font and the text color
that correspond to the passed event.
@param htmlString the HTLM string to render.
@param event the event associated to the string.
@param roomState the room state right before the event.
@param isEditMode wether string will be used for edition in the composer
@return an attributed string.
*/
- (NSAttributedString*)renderHTMLString:(NSString*)htmlString forEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState isEditMode:(BOOL)isEditMode;
/**
Defines the replacement attributed string for a redacted message.
@@ -1750,18 +1750,12 @@ static NSString *const kHTMLATagRegexPattern = @"<a href=(?:'|\")(.*?)(?:'|\")>(
}
- (NSAttributedString*)renderHTMLString:(NSString*)htmlString forEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState
{
return [self renderHTMLString:htmlString forEvent:event withRoomState:roomState isEditMode:NO];
}
- (NSAttributedString*)renderHTMLString:(NSString*)htmlString forEvent:(MXEvent*)event withRoomState:(MXRoomState*)roomState isEditMode:(BOOL)isEditMode
{
NSString *html = htmlString;
MXEvent *repliedEvent;
// Special treatment for "In reply to" message
// Note: `isEditMode` fixes an issue where editing a reply would display an "In reply to" span instead of a mention.
if (!isEditMode && (event.isReplyEvent || (!RiotSettings.shared.enableThreads && event.isInThread)))
if (roomState && (event.isReplyEvent || (!RiotSettings.shared.enableThreads && event.isInThread)))
{
repliedEvent = [self->mxSession.store eventWithEventId:event.relatesTo.inReplyTo.eventId inRoom:roomState.roomId];
if (repliedEvent)
@@ -181,6 +181,38 @@ final class AuthenticationCoordinator: NSObject, AuthenticationCoordinatorProtoc
toPresentable().present(alert, animated: true)
}
/// Prompts the user to trust a certificate by displaying its fingerprint (SHA256).
@MainActor private func displayUnrecognizedCertificateAlert(for certificate: Data) async -> Bool {
await withCheckedContinuation { continuation in
let title = VectorL10n.sslCouldNotVerify
let homeserverURLString = VectorL10n.sslHomeserverUrl(authenticationService.state.homeserver.displayableAddress)
let fingerprint = VectorL10n.sslFingerprintHash("SHA256")
let certificateFingerprint = (certificate as NSData).mx_SHA256AsHexString() ?? VectorL10n.error
let message = [VectorL10n.sslCertNotTrust,
VectorL10n.sslCertNewAccountExpl,
homeserverURLString,
fingerprint,
certificateFingerprint,
VectorL10n.sslOnlyAccept]
.joined(separator: "\n\n")
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: VectorL10n.cancel, style: .cancel) { action in
continuation.resume(with: .success(false))
})
alert.addAction(UIAlertAction(title: VectorL10n.sslTrust, style: .default) { action in
continuation.resume(with: .success(true))
})
// The alert will be encountered on the current stack or when server selection is being presented.
let presentingViewController = toPresentable().presentedViewController ?? toPresentable()
presentingViewController.present(alert, animated: true, completion: nil)
}
}
/// Cancels the registration flow, handing control back to the onboarding coordinator.
@MainActor private func cancelRegistration() {
authenticationService.reset()
@@ -681,6 +713,19 @@ extension AuthenticationCoordinator: SSOAuthenticationPresenterDelegate {
// MARK: - AuthenticationServiceDelegate
extension AuthenticationCoordinator: AuthenticationServiceDelegate {
func authenticationService(_ service: AuthenticationService, needsPromptFor unrecognizedCertificate: Data?, completion: @escaping (Bool) -> Void) {
guard let certificate = unrecognizedCertificate else {
completion(false)
return
}
Task {
let trusted = await self.displayUnrecognizedCertificateAlert(for: certificate)
completion(trusted)
}
}
func authenticationService(_ service: AuthenticationService, didReceive ssoLoginToken: String, with transactionID: String) -> Bool {
guard let presenter = ssoAuthenticationPresenter, transactionID == ssoTransactionID else {
Task { await displayError(message: VectorL10n.errorCommonMessage) }
@@ -156,7 +156,7 @@ extension RoomDataSource {
if event.isReply() {
let body: String
if let newContent = event.content[kMXMessageContentKeyNewContent] as? [String:Any] {
if let newContent = event.content[kMXMessageContentKeyNewContent] as? [String: Any] {
// Use new content if available.
body = newContent["formatted_body"] as? String ?? newContent[kMXMessageBodyKey] as? String ?? ""
} else {
@@ -167,7 +167,7 @@ extension RoomDataSource {
body = replyEventParts?.formattedBodyParts?.replyText ?? replyEventParts?.bodyParts.replyText ?? ""
}
let attributed = eventFormatter.renderHTMLString(body, for: event, with: self.roomState, isEditMode: true)
let attributed = eventFormatter.renderHTMLString(body, for: event, with: nil)
if let attributed = attributed, #available(iOS 15.0, *) {
editableTextMessage = PillsFormatter.insertPills(in: attributed,
withSession: self.mxSession,
@@ -180,7 +180,7 @@ extension RoomDataSource {
}
} else {
let body: String = event.content["formatted_body"] as? String ?? event.content["body"] as? String ?? ""
let attributed = eventFormatter.renderHTMLString(body, for: event, with: self.roomState, isEditMode: true)
let attributed = eventFormatter.renderHTMLString(body, for: event, with: nil)
if let attributed = attributed, #available(iOS 15.0, *) {
editableTextMessage = PillsFormatter.insertPills(in: attributed,
withSession: self.mxSession,
@@ -1077,6 +1077,12 @@ static BOOL _disableLongPressGestureOnEvent;
NSArray *bubbleComponents = bubbleData.bubbleComponents;
if (bubbleComponents.count == 1) {
return bubbleComponents.firstObject;
}
// The position check below fails for bubble data with a single component when message
// bubbles are enabled, thus the early bailout above
for (MXKRoomBubbleComponent *component in bubbleComponents)
{
// Ignore components without display (For example redacted event or state events)
@@ -17,6 +17,7 @@
*/
import Foundation
import UIKit
@objc enum SetPinCoordinatorViewMode: Int {
case setPin
@@ -49,6 +50,8 @@ final class SetPinCoordinatorBridgePresenter: NSObject {
// MARK: Private
private var pinCoordinatorWindow: UIWindow?
private let session: MXSession?
private var coordinator: SetPinCoordinator?
var viewMode: SetPinCoordinatorViewMode {
@@ -87,18 +90,23 @@ final class SetPinCoordinatorBridgePresenter: NSObject {
self.coordinator = setPinCoordinator
}
func present(in window: UIWindow) {
func presentWithMainAppWindow(_ window: UIWindow) {
let pinCoordinatorWindow = UIWindow(frame: window.bounds)
let setPinCoordinator = SetPinCoordinator(session: self.session, viewMode: self.viewMode, pinCodePreferences: .shared)
setPinCoordinator.delegate = self
guard let view = setPinCoordinator.toPresentable().view else { return }
window.addSubview(view)
view.leadingAnchor.constraint(equalTo: window.leadingAnchor, constant: 0).isActive = true
view.trailingAnchor.constraint(equalTo: window.trailingAnchor, constant: 0).isActive = true
view.topAnchor.constraint(equalTo: window.topAnchor, constant: 0).isActive = true
view.bottomAnchor.constraint(equalTo: window.bottomAnchor, constant: 0).isActive = true
pinCoordinatorWindow.addSubview(view)
view.leadingAnchor.constraint(equalTo: pinCoordinatorWindow.leadingAnchor, constant: 0).isActive = true
view.trailingAnchor.constraint(equalTo: pinCoordinatorWindow.trailingAnchor, constant: 0).isActive = true
view.topAnchor.constraint(equalTo: pinCoordinatorWindow.topAnchor, constant: 0).isActive = true
view.bottomAnchor.constraint(equalTo: pinCoordinatorWindow.bottomAnchor, constant: 0).isActive = true
pinCoordinatorWindow.makeKeyAndVisible()
setPinCoordinator.start()
self.pinCoordinatorWindow = pinCoordinatorWindow
self.coordinator = setPinCoordinator
}
@@ -106,6 +114,7 @@ final class SetPinCoordinatorBridgePresenter: NSObject {
guard let coordinator = self.coordinator else {
return
}
coordinator.toPresentable().dismiss(animated: animated) {
self.coordinator = nil
@@ -115,11 +124,10 @@ final class SetPinCoordinatorBridgePresenter: NSObject {
}
}
func dismiss() {
guard let coordinator = self.coordinator else {
return
}
coordinator.toPresentable().view.removeFromSuperview()
func dismissWithMainAppWindow(_ window: UIWindow) {
window.makeKeyAndVisible()
pinCoordinatorWindow = nil
coordinator = nil
}
}
+13 -7
View File
@@ -46,24 +46,30 @@ class URLValidator: NSObject {
/// - event: Event containing the link
/// - Returns: Validation result
static func validateTappedURL(_ url: URL, in event: MXEvent) -> URLValidationResult {
if let format = event.content["format"] as? String,
let formattedBody = event.content["formatted_body"] as? String {
guard let content = event.content else {
return .passed
}
if let format = content["format"] as? String,
let formattedBody = content["formatted_body"] as? String {
if format == kMXRoomMessageFormatHTML {
let visibleURL = FormattedBodyParser().getVisibleURL(forURL: url, inFormattedBody: formattedBody)
if url != visibleURL {
if let visibleURL = FormattedBodyParser().getVisibleURL(forURL: url, inFormattedBody: formattedBody),
url != visibleURL {
// urls are different, show confirmation alert
return .init(shouldShowConfirmationAlert: true,
visibleURLString: visibleURL?.absoluteString)
visibleURLString: visibleURL.absoluteString)
}
}
}
if let body = event.content[kMXMessageBodyKey] as? String,
body.vc_containsRTLOverride(),
body != url.absoluteString {
body.vc_containsRTLOverride(),
body != url.absoluteString {
// we don't know where the url is in the body, assuming visibleString is just a reverse of the url
return .init(shouldShowConfirmationAlert: true,
visibleURLString: url.absoluteString.vc_reversed())
}
return .passed
}