diff --git a/app/init/global_event_handler.js b/app/init/global_event_handler.js index 524cc21c2..7f1e2ac30 100644 --- a/app/init/global_event_handler.js +++ b/app/init/global_event_handler.js @@ -3,7 +3,7 @@ import {Alert, AppState, Dimensions, Linking, NativeModules, Platform} from 'react-native'; import AsyncStorage from '@react-native-community/async-storage'; -import CookieManager from '@react-native-community/cookies'; +import CookieManager from 'react-native-cookies'; import DeviceInfo from 'react-native-device-info'; import {getLocales} from 'react-native-localize'; import RNFetchBlob from 'rn-fetch-blob'; diff --git a/app/screens/sso/sso.js b/app/screens/sso/sso.js index ee498a000..51f5e7e0b 100644 --- a/app/screens/sso/sso.js +++ b/app/screens/sso/sso.js @@ -10,7 +10,7 @@ import { Platform, } from 'react-native'; import {WebView} from 'react-native-webview'; -import CookieManager from '@react-native-community/cookies'; +import CookieManager from 'react-native-cookies'; import urlParse from 'url-parse'; import {Client4} from '@mm-redux/client'; @@ -27,7 +27,7 @@ const HEADERS = { 'X-Mobile-App': 'mattermost', }; -const postMessageJS = 'window.ReactNativeWebView.postMessage(document.body.innerText);'; +const postMessageJS = "window.postMessage(document.body.innerText, '*');"; // Used to make sure that OneLogin forms scale appropriately on both platforms. const oneLoginFormScalingJS = ` @@ -240,17 +240,16 @@ class SSO extends PureComponent { true} injectedJavaScript={jsCode} onLoadEnd={this.onLoadEnd} - onMessage={(messagingEnabled || Platform.OS === 'android') ? this.onMessage : null} - sharedCookiesEnabled={Platform.OS === 'android'} + onMessage={messagingEnabled ? this.onMessage : null} + useSharedProcessPool={true} cacheEnabled={false} - useSharedProcessPool={false} /> ); } diff --git a/app/utils/security.js b/app/utils/security.js index b00c24ff0..e9b123357 100644 --- a/app/utils/security.js +++ b/app/utils/security.js @@ -2,7 +2,7 @@ // See LICENSE.txt for license information. import {Client4} from '@mm-redux/client'; -import CookieManager from '@react-native-community/cookies'; +import CookieManager from 'react-native-cookies'; export function setCSRFFromCookie(url) { return new Promise((resolve) => { diff --git a/ios/Podfile.lock b/ios/Podfile.lock index e54b8a088..471eca539 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -207,7 +207,7 @@ PODS: - React-jsinspector (0.62.2) - react-native-cameraroll (1.6.2): - React - - react-native-cookies (3.0.0): + - react-native-cookies (3.2.0): - React - react-native-document-picker (3.4.0): - React @@ -235,7 +235,7 @@ PODS: - react-native-video/Video (= 5.0.2) - react-native-video/Video (5.0.2): - React - - react-native-webview (9.4.0): + - react-native-webview (7.0.1): - React - React-RCTActionSheet (0.62.2): - React-Core/RCTActionSheetHeaders (= 0.62.2) @@ -320,7 +320,7 @@ PODS: - React - RNGestureHandler (1.6.1): - React - - RNKeychain (6.0.0): + - RNKeychain (4.0.5): - React - RNLocalize (1.4.0): - React @@ -380,7 +380,7 @@ DEPENDENCIES: - React-jsiexecutor (from `../node_modules/react-native/ReactCommon/jsiexecutor`) - React-jsinspector (from `../node_modules/react-native/ReactCommon/jsinspector`) - "react-native-cameraroll (from `../node_modules/@react-native-community/cameraroll`)" - - "react-native-cookies (from `../node_modules/@react-native-community/cookies`)" + - react-native-cookies (from `../node_modules/react-native-cookies/ios`) - react-native-document-picker (from `../node_modules/react-native-document-picker`) - react-native-hw-keyboard-event (from `../node_modules/react-native-hw-keyboard-event`) - react-native-image-picker (from `../node_modules/react-native-image-picker`) @@ -484,7 +484,7 @@ EXTERNAL SOURCES: react-native-cameraroll: :path: "../node_modules/@react-native-community/cameraroll" react-native-cookies: - :path: "../node_modules/@react-native-community/cookies" + :path: "../node_modules/react-native-cookies/ios" react-native-document-picker: :path: "../node_modules/react-native-document-picker" react-native-hw-keyboard-event: @@ -597,7 +597,7 @@ SPEC CHECKSUMS: React-jsiexecutor: 1540d1c01bb493ae3124ed83351b1b6a155db7da React-jsinspector: 512e560d0e985d0e8c479a54a4e5c147a9c83493 react-native-cameraroll: 94bec91c68b94ac946c61b497b594bb38692c41b - react-native-cookies: 6fe6a70d3b2fd8e81ddcd94d60a87727010d9b2e + react-native-cookies: 854d59c4135c70b92a02ca4930e68e4e2eb58150 react-native-document-picker: d694111879537cec2c258a1dcd2243d9df746824 react-native-hw-keyboard-event: b517cefb8d5c659a38049c582de85ff43337dc53 react-native-image-picker: 668e72d0277dc8c12ae90e835507c1eddd2e4f85 @@ -609,7 +609,7 @@ SPEC CHECKSUMS: react-native-safe-area: e8230b0017d76c00de6b01e2412dcf86b127c6a3 react-native-safe-area-context: 5f3e081f937ab7c44c179d551f332fa494cfcf8f react-native-video: 961749da457e73bf0b5565edfbaffc25abfb8974 - react-native-webview: 0e2881d2e3e72ad52a82445c1a116c43205fd471 + react-native-webview: 0d1c2b4e7ffb0543a74fa0512f2f8dc5fb0e49e2 React-RCTActionSheet: f41ea8a811aac770e0cc6e0ad6b270c644ea8b7c React-RCTAnimation: 49ab98b1c1ff4445148b72a3d61554138565bad0 React-RCTBlob: a332773f0ebc413a0ce85942a55b064471587a71 @@ -630,7 +630,7 @@ SPEC CHECKSUMS: RNFastImage: 35ae972d6727c84ee3f5c6897e07f84d0a3445e9 RNFileViewer: 3600e85d326dadfd0fd367eb38fcb4300b699b49 RNGestureHandler: 8f09cd560f8d533eb36da5a6c5a843af9f056b38 - RNKeychain: bf2d7e9a0ae7a073c07770dd2aa6d11c67581733 + RNKeychain: 840f8e6f13be0576202aefcdffd26a4f54bfe7b5 RNLocalize: fc27ee5878ce5a3af73873fb2d8e866e0d1e6d84 RNPermissions: 8ca17fd6c822eea589fe84709d9426e05cc39c39 RNReactNativeHapticFeedback: 22c5ecf474428766c6b148f96f2ff6155cd7225e diff --git a/package-lock.json b/package-lock.json index 8a3eeee49..ba14c1f49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3219,14 +3219,6 @@ "resolved": "https://registry.npmjs.org/@react-native-community/cli-types/-/cli-types-4.10.0.tgz", "integrity": "sha512-gU0Opspa/WYLQdmY0BKe0VLwD+SuNatypRvBP6nlyzS8/qmSaZ73047jHWYQavhfqn/WxHzBLQSwZK0a7ROfeg==" }, - "@react-native-community/cookies": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@react-native-community/cookies/-/cookies-3.0.0.tgz", - "integrity": "sha512-ms/CsrBlHffTyTRhXsKSmSK6WlWScG8wklfSmkr4WeeA0j0AQ1sknTg8YNsK0bMr6Ij1uDuvX9t96vZrFGpYqQ==", - "requires": { - "invariant": "^2.2.4" - } - }, "@react-native-community/masked-view": { "version": "0.1.10", "resolved": "https://registry.npmjs.org/@react-native-community/masked-view/-/masked-view-0.1.10.tgz", @@ -15816,6 +15808,13 @@ "prop-types": "^15.7.2" } }, + "react-native-cookies": { + "version": "github:mattermost/react-native-cookies#b35bafc388ae09c83bd875e887daf6a0755e0b40", + "from": "github:mattermost/react-native-cookies#b35bafc388ae09c83bd875e887daf6a0755e0b40", + "requires": { + "invariant": "^2.1.0" + } + }, "react-native-device-info": { "version": "5.5.7", "resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-5.5.7.tgz", @@ -16188,18 +16187,17 @@ } }, "react-native-webview": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/react-native-webview/-/react-native-webview-9.4.0.tgz", - "integrity": "sha512-BBOFUuza0p04+7fNi7TJmB0arpDJzGxHYwTCgI4vj5n/fl7u4jbm7ETp88mf7lo9lP6C6HGLo38KnEy1aXCQkg==", + "version": "github:mattermost/react-native-webview#b5e22940a613869d3999feac9451ee65352f4fbe", + "from": "github:mattermost/react-native-webview#b5e22940a613869d3999feac9451ee65352f4fbe", "requires": { - "escape-string-regexp": "2.0.0", + "escape-string-regexp": "1.0.5", "invariant": "2.2.4" }, "dependencies": { "escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" } } }, diff --git a/package.json b/package.json index 07c8b0800..6eb4c8941 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ "@babel/runtime": "7.9.6", "@react-native-community/async-storage": "1.10.1", "@react-native-community/cameraroll": "1.6.2", - "@react-native-community/cookies": "3.0.0", "@react-native-community/masked-view": "0.1.10", "@react-native-community/netinfo": "5.8.1", "@react-navigation/native": "5.3.2", @@ -39,6 +38,7 @@ "react-native-button": "3.0.1", "react-native-calendars": "1.265.0", "react-native-circular-progress": "1.3.6", + "react-native-cookies": "github:mattermost/react-native-cookies#b35bafc388ae09c83bd875e887daf6a0755e0b40", "react-native-device-info": "5.5.7", "react-native-document-picker": "3.4.0", "react-native-elements": "2.0.0", @@ -72,7 +72,7 @@ "react-native-v8": "0.62.2-patch.1", "react-native-vector-icons": "6.6.0", "react-native-video": "5.0.2", - "react-native-webview": "9.4.0", + "react-native-webview": "github:mattermost/react-native-webview#b5e22940a613869d3999feac9451ee65352f4fbe", "react-native-youtube": "2.0.1", "react-redux": "7.2.0", "redux": "4.0.5", diff --git a/patches/react-native-webview+9.4.0.patch b/patches/react-native-webview+9.4.0.patch deleted file mode 100644 index a2c24bfbf..000000000 --- a/patches/react-native-webview+9.4.0.patch +++ /dev/null @@ -1,188 +0,0 @@ -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 1995d87..33bd83c 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 -@@ -2,8 +2,12 @@ package com.reactnativecommunity.webview; - - import android.annotation.SuppressLint; - import android.annotation.TargetApi; -+import android.app.Activity; -+import android.app.AlertDialog; - import android.app.DownloadManager; -+import android.content.ActivityNotFoundException; - import android.content.Context; -+import android.content.DialogInterface; - import android.content.Intent; - import android.content.pm.ActivityInfo; - import android.content.pm.PackageManager; -@@ -15,6 +19,7 @@ import android.os.Build; - import android.os.Environment; - import androidx.annotation.RequiresApi; - import androidx.core.content.ContextCompat; -+import android.text.InputType; - import android.text.TextUtils; - import android.view.Gravity; - import android.view.View; -@@ -25,7 +30,9 @@ import android.webkit.ConsoleMessage; - import android.webkit.CookieManager; - import android.webkit.DownloadListener; - import android.webkit.GeolocationPermissions; -+import android.webkit.HttpAuthHandler; - import android.webkit.JavascriptInterface; -+import android.widget.LinearLayout; - import android.webkit.PermissionRequest; - import android.webkit.URLUtil; - import android.webkit.ValueCallback; -@@ -35,6 +42,7 @@ import android.webkit.WebResourceResponse; - import android.webkit.WebSettings; - import android.webkit.WebView; - import android.webkit.WebViewClient; -+import android.widget.EditText; - import android.widget.FrameLayout; - - import com.facebook.react.views.scroll.ScrollEvent; -@@ -720,6 +728,7 @@ public class RNCWebViewManager extends SimpleViewManager { - - protected static class RNCWebViewClient extends WebViewClient { - -+ protected Activity mCurrentActivity; - protected boolean mLastLoadFailed = false; - protected @Nullable - ReadableArray mUrlPrefixesForDefaultIntent; -@@ -729,6 +738,10 @@ public class RNCWebViewManager extends SimpleViewManager { - ignoreErrFailedForThisURL = url; - } - -+ public void setCurrentActivity(Activity mCurrentActivity) { -+ this.mCurrentActivity = mCurrentActivity; -+ } -+ - @Override - public void onPageFinished(WebView webView, String url) { - super.onPageFinished(webView, url); -@@ -810,6 +823,49 @@ public class RNCWebViewManager extends SimpleViewManager { - new TopLoadingErrorEvent(webView.getId(), eventData)); - } - -+ @Override -+ public void onReceivedHttpAuthRequest(WebView view, -+ final HttpAuthHandler handler, String host, String realm) -+ { -+ if (this.mCurrentActivity != null) { -+ final EditText usernameInput = new EditText(this.mCurrentActivity); -+ usernameInput.setHint("Username"); -+ -+ final EditText passwordInput = new EditText(this.mCurrentActivity); -+ passwordInput.setHint("Password"); -+ passwordInput.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); -+ -+ LinearLayout layout = new LinearLayout(this.mCurrentActivity); -+ layout.setOrientation(LinearLayout.VERTICAL); -+ layout.addView(usernameInput); -+ layout.addView(passwordInput); -+ -+ AlertDialog.Builder authDialog = new AlertDialog.Builder(this.mCurrentActivity) -+ .setTitle("Authentication Challenge") -+ .setMessage(host + " requires user name and password ") -+ .setView(layout) -+ .setCancelable(false) -+ .setPositiveButton("OK", new DialogInterface.OnClickListener() { -+ public void onClick(DialogInterface dialogInterface, int i) { -+ handler.proceed(usernameInput.getText().toString(), passwordInput.getText().toString()); -+ dialogInterface.dismiss(); -+ } -+ }) -+ .setNegativeButton("Cancel", new DialogInterface.OnClickListener() { -+ public void onClick(DialogInterface dialogInterface, int i) { -+ dialogInterface.dismiss(); -+ handler.cancel(); -+ } -+ }); -+ -+ if (view != null) { -+ authDialog.show(); -+ } -+ } else { -+ handler.cancel(); -+ } -+ } -+ - @RequiresApi(api = Build.VERSION_CODES.M) - @Override - public void onReceivedHttpError( -@@ -1010,6 +1066,7 @@ public class RNCWebViewManager extends SimpleViewManager { - protected boolean sendContentSizeChangeEvents = false; - private OnScrollDispatchHelper mOnScrollDispatchHelper; - protected boolean hasScrollEvent = false; -+ protected ReactContext reactContext; - - /** - * WebView must be created with an context of the current activity -@@ -1019,6 +1076,7 @@ public class RNCWebViewManager extends SimpleViewManager { - */ - public RNCWebView(ThemedReactContext reactContext) { - super(reactContext); -+ this.reactContext = reactContext; - } - - public void setIgnoreErrFailedForThisURL(String url) { -@@ -1069,6 +1127,9 @@ public class RNCWebViewManager extends SimpleViewManager { - super.setWebViewClient(client); - if (client instanceof RNCWebViewClient) { - mRNCWebViewClient = (RNCWebViewClient) client; -+ if (this.reactContext != null && this.reactContext.getCurrentActivity() != null && mRNCWebViewClient != null) { -+ mRNCWebViewClient.setCurrentActivity(this.reactContext.getCurrentActivity()); -+ } - } - } - -diff --git a/node_modules/react-native-webview/apple/RNCWebView.m b/node_modules/react-native-webview/apple/RNCWebView.m -index d2f9956..4b8d0fe 100644 ---- a/node_modules/react-native-webview/apple/RNCWebView.m -+++ b/node_modules/react-native-webview/apple/RNCWebView.m -@@ -737,7 +737,44 @@ - (void) webView:(WKWebView *)webView - if (webView.URL != nil) { - host = webView.URL.host; - } -- if ([[challenge protectionSpace] authenticationMethod] == NSURLAuthenticationMethodClientCertificate) { -+ -+ NSString *authenticationMethod = [[challenge protectionSpace] authenticationMethod]; -+ -+ if (authenticationMethod == NSURLAuthenticationMethodNTLM || authenticationMethod == NSURLAuthenticationMethodNegotiate) { -+ NSString *title = @"Authentication Challenge"; -+ NSString *message = [NSString stringWithFormat:@"%@ requires user name and password", host]; -+ UIAlertController *alertController = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; -+ [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { -+ textField.placeholder = @"User"; -+ }]; -+ -+ [alertController addTextFieldWithConfigurationHandler:^(UITextField *textField) { -+ textField.placeholder = @"Password"; -+ textField.secureTextEntry = YES; -+ }]; -+ -+ [alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { -+ NSString *userName = ((UITextField *)alertController.textFields[0]).text; -+ NSString *password = ((UITextField *)alertController.textFields[1]).text; -+ NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:userName password:password persistence:NSURLCredentialPersistenceNone]; -+ -+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential); -+ }]]; -+ -+ [alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { -+ completionHandler(NSURLSessionAuthChallengeUseCredential, nil); -+ }]]; -+ -+ dispatch_async(dispatch_get_main_queue(), ^{ -+ UIViewController *rootVC = UIApplication.sharedApplication.delegate.window.rootViewController; -+ -+ while (rootVC.presentedViewController != nil) { -+ rootVC = rootVC.presentedViewController; -+ } -+ [rootVC presentViewController:alertController animated:YES completion:^{}]; -+ }); -+ return; -+ } else if (authenticationMethod == NSURLAuthenticationMethodClientCertificate) { - completionHandler(NSURLSessionAuthChallengeUseCredential, clientAuthenticationCredential); - return; - } diff --git a/test/setup.js b/test/setup.js index 72a5916c7..0bf8d9a49 100644 --- a/test/setup.js +++ b/test/setup.js @@ -154,7 +154,7 @@ jest.mock('react-native-localize', () => ({ ]), })); -jest.mock('@react-native-community/cookies', () => ({ +jest.mock('react-native-cookies', () => ({ addEventListener: jest.fn(), removeEventListener: jest.fn(), openURL: jest.fn(),