From a6eb514761893c7802c440b978e83d0c3e0923da Mon Sep 17 00:00:00 2001 From: Gleidson Daniel Silva Date: Tue, 6 Jun 2023 18:53:48 -0300 Subject: [PATCH] fix: Calls with jwt not working on ios and fix media permission on iOS (#5075) * fix roomId * fix ios permission * update lib and patch * try * update webview * update method * fix ios * move to a function --- .../helpers/getRoomIdFromJitsiCall.test.ts | 18 +++ .../methods/helpers/getRoomIdFromJitsiCall.ts | 9 ++ app/views/AdminPanelView/index.tsx | 4 +- app/views/JitsiMeetView.tsx | 21 ++-- ios/Podfile.lock | 6 +- package.json | 2 +- ...tch => react-native-webview+11.26.1.patch} | 111 ++++++++---------- yarn.lock | 8 +- 8 files changed, 102 insertions(+), 77 deletions(-) create mode 100644 app/lib/methods/helpers/getRoomIdFromJitsiCall.test.ts create mode 100644 app/lib/methods/helpers/getRoomIdFromJitsiCall.ts rename patches/{react-native-webview+10.3.2.patch => react-native-webview+11.26.1.patch} (70%) diff --git a/app/lib/methods/helpers/getRoomIdFromJitsiCall.test.ts b/app/lib/methods/helpers/getRoomIdFromJitsiCall.test.ts new file mode 100644 index 000000000..7cf2b00c9 --- /dev/null +++ b/app/lib/methods/helpers/getRoomIdFromJitsiCall.test.ts @@ -0,0 +1,18 @@ +import { getRoomIdFromJitsiCallUrl } from './getRoomIdFromJitsiCall'; + +describe('getRoomIdFromJitsiCallUrl function', () => { + const urlWithJwt = + 'https://meet.rocketchat.test/rocket6474dd29bbb65c7e344c0da0?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ2aWRlb2NvbmZzcXVhZF9hcHAiLCJzdWIiOiJtZWV0LnJvY2tldGNoYXQuc2hvcCIsImlhdCI6MTY4NTM4NTE3OSwibmJmIjoxNjg1Mzg1MTc5LCJleHAiOjE2ODUzODg3ZXQ2NDc0ZGQyOWJiYjY1YzdlMzQ0YzBkYTAiLCJjb250ZXh0Ijp7InVzZXIiOnsibmFtZSI6InhkYW5pIiwiYXZhdGFyIjoiaHR0cHM6Ly9tb2JpbGUucm9ja2V0LmNoYXQvYXZhdGFyL3hkYW5pIiwiZW1haWwiOiJ1c2VyX2FSdEVMTHJGdkpEQ29USktiQHJvY2tldC5jaGF0In19LCJtb2RlcmF0b3IiOnRydWV9.WCo8Do4m1w8LBg5lVyd7Z-M9dG97uk5ogwfCaBzEUv4#config.desktopSharingChromeExtId="nocfbnnmjnndkbipkabodnheejiegccf"&config.callDisplayName="daniel"&config.startWithAudioMuted=false&config.startWithVideoMuted=true&config.prejoinPageEnabled=false&config.prejoinConfig.enabled=false&config.disableDeepLinking=true'; + const urlWithoutJwt = + 'https://meet.rocketchat.test/rocket6474dd29bbb65c7e344c0da0#config.desktopSharingChromeExtId="nocfbnnmjnndkbipkabodnheejiegccf"&config.callDisplayName="daniel"&config.startWithAudioMuted=false&config.startWithVideoMuted=true&config.prejoinPageEnabled=false&config.prejoinConfig.enabled=false&config.disableDeepLinking=true'; + + test('return correct url without jwt', () => { + const roomId = getRoomIdFromJitsiCallUrl(urlWithoutJwt); + expect(roomId).toEqual('rocket6474dd29bbb65c7e344c0da0'); + }); + + test('return correct url with jwt', () => { + const roomId = getRoomIdFromJitsiCallUrl(urlWithJwt); + expect(roomId).toEqual('rocket6474dd29bbb65c7e344c0da0'); + }); +}); diff --git a/app/lib/methods/helpers/getRoomIdFromJitsiCall.ts b/app/lib/methods/helpers/getRoomIdFromJitsiCall.ts new file mode 100644 index 000000000..6fa85c478 --- /dev/null +++ b/app/lib/methods/helpers/getRoomIdFromJitsiCall.ts @@ -0,0 +1,9 @@ +export const getRoomIdFromJitsiCallUrl = (jitsiCallUrl: string): string => { + const url = jitsiCallUrl + ?.split(/^https?:\/\//)[1] + ?.split('#')[0] + ?.split('/')[1]; + + const roomId = url.includes('?jwt') ? url.split('?jwt')[0] : url; + return roomId; +}; diff --git a/app/views/AdminPanelView/index.tsx b/app/views/AdminPanelView/index.tsx index d51f019e4..e1a146ab4 100644 --- a/app/views/AdminPanelView/index.tsx +++ b/app/views/AdminPanelView/index.tsx @@ -29,6 +29,8 @@ const AdminPanelView = () => { return null; } + const str = `Meteor.loginWithToken('${token}', function() { })`; + return ( @@ -36,7 +38,7 @@ const AdminPanelView = () => { // https://github.com/react-native-community/react-native-webview/issues/1311 onMessage={() => {}} source={{ uri: `${baseUrl}/admin/info?layout=embedded` }} - injectedJavaScript={`Meteor.loginWithToken('${token}', function() { })`} + injectedJavaScript={str} /> ); diff --git a/app/views/JitsiMeetView.tsx b/app/views/JitsiMeetView.tsx index 9b5f5e4d7..1c699fde7 100644 --- a/app/views/JitsiMeetView.tsx +++ b/app/views/JitsiMeetView.tsx @@ -1,4 +1,4 @@ -import { activateKeepAwake, deactivateKeepAwake } from 'expo-keep-awake'; +import { activateKeepAwakeAsync, deactivateKeepAwake } from 'expo-keep-awake'; import React from 'react'; import { BackHandler, Linking, NativeEventSubscription, SafeAreaView } from 'react-native'; import WebView from 'react-native-webview'; @@ -7,6 +7,7 @@ import { WebViewNavigation } from 'react-native-webview/lib/WebViewTypes'; import { IBaseScreen } from '../definitions'; import { userAgent } from '../lib/constants'; import { isIOS } from '../lib/methods/helpers'; +import { getRoomIdFromJitsiCallUrl } from '../lib/methods/helpers/getRoomIdFromJitsiCall'; import { events, logEvent } from '../lib/methods/helpers/log'; import { endVideoConfTimer, initVideoConfTimer } from '../lib/methods/videoConfTimer'; import { ChatsStackParamList } from '../stacks/types'; @@ -30,7 +31,7 @@ class JitsiMeetView extends React.Component { componentDidMount() { this.handleJitsiApp(); this.onConferenceJoined(); - activateKeepAwake(); + activateKeepAwakeAsync(); } componentWillUnmount() { @@ -67,11 +68,10 @@ class JitsiMeetView extends React.Component { onNavigationStateChange = (webViewState: WebViewNavigation) => { const { navigation, route } = this.props; - const jitsiRoomId = route.params.url - ?.split(/^https?:\/\//)[1] - ?.split('#')[0] - ?.split('/')[1]; - if ((jitsiRoomId && !webViewState.url.includes(jitsiRoomId)) || webViewState.url.includes('close')) { + + const roomId = getRoomIdFromJitsiCallUrl(route.params.url); + + if ((roomId && !webViewState.url.includes(roomId)) || webViewState.url.includes('close')) { if (isIOS) { if (webViewState.navigationType) { navigation.pop(); @@ -83,16 +83,19 @@ class JitsiMeetView extends React.Component { }; render() { + const uri = `${this.url}${this.url.includes('#config') ? '&' : '#'}config.disableDeepLinking=true`; return ( ); diff --git a/ios/Podfile.lock b/ios/Podfile.lock index c638e11f2..397db9568 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -407,8 +407,8 @@ PODS: - React - react-native-slider (4.4.2): - React-Core - - react-native-webview (10.3.2): - - React + - react-native-webview (11.26.1): + - React-Core - React-perflogger (0.71.7) - React-RCTActionSheet (0.71.7): - React-Core/RCTActionSheetHeaders (= 0.71.7) @@ -949,7 +949,7 @@ SPEC CHECKSUMS: react-native-safe-area-context: f0906bf8bc9835ac9a9d3f97e8bde2a997d8da79 react-native-simple-crypto: a26121696064628b6cb92f52f653353114deb7f4 react-native-slider: 33b8d190b59d4f67a541061bb91775d53d617d9d - react-native-webview: 679b6f400176e2ea8a785acf7ae16cf282e7d1eb + react-native-webview: 9f111dfbcfc826084d6c507f569e5e03342ee1c1 React-perflogger: 2d505bbe298e3b7bacdd9e542b15535be07220f6 React-RCTActionSheet: 0e96e4560bd733c9b37efbf68f5b1a47615892fb React-RCTAnimation: fd138e26f120371c87e406745a27535e2c8a04ef diff --git a/package.json b/package.json index 4ebbaa063..3eba48197 100644 --- a/package.json +++ b/package.json @@ -131,7 +131,7 @@ "react-native-svg": "^13.8.0", "react-native-ui-lib": "RocketChat/react-native-ui-lib#7.2.0", "react-native-vector-icons": "^9.2.0", - "react-native-webview": "10.3.2", + "react-native-webview": "11.26.1", "react-redux": "^8.0.5", "reactotron-react-native": "^5.0.3", "redux": "4.2.0", diff --git a/patches/react-native-webview+10.3.2.patch b/patches/react-native-webview+11.26.1.patch similarity index 70% rename from patches/react-native-webview+10.3.2.patch rename to patches/react-native-webview+11.26.1.patch index 6c9db9d55..35b11542f 100644 --- a/patches/react-native-webview+10.3.2.patch +++ b/patches/react-native-webview+11.26.1.patch @@ -1,10 +1,10 @@ diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java -index ab869cf..08ce7ce 100644 +index 9cfe821..b7fe976 100644 --- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java -@@ -84,6 +84,12 @@ import java.util.Map; - - import javax.annotation.Nullable; +@@ -102,6 +102,12 @@ import java.util.Locale; + import java.util.Map; + import java.util.concurrent.atomic.AtomicReference; +import java.security.cert.X509Certificate; +import java.security.PrivateKey; @@ -15,16 +15,16 @@ index ab869cf..08ce7ce 100644 /** * Manages instances of {@link WebView} *

-@@ -140,6 +146,8 @@ public class RNCWebViewManager extends SimpleViewManager { - protected @Nullable String mUserAgent = null; - protected @Nullable String mUserAgentWithApplicationName = null; +@@ -166,6 +172,8 @@ public class RNCWebViewManager extends SimpleViewManager { + protected @Nullable String mDownloadingMessage = null; + protected @Nullable String mLackPermissionToDownloadMessage = null; + private static String certificateAlias = null; + public RNCWebViewManager() { mWebViewConfig = new WebViewConfig() { public void configWebView(WebView webView) { -@@ -151,6 +159,10 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -177,6 +185,10 @@ public class RNCWebViewManager extends SimpleViewManager { mWebViewConfig = webViewConfig; } @@ -32,10 +32,10 @@ index ab869cf..08ce7ce 100644 + certificateAlias = alias; + } + - protected static void dispatchEvent(WebView webView, Event event) { - ReactContext reactContext = (ReactContext) webView.getContext(); - EventDispatcher eventDispatcher = -@@ -562,7 +574,7 @@ public class RNCWebViewManager extends SimpleViewManager { + @Override + public String getName() { + return REACT_CLASS; +@@ -687,7 +699,7 @@ public class RNCWebViewManager extends SimpleViewManager { @Override protected void addEventEmitters(ThemedReactContext reactContext, WebView view) { // Do not register default touch emitter and let WebView implementation handle touches @@ -44,17 +44,12 @@ index ab869cf..08ce7ce 100644 } @Override -@@ -742,12 +754,56 @@ public class RNCWebViewManager extends SimpleViewManager { - - protected static class RNCWebViewClient extends WebViewClient { - -+ protected ReactContext reactContext; - protected boolean mLastLoadFailed = false; - protected @Nullable - ReadableArray mUrlPrefixesForDefaultIntent; +@@ -913,6 +925,50 @@ public class RNCWebViewManager extends SimpleViewManager { protected RNCWebView.ProgressChangedFilter progressChangedFilter = null; protected @Nullable String ignoreErrFailedForThisURL = null; - + protected @Nullable BasicAuthCredential basicAuthCredential = null; ++ protected ReactContext reactContext; ++ + public RNCWebViewClient(ReactContext reactContext) { + this.reactContext = reactContext; + } @@ -97,12 +92,11 @@ index ab869cf..08ce7ce 100644 + super.onReceivedClientCertRequest(view, request); + } + } -+ + public void setIgnoreErrFailedForThisURL(@Nullable String url) { ignoreErrFailedForThisURL = url; - } diff --git a/node_modules/react-native-webview/apple/RNCWebView.m b/node_modules/react-native-webview/apple/RNCWebView.m -index 02b4238..e0635ed 100644 +index 7570d8d..eaa0e5d 100644 --- a/node_modules/react-native-webview/apple/RNCWebView.m +++ b/node_modules/react-native-webview/apple/RNCWebView.m @@ -17,6 +17,9 @@ @@ -115,8 +109,8 @@ index 02b4238..e0635ed 100644 static NSTimer *keyboardTimer; static NSString *const HistoryShimName = @"ReactNativeHistoryShim"; static NSString *const MessageHandlerName = @"ReactNativeWebView"; -@@ -737,6 +740,68 @@ static NSDictionary* customCertificatesForHost; - customCertificatesForHost = certificates; +@@ -963,6 +966,68 @@ + (void)setCustomCertificatesForHost:(nullable NSDictionary*)certificates { + customCertificatesForHost = certificates; } +-(NSURLCredential *)getUrlCredential:(NSURLAuthenticationChallenge *)challenge path:(NSString *)path password:(NSString *)password @@ -184,37 +178,36 @@ index 02b4238..e0635ed 100644 - (void) webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential * _Nullable))completionHandler -@@ -746,7 +811,32 @@ static NSDictionary* customCertificatesForHost; - host = webView.URL.host; - } - if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) { -- completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential); -+ NSString *host = challenge.protectionSpace.host; +@@ -972,7 +1037,31 @@ - (void) webView:(WKWebView *)webView + host = webView.URL.host; + } + if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) { +- completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential); ++ NSString *host = challenge.protectionSpace.host; + -+ // Read the clientSSL info from MMKV -+ __block NSDictionary *clientSSL; -+ SecureStorage *secureStorage = [[SecureStorage alloc] init]; -+ -+ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31 -+ NSString *key = [secureStorage getSecureKey:[self stringToHex:@"com.MMKV.default"]]; -+ NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; -+ -+ if (key == NULL) { -+ return completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, credential); -+ } -+ -+ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding]; -+ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess]; -+ clientSSL = [mmkv getObjectOfClass:[NSDictionary class] forKey:host]; -+ -+ -+ if (clientSSL != (id)[NSNull null]) { -+ NSString *path = [clientSSL objectForKey:@"path"]; -+ NSString *password = [clientSSL objectForKey:@"password"]; -+ credential = [self getUrlCredential:challenge path:path password:password]; -+ } -+ -+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential); - return; - } - if ([[challenge protectionSpace] serverTrust] != nil && customCertificatesForHost != nil && host != nil) { ++ // Read the clientSSL info from MMKV ++ __block NSDictionary *clientSSL; ++ SecureStorage *secureStorage = [[SecureStorage alloc] init]; ++ ++ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31 ++ NSString *key = [secureStorage getSecureKey:[self stringToHex:@"com.MMKV.default"]]; ++ NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; ++ ++ if (key == NULL) { ++ return completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, credential); ++ } ++ ++ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding]; ++ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess]; ++ clientSSL = [mmkv getObjectOfClass:[NSDictionary class] forKey:host]; ++ ++ if (clientSSL != (id)[NSNull null]) { ++ NSString *path = [clientSSL objectForKey:@"path"]; ++ NSString *password = [clientSSL objectForKey:@"password"]; ++ credential = [self getUrlCredential:challenge path:path password:password]; ++ } ++ ++ completionHandler(NSURLSessionAuthChallengeUseCredential, credential); + return; + } + if ([[challenge protectionSpace] serverTrust] != nil && customCertificatesForHost != nil && host != nil) { diff --git a/yarn.lock b/yarn.lock index bf5eb782b..79927ade6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17242,10 +17242,10 @@ react-native-vector-icons@^9.2.0: prop-types "^15.7.2" yargs "^16.1.1" -react-native-webview@10.3.2: - version "10.3.2" - resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-10.3.2.tgz#c634946152099c95d521a3abc71065d1d642e192" - integrity sha512-4A8FKL/puonkqQ1FOKd+iPulqRXCG4inmIK4pQ60zv9Ua+YkBKLxxofQiCvRwIXSSgAXYT+AE3rOHr3bx4A/cw== +react-native-webview@11.26.1: + version "11.26.1" + resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-11.26.1.tgz#658c09ed5162dc170b361e48c2dd26c9712879da" + integrity sha512-hC7BkxOpf+z0UKhxFSFTPAM4shQzYmZHoELa6/8a/MspcjEP7ukYKpuSUTLDywQditT8yI9idfcKvfZDKQExGw== dependencies: escape-string-regexp "2.0.0" invariant "2.2.4"