From 5decccf6cb33aff11b7ef94abb1880d86e3f798f Mon Sep 17 00:00:00 2001 From: JanNiklas Grabowski Date: Fri, 22 Dec 2023 12:25:59 +0100 Subject: [PATCH] hotfix use custom url scheme to open links if provided --- Riot/Categories/UIApplication.swift | 13 +++++- .../Common/Recents/RecentsViewController.m | 4 +- .../VersionCheckCoordinator.swift | 2 +- .../Controllers/MXKWebViewViewController.m | 4 +- Riot/Modules/MatrixKit/Utils/MXKTools.h | 9 ++++ Riot/Modules/MatrixKit/Utils/MXKTools.m | 16 +++++++ .../Modules/Settings/SettingsViewController.m | 10 ++-- Riot/Modules/TabBar/MasterTabBarController.m | 4 +- RiotNSE/target.yml | 1 + .../Login/AuthenticationLoginViewModel.swift | 2 +- .../View/AuthenticationLoginScreen.swift | 5 +- ...enticationServerSelectionCoordinator.swift | 2 +- .../AuthenticationServerSelectionScreen.swift | 2 +- .../View/LiveLocationSharingViewer.swift | 2 +- .../View/LocationSharingView.swift | 2 +- .../View/StaticLocationView.swift | 2 +- .../ServerDowntimeDefaultService.swift | 2 +- bwi/URLScheme/CustomURLSchemeHelper.swift | 46 +++++++++++++++++++ 18 files changed, 106 insertions(+), 22 deletions(-) create mode 100644 bwi/URLScheme/CustomURLSchemeHelper.swift diff --git a/Riot/Categories/UIApplication.swift b/Riot/Categories/UIApplication.swift index d2e27c476..528b46dee 100644 --- a/Riot/Categories/UIApplication.swift +++ b/Riot/Categories/UIApplication.swift @@ -21,12 +21,21 @@ extension UIApplication { let application = UIApplication.shared - guard application.canOpenURL(url) else { + // bwi: override scheme if needed + var tmpURL = url + + if let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) { + if let newURL = CustomURLSchemeHelper.shared.overrideURLSchemeIfNeeded(urlComponents).url { + tmpURL = newURL + } + } + + guard application.canOpenURL(tmpURL) else { completion?(false) return } - application.open(url, options: [:], completionHandler: { success in + application.open(tmpURL, options: [:], completionHandler: { success in completion?(success) }) } diff --git a/Riot/Modules/Common/Recents/RecentsViewController.m b/Riot/Modules/Common/Recents/RecentsViewController.m index 88f807d21..ad29106a9 100644 --- a/Riot/Modules/Common/Recents/RecentsViewController.m +++ b/Riot/Modules/Common/Recents/RecentsViewController.m @@ -2542,7 +2542,9 @@ NSString *const RecentsViewControllerDataReadyNotification = @"RecentsViewContro -(void) gotoAppStore { NSString *iTunesLink = BWIBuildSettings.shared.itunesAppLink; - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:iTunesLink] options:@{} completionHandler:nil]; + if (iTunesLink) { + [[UIApplication sharedApplication] vc_open:[NSURL URLWithString:iTunesLink] completionHandler:nil]; + } } #pragma mark - SpaceChildRoomDetailBridgePresenterDelegate diff --git a/Riot/Modules/Home/VersionCheck/VersionCheckCoordinator.swift b/Riot/Modules/Home/VersionCheck/VersionCheckCoordinator.swift index 728ca119d..5cce32233 100644 --- a/Riot/Modules/Home/VersionCheck/VersionCheckCoordinator.swift +++ b/Riot/Modules/Home/VersionCheck/VersionCheckCoordinator.swift @@ -120,7 +120,7 @@ class VersionCheckCoordinator: Coordinator, VersionCheckBannerViewDelegate, Vers } if let url = Constants.supportURL { - UIApplication.shared.open(url, options: [:], completionHandler: nil) + UIApplication.shared.vc_open(url, completionHandler: nil) } } diff --git a/Riot/Modules/MatrixKit/Controllers/MXKWebViewViewController.m b/Riot/Modules/MatrixKit/Controllers/MXKWebViewViewController.m index 08189aec0..5c74b8572 100644 --- a/Riot/Modules/MatrixKit/Controllers/MXKWebViewViewController.m +++ b/Riot/Modules/MatrixKit/Controllers/MXKWebViewViewController.m @@ -355,7 +355,9 @@ NSString *const kMXKWebViewViewControllerJavaScriptEnableLog = { if (navigationAction.navigationType == WKNavigationTypeLinkActivated) { // bwi: clicked links should be opened in system browser - [[UIApplication sharedApplication] openURL:navigationAction.request.URL options:@{} completionHandler:nil]; + if (navigationAction.request.URL) { + [[UIApplication sharedApplication] vc_open:navigationAction.request.URL completionHandler:nil]; + } decisionHandler(WKNavigationActionPolicyCancel); } else { // bwi: Open url in webview diff --git a/Riot/Modules/MatrixKit/Utils/MXKTools.h b/Riot/Modules/MatrixKit/Utils/MXKTools.h index f5326d405..5a18c9d39 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKTools.h +++ b/Riot/Modules/MatrixKit/Utils/MXKTools.h @@ -419,4 +419,13 @@ manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo */ + (NSString*)logForPushToken:(NSData*)pushToken; +#pragma mark - bwi +/** + Check if link is a permalink. + + @param link the link to ceck. + @return true if link is a permalink, false if it is not a permalink. + */ ++ (BOOL)isLinkPermalink:(NSString*)link; + @end diff --git a/Riot/Modules/MatrixKit/Utils/MXKTools.m b/Riot/Modules/MatrixKit/Utils/MXKTools.m index a93c09f93..2464f4c9a 100644 --- a/Riot/Modules/MatrixKit/Utils/MXKTools.m +++ b/Riot/Modules/MatrixKit/Utils/MXKTools.m @@ -1079,8 +1079,10 @@ manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo NSRange matchRange = [match range]; NSURL *matchUrl = [match URL]; NSURLComponents *url = [[NSURLComponents new] initWithURL:matchUrl resolvingAgainstBaseURL:NO]; + url = [CustomURLSchemeHelper.shared overrideURLSchemeIfNeeded:url]; if (url.URL) { + [mutableAttributedString addAttribute:NSLinkAttributeName value:url.URL range:matchRange]; [mutableAttributedString addAttribute:NSForegroundColorAttributeName value:ThemeService.shared.theme.colors.links range:matchRange]; } } @@ -1254,4 +1256,18 @@ manualChangeMessageForVideo:(NSString*)manualChangeMessageForVideo return [NSString stringWithFormat:@"%@...", [pushToken subdataWithRange:NSMakeRange(0, len)]]; } +#pragma mark - bwi + ++ (BOOL)isLinkPermalink:(NSString*)link +{ + if ([permalinkRegex numberOfMatchesInString:link options:0 range:NSMakeRange(0, link.length)] == 0) + { + return NO; + } + else + { + return YES; + } +} + @end diff --git a/Riot/Modules/Settings/SettingsViewController.m b/Riot/Modules/Settings/SettingsViewController.m index adc38c7c1..46c046b4b 100644 --- a/Riot/Modules/Settings/SettingsViewController.m +++ b/Riot/Modules/Settings/SettingsViewController.m @@ -3436,11 +3436,11 @@ SSOAuthenticationPresenterDelegate> } else if (row == ABOUT_COPYRIGHT_INDEX) { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:BWIBuildSettings.shared.applicationCopyrightUrlString] options:@{} completionHandler:nil]; + [[UIApplication sharedApplication] vc_open:[NSURL URLWithString:BWIBuildSettings.shared.applicationCopyrightUrlString] completionHandler:nil]; } else if (row == ABOUT_ACCEPTABLE_USE_INDEX) { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:BuildSettings.applicationAcceptableUsePolicyUrlString] options:@{} completionHandler:nil]; + [[UIApplication sharedApplication] vc_open:[NSURL URLWithString: BuildSettings.applicationAcceptableUsePolicyUrlString] completionHandler:nil]; } else if (row == ABOUT_SUPPORT_INDEX) { @@ -3457,11 +3457,11 @@ SSOAuthenticationPresenterDelegate> { if (BWIBuildSettings.shared.bwiUseWellKnownPrivacyPolicyLink) { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:self.mainSession.homeserverWellknown.dataPrivacyURL] options:@{} completionHandler:nil]; + [[UIApplication sharedApplication] vc_open:[NSURL URLWithString: self.mainSession.homeserverWellknown.dataPrivacyURL] completionHandler:nil]; } else { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:BWIBuildSettings.shared.applicationPrivacyPolicyUrlString] options:@{} completionHandler:nil]; + [[UIApplication sharedApplication] vc_open:[NSURL URLWithString: BWIBuildSettings.shared.applicationPrivacyPolicyUrlString] completionHandler:nil]; } } else if (row == ABOUT_ACCESSIBILITY_DECLARATION_INDEX) @@ -3481,7 +3481,7 @@ SSOAuthenticationPresenterDelegate> } else if (row == ABOUT_IMPRINT_INDEX) { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:[self.mainSession.homeserverWellknown imprintURL]] options:@{} completionHandler:nil]; + [[UIApplication sharedApplication] vc_open:[NSURL URLWithString: [self.mainSession.homeserverWellknown imprintURL]] completionHandler:nil]; } } else if (section == SECTION_TAG_USER_SETTINGS) diff --git a/Riot/Modules/TabBar/MasterTabBarController.m b/Riot/Modules/TabBar/MasterTabBarController.m index 72cb22927..1c2fb95a3 100644 --- a/Riot/Modules/TabBar/MasterTabBarController.m +++ b/Riot/Modules/TabBar/MasterTabBarController.m @@ -1092,10 +1092,10 @@ [alert addAction:[UIAlertAction actionWithTitle:BWIL10n.bwiAnalyticsAlertInfoButton style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { if (BWIBuildSettings.shared.bwiUseWellKnownPrivacyPolicyLink) { if (self->mxSessionArray.firstObject.homeserverWellknown.dataPrivacyURL != nil) { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:self->mxSessionArray.firstObject.homeserverWellknown.dataPrivacyURL] options:@{} completionHandler:nil]; + [[UIApplication sharedApplication] vc_open:[NSURL URLWithString: self->mxSessionArray.firstObject.homeserverWellknown.dataPrivacyURL] completionHandler:nil]; } } else { - [[UIApplication sharedApplication] openURL:[NSURL URLWithString:BWIBuildSettings.shared.applicationPrivacyPolicyUrlString] options:@{} completionHandler:nil]; + [[UIApplication sharedApplication] vc_open:[NSURL URLWithString: BWIBuildSettings.shared.applicationPrivacyPolicyUrlString] completionHandler:nil]; } }]]; [alert addAction:[UIAlertAction actionWithTitle:BWIL10n.bwiAnalyticsAlertCancelButton style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) { diff --git a/RiotNSE/target.yml b/RiotNSE/target.yml index 9b4d7a77c..5b1911507 100644 --- a/RiotNSE/target.yml +++ b/RiotNSE/target.yml @@ -57,6 +57,7 @@ targets: - path: ../bwi/MatomoAnalytics/AnalyticsConfiguration.swift - path: ../bwi/MatomoAnalytics/DecryptedEvent.swift - path: ../bwi/MatomoAnalytics/E2EEError.swift + - path: ../bwi/URLScheme/CustomURLSchemeHelper.swift - path: ../Riot/Managers/Settings/RiotSettings.swift - path: ../Config/BuildSettings.swift - path: ../Config/BWIBuildSettings.swift diff --git a/RiotSwiftUI/Modules/Authentication/Login/AuthenticationLoginViewModel.swift b/RiotSwiftUI/Modules/Authentication/Login/AuthenticationLoginViewModel.swift index c3085dfa0..38354c2a7 100644 --- a/RiotSwiftUI/Modules/Authentication/Login/AuthenticationLoginViewModel.swift +++ b/RiotSwiftUI/Modules/Authentication/Login/AuthenticationLoginViewModel.swift @@ -86,7 +86,7 @@ class AuthenticationLoginViewModel: AuthenticationLoginViewModelType, Authentica message: BWIL10n.bwiDeprecatedVersionWarningMessage, primaryButton: (BWIL10n.bwiDeprecatedVersionAppstoreButton, { - UIApplication.shared.open(URL(string: BWIBuildSettings.shared.itunesAppLink)!) + UIApplication.shared.vc_open(URL(string: BWIBuildSettings.shared.itunesAppLink)!, completionHandler: nil) }), secondaryButton: (VectorL10n.ok, {})) diff --git a/RiotSwiftUI/Modules/Authentication/Login/View/AuthenticationLoginScreen.swift b/RiotSwiftUI/Modules/Authentication/Login/View/AuthenticationLoginScreen.swift index d07a81918..5d5b4be87 100644 --- a/RiotSwiftUI/Modules/Authentication/Login/View/AuthenticationLoginScreen.swift +++ b/RiotSwiftUI/Modules/Authentication/Login/View/AuthenticationLoginScreen.swift @@ -218,9 +218,8 @@ struct AuthenticationLoginScreen: View { return } let tosURL = URL.init(string: urlString)! // add your link here - if UIApplication.shared.canOpenURL(tosURL) { - UIApplication.shared.open(tosURL) - } + + UIApplication.shared.vc_open(tosURL, completionHandler: nil) }, label: { Text(BWIL10n.authenticationDataprivacyText) .font(theme.fonts.footnote) diff --git a/RiotSwiftUI/Modules/Authentication/ServerSelection/Coordinator/AuthenticationServerSelectionCoordinator.swift b/RiotSwiftUI/Modules/Authentication/ServerSelection/Coordinator/AuthenticationServerSelectionCoordinator.swift index b2f161cbf..ae6f27428 100644 --- a/RiotSwiftUI/Modules/Authentication/ServerSelection/Coordinator/AuthenticationServerSelectionCoordinator.swift +++ b/RiotSwiftUI/Modules/Authentication/ServerSelection/Coordinator/AuthenticationServerSelectionCoordinator.swift @@ -130,7 +130,7 @@ final class AuthenticationServerSelectionCoordinator: Coordinator, Presentable { stopLoading() let primaryButtonCompletion: (() -> Void)? = { () in if let url = URL(string: BWIBuildSettings.shared.bumAdvertizementURLString) { - UIApplication.shared.open(url) + UIApplication.shared.vc_open(url, completionHandler: nil) } } diff --git a/RiotSwiftUI/Modules/Authentication/ServerSelection/View/AuthenticationServerSelectionScreen.swift b/RiotSwiftUI/Modules/Authentication/ServerSelection/View/AuthenticationServerSelectionScreen.swift index b42eb0eb3..250377052 100644 --- a/RiotSwiftUI/Modules/Authentication/ServerSelection/View/AuthenticationServerSelectionScreen.swift +++ b/RiotSwiftUI/Modules/Authentication/ServerSelection/View/AuthenticationServerSelectionScreen.swift @@ -263,7 +263,7 @@ struct AuthenticationServerSelectionScreen: View { return Alert( title: Text(BWIL10n.authenticationServerSelectionServerDeniedTitle), message: Text(BWIL10n.authenticationServerSelectionServerDeniedMessage), - primaryButton: .default(Text(BWIL10n.authenticationServerSelectionServerDeniedAdvertizementWebsiteButton), action: {UIApplication.shared.open(url)}), + primaryButton: .default(Text(BWIL10n.authenticationServerSelectionServerDeniedAdvertizementWebsiteButton), action: {UIApplication.shared.vc_open(url, completionHandler: nil)}), secondaryButton: .default(Text(VectorL10n.ok))) } else { diff --git a/RiotSwiftUI/Modules/LocationSharing/LiveLocationSharingViewer/View/LiveLocationSharingViewer.swift b/RiotSwiftUI/Modules/LocationSharing/LiveLocationSharingViewer/View/LiveLocationSharingViewer.swift index e0ac8ac76..2e51df3ce 100644 --- a/RiotSwiftUI/Modules/LocationSharing/LiveLocationSharingViewer/View/LiveLocationSharingViewer.swift +++ b/RiotSwiftUI/Modules/LocationSharing/LiveLocationSharingViewer/View/LiveLocationSharingViewer.swift @@ -123,7 +123,7 @@ struct LiveLocationSharingViewer: View { .bottomSheet(sheet, if: viewModel.viewState.isBottomSheetVisible) .actionSheet(isPresented: $viewModel.showMapCreditsSheet) { MapCreditsActionSheet(openURL: { url in - openURL(url) + UIApplication.shared.vc_open(url, completionHandler: nil) }).sheet } .alert(item: $viewModel.alertInfo) { info in diff --git a/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/View/LocationSharingView.swift b/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/View/LocationSharingView.swift index 47f2483cc..ef6e33604 100644 --- a/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/View/LocationSharingView.swift +++ b/RiotSwiftUI/Modules/LocationSharing/StartLocationSharing/View/LocationSharingView.swift @@ -49,7 +49,7 @@ struct LocationSharingView: View { .padding(.bottom, 10.0) .actionSheet(isPresented: $context.showMapCreditsSheet) { MapCreditsActionSheet(openURL: { url in - openURL(url) + UIApplication.shared.vc_open(url, completionHandler: nil) }).sheet } } diff --git a/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/View/StaticLocationView.swift b/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/View/StaticLocationView.swift index f50741884..9c94a6f32 100644 --- a/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/View/StaticLocationView.swift +++ b/RiotSwiftUI/Modules/LocationSharing/StaticLocationSharingViewer/View/StaticLocationView.swift @@ -59,7 +59,7 @@ struct StaticLocationView: View { .padding(.bottom, 10.0 + safeAreaInsets.bottom) .actionSheet(isPresented: $viewModel.showMapCreditsSheet) { MapCreditsActionSheet(openURL: { url in - openURL(url) + UIApplication.shared.vc_open(url, completionHandler: nil) }).sheet } } diff --git a/bwi/ServerMaintenance/ServerDowntimeDefaultService.swift b/bwi/ServerMaintenance/ServerDowntimeDefaultService.swift index ea10bd302..1874ec8f4 100644 --- a/bwi/ServerMaintenance/ServerDowntimeDefaultService.swift +++ b/bwi/ServerMaintenance/ServerDowntimeDefaultService.swift @@ -190,7 +190,7 @@ extension ServerDowntimeDefaultService : ServerDowntimeService { message: Text(BWIL10n.bwiOutdatedVersionWarningMessage(AppInfo.current.displayName)), dismissButton: .destructive(Text(BWIL10n.bwiOutdatedVersionAppstoreButton), action: { let iTunesLink = BWIBuildSettings.shared.itunesAppLink - UIApplication.shared.open(URL(string: iTunesLink)!, options: [:], completionHandler: nil) + UIApplication.shared.vc_open(URL(string: iTunesLink)!, completionHandler: nil) })) case .showDowntimeTimeAlert: if BWIBuildSettings.shared.ignoreBlockingMaintenance && isBlocking() { diff --git a/bwi/URLScheme/CustomURLSchemeHelper.swift b/bwi/URLScheme/CustomURLSchemeHelper.swift new file mode 100644 index 000000000..bcda3ece4 --- /dev/null +++ b/bwi/URLScheme/CustomURLSchemeHelper.swift @@ -0,0 +1,46 @@ +// +/* + * Copyright (c) 2023 BWI GmbH + * + * 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 Foundation + +@objcMembers class CustomURLSchemeHelper : NSObject { + static let shared = CustomURLSchemeHelper() + + func overrideURLSchemeIfNeeded(_ urlComponents: URLComponents) -> URLComponents { + if AppConfigService.shared.externalUrlScheme() != nil { + guard let url = urlComponents.url else { + return urlComponents + } + // Check if link is a permalink + if MXKTools.isLinkPermalink(url.absoluteString) { + return urlComponents + } + // Only override http / https + if (urlComponents.scheme ?? "http").elementsEqual("http") || (urlComponents.scheme ?? "https").elementsEqual("https") { + var newURLComponents = urlComponents + if let urlScheme = AppConfigService.shared.externalUrlScheme() { + newURLComponents.scheme = urlScheme + } + return newURLComponents + } else { + return urlComponents + } + } else { + return urlComponents + } + } +}