From 0c882ed2249a75ab23f93f10a7f81ed17dfad935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:24:34 +0000 Subject: [PATCH 01/41] Port: remove webviewref validation --- app/core/BackgroundBridge/Port.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/core/BackgroundBridge/Port.ts b/app/core/BackgroundBridge/Port.ts index 78dff7d2b43..49c47f97079 100644 --- a/app/core/BackgroundBridge/Port.ts +++ b/app/core/BackgroundBridge/Port.ts @@ -19,9 +19,9 @@ class Port extends EventEmitter { const js = this._isMainFrame ? JS_POST_MESSAGE_TO_PROVIDER(msg, origin) : JS_IFRAME_POST_MESSAGE_TO_PROVIDER(msg, origin); - if (this._window.webViewRef?.current) { - this._window?.injectJavaScript(js); - } + console.log('Post js', js); + console.log('this._window', this._window); + this._window?.injectJavaScript(js); }; } From 372ada60fcc89fc35f6c490470967280ec1cb2eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Fri, 15 Dec 2023 17:07:48 +0000 Subject: [PATCH 02/41] use react-native-webview fork --- package.json | 2 +- yarn.lock | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 18e072dc54f..56b9d54819f 100644 --- a/package.json +++ b/package.json @@ -349,7 +349,7 @@ "react-native-vector-icons": "6.4.2", "react-native-video": "5.2.1", "react-native-view-shot": "^3.1.2", - "react-native-webview": "11.13.0", + "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#9386bb762e8c740b676d31e2ef5c20e34421c36a", "react-native-webview-invoke": "^0.6.2", "react-redux": "7.2.4", "readable-stream": "2.3.7", diff --git a/yarn.lock b/yarn.lock index 9ede736669a..ca831b5c890 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22779,10 +22779,16 @@ react-native-webview-invoke@^0.6.2: resolved "https://registry.yarnpkg.com/react-native-webview-invoke/-/react-native-webview-invoke-0.6.2.tgz#75cc27ef98ea1cbc9386269347d3aafe90d33aa3" integrity sha512-PCzP7Zl3XwHU10JYS8nR0gwuR8XiOO0MhC8y9ZuPPI+HeISn95GvNYhOXxeLgfbdbUcpNWh1HqxPDySlfCIqxg== -react-native-webview@11.13.0: - version "11.13.0" - resolved "https://registry.yarnpkg.com/react-native-webview/-/react-native-webview-11.13.0.tgz#a2eca0f87b2ae9bba0dd8144594aeff9947cc5d6" - integrity sha512-jjQAKWv8JzRmcn76fMe4lXD84AAeR7kn43kAmUe1GX312BMLaP+RbKlgpYAlNuOBXL0YirItGKDrpaD0bNROOA== +"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#9386bb762e8c740b676d31e2ef5c20e34421c36a": + version "13.6.3" + resolved "https://github.com/MetaMask/react-native-webview-mm#9386bb762e8c740b676d31e2ef5c20e34421c36a" + dependencies: + escape-string-regexp "2.0.0" + invariant "2.2.4" + +"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#f4cafd9fbd7659ca44b6af2a09034ad2f5565aa7": + version "13.6.3" + resolved "https://github.com/MetaMask/react-native-webview-mm#f4cafd9fbd7659ca44b6af2a09034ad2f5565aa7" dependencies: escape-string-regexp "2.0.0" invariant "2.2.4" From eb604a6b980141bb5c3d46888c702f1c5c1ca2bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Fri, 15 Dec 2023 17:08:14 +0000 Subject: [PATCH 03/41] remove webview patches --- patches/react-native-webview+11.13.0.patch | 1325 -------------------- 1 file changed, 1325 deletions(-) delete mode 100644 patches/react-native-webview+11.13.0.patch diff --git a/patches/react-native-webview+11.13.0.patch b/patches/react-native-webview+11.13.0.patch deleted file mode 100644 index 6168b3ed384..00000000000 --- a/patches/react-native-webview+11.13.0.patch +++ /dev/null @@ -1,1325 +0,0 @@ -diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/CustomCookieJar.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/CustomCookieJar.java -new file mode 100644 -index 0000000..f4a6af9 ---- /dev/null -+++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/CustomCookieJar.java -@@ -0,0 +1,78 @@ -+package com.reactnativecommunity.webview; -+import android.util.Log; -+import android.webkit.CookieManager; -+import android.webkit.ValueCallback; -+import java.net.HttpURLConnection; -+import java.net.URL; -+import java.util.ArrayList; -+import java.util.Collection; -+import java.util.Iterator; -+import java.util.List; -+import java.util.Map; -+import okhttp3.Cookie; -+import okhttp3.CookieJar; -+import okhttp3.HttpUrl; -+ -+class CustomCookieJar implements CookieJar { -+ private Worker worker; -+ private CookieManager cookieManager; -+ -+ public CustomCookieJar() { -+ worker = new Worker(); -+ cookieManager = this.getCookieManager(); -+ } -+ -+ private CookieManager getCookieManager() { -+ CookieManager cookieManager = CookieManager.getInstance(); -+ cookieManager.setAcceptCookie(true); -+ return cookieManager; -+ } -+ -+ @Override -+ public void saveFromResponse(HttpUrl url, List cookies) { -+ worker.execute(() -> { -+ try { -+ -+ for (Cookie cookie : cookies) { -+ String _url = url.toString(); -+ String _cookie = cookie.toString(); -+ cookieManager.setCookie(_url, _cookie, new ValueCallback() { -+ @Override -+ public void onReceiveValue(Boolean value) {} -+ }); -+ cookieManager.flush(); -+ } -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } -+ }); -+ } -+ -+ @Override -+ public List loadForRequest(HttpUrl httpUrl) { -+ List cookieList = new ArrayList(); -+ try { -+ -+ if (cookieManager.hasCookies()) { -+ String response = cookieManager.getCookie(httpUrl.toString()); -+ -+ if (response != null) { -+ String[] browserCookies = response.split(";"); -+ -+ for (String cookieStr : browserCookies) { -+ Cookie cookie = Cookie.parse(httpUrl, cookieStr); -+ if (cookie == null) { -+ continue; -+ } -+ cookieList.add(cookie); -+ } -+ } -+ -+ } -+ return cookieList; -+ } catch (Exception e) { -+ e.printStackTrace(); -+ return cookieList; -+ } -+ } -+} -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 f743bbc..06d172f 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 -@@ -5,6 +5,7 @@ import android.annotation.TargetApi; - import android.app.Activity; - import android.app.DownloadManager; - import android.content.Context; -+import android.content.Intent; - import android.content.pm.ActivityInfo; - import android.content.pm.PackageManager; - import android.graphics.Bitmap; -@@ -14,6 +15,7 @@ import android.net.http.SslError; - import android.net.Uri; - import android.os.Build; - import android.os.Environment; -+import android.os.Handler; - import android.os.Message; - import android.os.SystemClock; - import android.text.TextUtils; -@@ -24,12 +26,17 @@ import android.view.View; - import android.view.ViewGroup; - import android.view.ViewGroup.LayoutParams; - import android.view.WindowManager; -+import android.view.inputmethod.InputMethodManager; - import android.webkit.ConsoleMessage; - import android.webkit.CookieManager; - import android.webkit.DownloadListener; - import android.webkit.GeolocationPermissions; - import android.webkit.JavascriptInterface; -+import android.webkit.JsPromptResult; -+import android.webkit.JsResult; - import android.webkit.RenderProcessGoneDetail; -+import android.webkit.ServiceWorkerClient; -+import android.webkit.ServiceWorkerController; - import android.webkit.SslErrorHandler; - import android.webkit.PermissionRequest; - import android.webkit.URLUtil; -@@ -40,6 +47,7 @@ import android.webkit.WebResourceResponse; - import android.webkit.WebSettings; - import android.webkit.WebView; - import android.webkit.WebViewClient; -+import android.widget.Button; - import android.widget.FrameLayout; - - import androidx.annotation.Nullable; -@@ -88,18 +96,54 @@ import com.reactnativecommunity.webview.events.TopRenderProcessGoneEvent; - import org.json.JSONException; - import org.json.JSONObject; - -+import java.io.ByteArrayInputStream; -+import java.io.IOException; -+import java.io.InputStream; - import java.io.UnsupportedEncodingException; -+import java.lang.reflect.Field; -+import java.net.CookieStore; -+import java.net.HttpCookie; -+import java.net.HttpURLConnection; - import java.net.MalformedURLException; -+import java.net.URI; -+import java.net.URISyntaxException; - import java.net.URL; - import java.net.URLEncoder; -+import java.nio.charset.Charset; -+import java.nio.charset.StandardCharsets; -+import java.nio.charset.UnsupportedCharsetException; -+import java.text.Bidi; - import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.Collection; - import java.util.Collections; - import java.util.HashMap; -+import java.util.HashSet; - import java.util.List; - import java.util.Locale; - import java.util.Map; -+import java.util.Objects; -+import java.util.Set; - import java.util.concurrent.atomic.AtomicReference; - -+import okhttp3.MediaType; -+import okhttp3.OkHttpClient; -+import okhttp3.Request; -+import okhttp3.RequestBody; -+import okhttp3.Response; -+ -+import android.view.inputmethod.BaseInputConnection; -+import android.view.inputmethod.EditorInfo; -+import android.view.inputmethod.InputConnection; -+ -+ -+import android.content.DialogInterface; -+import android.os.Bundle; -+import android.widget.Toast; -+ -+import androidx.appcompat.app.AlertDialog; -+import androidx.appcompat.app.AppCompatActivity; -+ - /** - * Manages instances of {@link WebView} - *

-@@ -137,13 +181,19 @@ public class RNCWebViewManager extends SimpleViewManager { - public static final int COMMAND_LOAD_URL = 7; - public static final int COMMAND_FOCUS = 8; - -+ protected static final String MIME_UNKNOWN = "application/octet-stream"; -+ protected static final String HTML_ENCODING = "UTF-8"; -+ protected static final long BYTES_IN_MEGABYTE = 1000000; -+ - // android commands - public static final int COMMAND_CLEAR_FORM_DATA = 1000; - public static final int COMMAND_CLEAR_CACHE = 1001; - public static final int COMMAND_CLEAR_HISTORY = 1002; - - protected static final String REACT_CLASS = "RNCWebView"; -- protected static final String HTML_ENCODING = "UTF-8"; -+ -+ protected static final String HEADER_CONTENT_TYPE = "content-type"; -+ - protected static final String HTML_MIME_TYPE = "text/html"; - protected static final String JAVASCRIPT_INTERFACE = "ReactNativeWebView"; - protected static final String HTTP_METHOD_POST = "POST"; -@@ -155,13 +205,19 @@ public class RNCWebViewManager extends SimpleViewManager { - - protected RNCWebChromeClient mWebChromeClient = null; - protected boolean mAllowsFullscreenVideo = false; -- protected @Nullable String mUserAgent = null; -- protected @Nullable String mUserAgentWithApplicationName = null; -+ protected @Nullable String RNUserAgent = null; -+ protected @Nullable String RNUserAgentWithApplicationName = null; -+ protected static String deviceUserAgent; -+ -+ protected static OkHttpClient httpClient; - - public RNCWebViewManager() { -- mWebViewConfig = new WebViewConfig() { -- public void configWebView(WebView webView) { -- } -+ mWebViewConfig = webView -> { -+ httpClient = new OkHttpClient.Builder() -+ .cookieJar(new CustomCookieJar()) -+ .followRedirects(false) -+ .followSslRedirects(false) -+ .build(); - }; - } - -@@ -182,6 +238,7 @@ public class RNCWebViewManager extends SimpleViewManager { - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - protected WebView createViewInstance(ThemedReactContext reactContext) { - RNCWebView webView = createRNCWebViewInstance(reactContext); -+ deviceUserAgent = webView.getSettings().getUserAgentString(); - setupWebChromeClient(reactContext, webView); - reactContext.addLifecycleEventListener(webView); - mWebViewConfig.configWebView(webView); -@@ -209,47 +266,161 @@ public class RNCWebViewManager extends SimpleViewManager { - } - - webView.setDownloadListener(new DownloadListener() { -+ protected ReactContext mReactContext; -+ - public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength) { - webView.setIgnoreErrFailedForThisURL(url); -+ this.mReactContext = reactContext; - - RNCWebViewModule module = getModule(reactContext); -- - DownloadManager.Request request = new DownloadManager.Request(Uri.parse(url)); -- - String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); -- String downloadMessage = "Downloading " + fileName; -+ //Filename validation checking for files that use RTL characters and do not allow those types -+ if(fileName == null || (fileName != null && (new Bidi(fileName, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT).isMixed()))) { -+ Toast.makeText(mReactContext, "Invalid filename or type", Toast.LENGTH_SHORT).show(); -+ } else { -+ AlertDialog.Builder builder = new AlertDialog.Builder(mReactContext); -+ builder.setMessage("Do you want to download \n" + fileName + "?"); -+ builder.setCancelable(false); -+ builder.setPositiveButton("Download", new DialogInterface.OnClickListener() { -+ public void onClick(DialogInterface dialog, int which) { -+ String downloadMessage = "Downloading " + fileName; -+ -+ //Attempt to add cookie, if it exists -+ URL urlObj = null; -+ try { -+ urlObj = new URL(url); -+ String baseUrl = urlObj.getProtocol() + "://" + urlObj.getHost(); -+ String cookie = CookieManager.getInstance().getCookie(baseUrl); -+ request.addRequestHeader("Cookie", cookie); -+ } catch (MalformedURLException e) { -+ System.out.println("Error getting cookie for DownloadManager: " + e.toString()); -+ e.printStackTrace(); -+ } - -- //Attempt to add cookie, if it exists -- URL urlObj = null; -- try { -- urlObj = new URL(url); -- String baseUrl = urlObj.getProtocol() + "://" + urlObj.getHost(); -- String cookie = CookieManager.getInstance().getCookie(baseUrl); -- request.addRequestHeader("Cookie", cookie); -- } catch (MalformedURLException e) { -- System.out.println("Error getting cookie for DownloadManager: " + e.toString()); -- e.printStackTrace(); -+ //Finish setting up request -+ request.addRequestHeader("User-Agent", userAgent); -+ request.setTitle(fileName); -+ request.setDescription(downloadMessage); -+ request.allowScanningByMediaScanner(); -+ request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); -+ request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); -+ module.setDownloadRequest(request); -+ if (module.grantFileDownloaderPermissions()) { -+ module.downloadFile(); -+ } -+ } -+ }); -+ builder.setNegativeButton("Cancel", (DialogInterface.OnClickListener) (dialog, which) -> { -+ return; -+ }); -+ AlertDialog alertDialog = builder.create(); -+ alertDialog.show(); - } -+ } -+ }); - -- //Finish setting up request -- request.addRequestHeader("User-Agent", userAgent); -- request.setTitle(fileName); -- request.setDescription(downloadMessage); -- request.allowScanningByMediaScanner(); -- request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); -- request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); -+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { -+ ServiceWorkerController swController = ServiceWorkerController.getInstance(); -+ swController.setServiceWorkerClient(new ServiceWorkerClient() { -+ @Override -+ public WebResourceResponse shouldInterceptRequest(WebResourceRequest request) { -+ String method = request.getMethod(); - -- module.setDownloadRequest(request); -+ if (method.equals("GET")) { -+ WebResourceResponse response = RNCWebViewManager.this.shouldInterceptRequest(request, false, webView); -+ if (response != null) { -+ return response; -+ } -+ } - -- if (module.grantFileDownloaderPermissions()) { -- module.downloadFile(); -+ return super.shouldInterceptRequest(request); - } -- } -- }); -+ }); -+ } - - return webView; - } - -+ private Boolean urlStringLooksInvalid(String urlString) { -+ return urlString == null || -+ urlString.trim().equals("") || -+ !(urlString.startsWith("http") && !urlString.startsWith("www")) || -+ urlString.contains("|"); -+ } -+ -+ public static Boolean responseRequiresJSInjection(Response response) { -+ if (response.isRedirect()) { -+ return false; -+ } -+ final String contentTypeAndCharset = response.header(HEADER_CONTENT_TYPE, MIME_UNKNOWN); -+ final int responseCode = response.code(); -+ -+ boolean contentTypeIsHtml = contentTypeAndCharset.startsWith(HTML_MIME_TYPE); -+ boolean responseCodeIsInjectible = responseCode == 200; -+ String responseBody = ""; -+ -+ if (contentTypeIsHtml && responseCodeIsInjectible) { -+ try { -+ assert response.body() != null; -+ responseBody = response.peekBody(BYTES_IN_MEGABYTE).string(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ return false; -+ } -+ -+ -+ boolean responseBodyContainsHTMLLikeString = responseBody.matches("[\\S\\s]*<[a-z]+[\\S\\s]*>[\\S\\s]*"); -+ return responseBodyContainsHTMLLikeString; -+ } else { -+ return false; -+ } -+ } -+ -+ public WebResourceResponse shouldInterceptRequest(WebResourceRequest request, Boolean onlyMainFrame, RNCWebView webView) { -+ Uri url = request.getUrl(); -+ String urlStr = url.toString(); -+ -+ if (onlyMainFrame && !request.isForMainFrame() || -+ urlStringLooksInvalid(urlStr)) { -+ return null; -+ } -+ -+ String _userAgent; -+ -+ if (RNUserAgent != null) { -+ _userAgent = RNUserAgent; -+ } else { -+ _userAgent = deviceUserAgent; -+ } -+ -+ try { -+ Request req = new Request.Builder() -+ .url(urlStr) -+ .header("User-Agent", _userAgent) -+ .build(); -+ -+ Response response = httpClient.newCall(req).execute(); -+ -+ if (!responseRequiresJSInjection(response)) { -+ return null; -+ } -+ -+ InputStream is = response.body().byteStream(); -+ MediaType contentType = response.body().contentType(); -+ Charset charset = contentType != null ? contentType.charset(StandardCharsets.UTF_8) : StandardCharsets.UTF_8; -+ -+ RNCWebView reactWebView = (RNCWebView) webView; -+ if (response.code() == HttpURLConnection.HTTP_OK) { -+ is = new InputStreamWithInjectedJS(is, reactWebView.injectedJSBeforeContentLoaded, charset); -+ } -+ -+ return new WebResourceResponse("text/html", charset.name(), is); -+ } catch (IOException e) { -+ return null; -+ } -+ } -+ - @ReactProp(name = "javaScriptEnabled") - public void setJavaScriptEnabled(WebView view, boolean enabled) { - view.getSettings().setJavaScriptEnabled(enabled); -@@ -285,13 +456,10 @@ public class RNCWebViewManager extends SimpleViewManager { - if (enabled) { - Context ctx = view.getContext(); - if (ctx != null) { -- view.getSettings().setAppCachePath(ctx.getCacheDir().getAbsolutePath()); - view.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); -- view.getSettings().setAppCacheEnabled(true); - } - } else { - view.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); -- view.getSettings().setAppCacheEnabled(false); - } - } - -@@ -327,12 +495,12 @@ public class RNCWebViewManager extends SimpleViewManager { - public void setLayerType(WebView view, String layerTypeString) { - int layerType = View.LAYER_TYPE_NONE; - switch (layerTypeString) { -- case "hardware": -- layerType = View.LAYER_TYPE_HARDWARE; -- break; -- case "software": -- layerType = View.LAYER_TYPE_SOFTWARE; -- break; -+ case "hardware": -+ layerType = View.LAYER_TYPE_HARDWARE; -+ break; -+ case "software": -+ layerType = View.LAYER_TYPE_SOFTWARE; -+ break; - } - view.setLayerType(layerType, null); - } -@@ -387,9 +555,9 @@ public class RNCWebViewManager extends SimpleViewManager { - @ReactProp(name = "userAgent") - public void setUserAgent(WebView view, @Nullable String userAgent) { - if (userAgent != null) { -- mUserAgent = userAgent; -+ RNUserAgent = userAgent; - } else { -- mUserAgent = null; -+ RNUserAgent = null; - } - this.setUserAgentString(view); - } -@@ -399,19 +567,19 @@ public class RNCWebViewManager extends SimpleViewManager { - if(applicationName != null) { - if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - String defaultUserAgent = WebSettings.getDefaultUserAgent(view.getContext()); -- mUserAgentWithApplicationName = defaultUserAgent + " " + applicationName; -+ RNUserAgentWithApplicationName = defaultUserAgent + " " + applicationName; - } - } else { -- mUserAgentWithApplicationName = null; -+ RNUserAgentWithApplicationName = null; - } - this.setUserAgentString(view); - } - - protected void setUserAgentString(WebView view) { -- if(mUserAgent != null) { -- view.getSettings().setUserAgentString(mUserAgent); -- } else if(mUserAgentWithApplicationName != null) { -- view.getSettings().setUserAgentString(mUserAgentWithApplicationName); -+ if(RNUserAgent != null) { -+ view.getSettings().setUserAgentString(RNUserAgent); -+ } else if(RNUserAgentWithApplicationName != null) { -+ view.getSettings().setUserAgentString(RNUserAgentWithApplicationName); - } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - // handle unsets of `userAgent` prop as long as device is >= API 17 - view.getSettings().setUserAgentString(WebSettings.getDefaultUserAgent(view.getContext())); -@@ -490,7 +658,6 @@ public class RNCWebViewManager extends SimpleViewManager { - - // Disable caching - view.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); -- view.getSettings().setAppCacheEnabled(false); - view.clearHistory(); - view.clearCache(true); - -@@ -842,13 +1009,116 @@ public class RNCWebViewManager extends SimpleViewManager { - } - } - -- protected static class RNCWebViewClient extends WebViewClient { -+ public static class InputStreamWithInjectedJS extends InputStream { -+ private InputStream pageIS; -+ private InputStream scriptIS; -+ private Charset charset; -+ private static final String REACT_CLASS = "InputStreamWithInjectedJS"; -+ private static Map script = new HashMap<>(); -+ -+ private boolean hasJS = false; -+ private boolean headWasFound = false; -+ private boolean scriptWasInjected = false; -+ -+ private int lowercaseD = 100; -+ private int closingTag = 62; -+ private boolean hasClosingHead = false; -+ -+ private StringBuffer contentBuffer = new StringBuffer(); -+ -+ @SuppressLint("LongLogTag") -+ private static Charset getCharset(String charsetName) { -+ Charset cs = StandardCharsets.UTF_8; -+ try { -+ if (charsetName != null) { -+ cs = Charset.forName(charsetName); -+ } -+ } catch (UnsupportedCharsetException e) { -+ Log.d(REACT_CLASS, "wrong charset: " + charsetName); -+ } -+ -+ return cs; -+ } -+ -+ private static InputStream getScript(Charset charset) { -+ String js = script.get(charset); -+ if (js == null) { -+ String defaultJs = script.get(StandardCharsets.UTF_8); -+ js = new String(defaultJs.getBytes(StandardCharsets.UTF_8), charset); -+ script.put(charset, js); -+ } -+ -+ return new ByteArrayInputStream(js.getBytes(charset)); -+ } -+ -+ InputStreamWithInjectedJS(InputStream is, String js, Charset charset) { -+ if (js == null) { -+ this.pageIS = is; -+ } else { -+ this.hasJS = true; -+ this.charset = charset; -+ Charset cs = StandardCharsets.UTF_8; -+ String jsScript = ""; -+ script.put(cs, jsScript); -+ this.pageIS = is; -+ } -+ } -+ -+ @Override -+ public int read() throws IOException { -+ if (scriptWasInjected || !hasJS) { -+ return pageIS.read(); -+ } -+ -+ if (!scriptWasInjected && headWasFound) { -+ int nextByte; -+ if (!hasClosingHead) { -+ nextByte = pageIS.read(); -+ if (nextByte != closingTag) { -+ return nextByte; -+ } -+ hasClosingHead = true; -+ return nextByte; -+ } -+ nextByte = scriptIS.read(); -+ if (nextByte == -1) { -+ scriptIS.close(); -+ scriptWasInjected = true; -+ return pageIS.read(); -+ } else { -+ return nextByte; -+ } -+ } -+ -+ if (!headWasFound) { -+ int nextByte = pageIS.read(); -+ contentBuffer.append((char) nextByte); -+ int bufferLength = contentBuffer.length(); -+ if (nextByte == lowercaseD && bufferLength >= 5) { -+ if (contentBuffer.substring(bufferLength - 5).equals(" { - @Override - public void onPageFinished(WebView webView, String url) { - super.onPageFinished(webView, url); -+ // Only return the URL that the web view is currently showing. -+ String visibleUrl = webView.getUrl(); -+ Boolean isFinishedLoading = url.equals(visibleUrl); - -- if (!mLastLoadFailed) { -+ if (!mLastLoadFailed && isFinishedLoading) { -+ if(Objects.nonNull(mWebChromeClient)) mWebChromeClient.blockJsDuringLoading = false; - RNCWebView reactWebView = (RNCWebView) webView; - - reactWebView.callInjectedJavaScript(); - -- emitFinishEvent(webView, url); -+ emitFinishEvent(webView, visibleUrl); - } - } - - @Override - public void onPageStarted(WebView webView, String url, Bitmap favicon) { - super.onPageStarted(webView, url, favicon); -+ if(Objects.nonNull(mWebChromeClient)) mWebChromeClient.blockJsDuringLoading = true; - mLastLoadFailed = false; - -- RNCWebView reactWebView = (RNCWebView) webView; -- reactWebView.callInjectedJavaScriptBeforeContentLoaded(); -- - ((RNCWebView) webView).dispatchEvent( - webView, - new TopLoadingStartEvent( -@@ -882,6 +1154,20 @@ public class RNCWebViewManager extends SimpleViewManager { - createWebViewEvent(webView, url))); - } - -+ @Override -+ public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest request) { -+ String method = request.getMethod(); -+ -+ if (method.equals("GET")) { -+ WebResourceResponse response = RNCWebViewManager.this.shouldInterceptRequest(request, true, (RNCWebView)webView); -+ if (response != null) { -+ return response; -+ } -+ } -+ -+ return super.shouldInterceptRequest(webView, request); -+ } -+ - @Override - public boolean shouldOverrideUrlLoading(WebView view, String url) { - final RNCWebView rncWebView = (RNCWebView) view; -@@ -891,7 +1177,6 @@ public class RNCWebViewManager extends SimpleViewManager { - final Pair> lock = RNCWebViewModule.shouldOverrideUrlLoadingLock.getNewLock(); - final int lockIdentifier = lock.first; - final AtomicReference lockObject = lock.second; -- - final WritableMap event = createWebViewEvent(view, url); - event.putInt("lockIdentifier", lockIdentifier); - rncWebView.sendDirectMessage("onShouldStartLoadWithRequest", event); -@@ -919,6 +1204,17 @@ public class RNCWebViewManager extends SimpleViewManager { - RNCWebViewModule.shouldOverrideUrlLoadingLock.removeLock(lockIdentifier); - - return shouldOverride; -+ } else if (url != null && Arrays.asList(DEEPLINK_ALLOW_LIST).contains(url)) { -+ // This case is used to support deeplinking within the webview. We are limiting this but -+ // if more links are to be supported we should consider a more scaleable solution. That is -+ // secure and scaleable. -+ Intent intent = new Intent(Intent.ACTION_VIEW); -+ intent.setData(Uri.parse(url)); -+ if(intent.resolveActivity(view.getContext().getPackageManager()) != null) { -+ view.getContext().startActivity(intent); -+ return true; -+ } else -+ return false; - } else { - FLog.w(TAG, "Couldn't use blocking synchronous call for onShouldStartLoadWithRequest due to debugging or missing Catalyst instance, falling back to old event-and-load."); - progressChangedFilter.setWaitingForCommandLoadUrl(true); -@@ -934,67 +1230,86 @@ public class RNCWebViewManager extends SimpleViewManager { - @TargetApi(Build.VERSION_CODES.N) - @Override - public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { -+ if(Objects.nonNull(mWebChromeClient)) mWebChromeClient.blockJsDuringLoading = true; -+ -+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { -+ -+ /* -+ * In order to follow redirects properly, we return null in interceptRequest(). -+ * Doing this breaks the web3 injection on the resulting page, so we have to reload to -+ * make sure web3 is available. -+ * */ -+ -+ if (request.isForMainFrame() && request.isRedirect()) { -+ view.loadUrl(request.getUrl().toString()); -+ return true; -+ } -+ } -+ - final String url = request.getUrl().toString(); -+ - return this.shouldOverrideUrlLoading(view, url); - } - -+ -+ - @Override - public void onReceivedSslError(final WebView webView, final SslErrorHandler handler, final SslError error) { -- // onReceivedSslError is called for most requests, per Android docs: https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%2520android.webkit.SslErrorHandler,%2520android.net.http.SslError) -- // WebView.getUrl() will return the top-level window URL. -- // If a top-level navigation triggers this error handler, the top-level URL will be the failing URL (not the URL of the currently-rendered page). -- // This is desired behavior. We later use these values to determine whether the request is a top-level navigation or a subresource request. -- String topWindowUrl = webView.getUrl(); -- String failingUrl = error.getUrl(); -- -- // Cancel request after obtaining top-level URL. -- // If request is cancelled before obtaining top-level URL, undesired behavior may occur. -- // Undesired behavior: Return value of WebView.getUrl() may be the current URL instead of the failing URL. -- handler.cancel(); -- -- if (!topWindowUrl.equalsIgnoreCase(failingUrl)) { -- // If error is not due to top-level navigation, then do not call onReceivedError() -- Log.w("RNCWebViewManager", "Resource blocked from loading due to SSL error. Blocked URL: "+failingUrl); -- return; -- } -+ // onReceivedSslError is called for most requests, per Android docs: https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%2520android.webkit.SslErrorHandler,%2520android.net.http.SslError) -+ // WebView.getUrl() will return the top-level window URL. -+ // If a top-level navigation triggers this error handler, the top-level URL will be the failing URL (not the URL of the currently-rendered page). -+ // This is desired behavior. We later use these values to determine whether the request is a top-level navigation or a subresource request. -+ String topWindowUrl = webView.getUrl(); -+ String failingUrl = error.getUrl(); -+ -+ // Cancel request after obtaining top-level URL. -+ // If request is cancelled before obtaining top-level URL, undesired behavior may occur. -+ // Undesired behavior: Return value of WebView.getUrl() may be the current URL instead of the failing URL. -+ handler.cancel(); -+ -+ if (!topWindowUrl.equalsIgnoreCase(failingUrl)) { -+ // If error is not due to top-level navigation, then do not call onReceivedError() -+ Log.w("RNCWebViewManager", "Resource blocked from loading due to SSL error. Blocked URL: "+failingUrl); -+ return; -+ } - -- int code = error.getPrimaryError(); -- String description = ""; -- String descriptionPrefix = "SSL error: "; -- -- // https://developer.android.com/reference/android/net/http/SslError.html -- switch (code) { -- case SslError.SSL_DATE_INVALID: -- description = "The date of the certificate is invalid"; -- break; -- case SslError.SSL_EXPIRED: -- description = "The certificate has expired"; -- break; -- case SslError.SSL_IDMISMATCH: -- description = "Hostname mismatch"; -- break; -- case SslError.SSL_INVALID: -- description = "A generic error occurred"; -- break; -- case SslError.SSL_NOTYETVALID: -- description = "The certificate is not yet valid"; -- break; -- case SslError.SSL_UNTRUSTED: -- description = "The certificate authority is not trusted"; -- break; -- default: -- description = "Unknown SSL Error"; -- break; -- } -+ int code = error.getPrimaryError(); -+ String description = ""; -+ String descriptionPrefix = "SSL error: "; - -- description = descriptionPrefix + description; -+ // https://developer.android.com/reference/android/net/http/SslError.html -+ switch (code) { -+ case SslError.SSL_DATE_INVALID: -+ description = "The date of the certificate is invalid"; -+ break; -+ case SslError.SSL_EXPIRED: -+ description = "The certificate has expired"; -+ break; -+ case SslError.SSL_IDMISMATCH: -+ description = "Hostname mismatch"; -+ break; -+ case SslError.SSL_INVALID: -+ description = "A generic error occurred"; -+ break; -+ case SslError.SSL_NOTYETVALID: -+ description = "The certificate is not yet valid"; -+ break; -+ case SslError.SSL_UNTRUSTED: -+ description = "The certificate authority is not trusted"; -+ break; -+ default: -+ description = "Unknown SSL Error"; -+ break; -+ } - -- this.onReceivedError( -- webView, -- code, -- description, -- failingUrl -- ); -+ description = descriptionPrefix + description; -+ -+ this.onReceivedError( -+ webView, -+ code, -+ description, -+ failingUrl -+ ); - } - - @Override -@@ -1005,9 +1320,9 @@ public class RNCWebViewManager extends SimpleViewManager { - String failingUrl) { - - if (ignoreErrFailedForThisURL != null -- && failingUrl.equals(ignoreErrFailedForThisURL) -- && errorCode == -1 -- && description.equals("net::ERR_FAILED")) { -+ && failingUrl.equals(ignoreErrFailedForThisURL) -+ && errorCode == -1 -+ && description.equals("net::ERR_FAILED")) { - - // This is a workaround for a bug in the WebView. - // See these chromium issues for more context: -@@ -1056,36 +1371,36 @@ public class RNCWebViewManager extends SimpleViewManager { - @TargetApi(Build.VERSION_CODES.O) - @Override - public boolean onRenderProcessGone(WebView webView, RenderProcessGoneDetail detail) { -- // WebViewClient.onRenderProcessGone was added in O. -- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { -- return false; -- } -- super.onRenderProcessGone(webView, detail); -+ // WebViewClient.onRenderProcessGone was added in O. -+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { -+ return false; -+ } -+ super.onRenderProcessGone(webView, detail); - -- if(detail.didCrash()){ -- Log.e("RNCWebViewManager", "The WebView rendering process crashed."); -- } -- else{ -- Log.w("RNCWebViewManager", "The WebView rendering process was killed by the system."); -- } -+ if(detail.didCrash()){ -+ Log.e("RNCWebViewManager", "The WebView rendering process crashed."); -+ } -+ else{ -+ Log.w("RNCWebViewManager", "The WebView rendering process was killed by the system."); -+ } - -- // if webView is null, we cannot return any event -- // since the view is already dead/disposed -- // still prevent the app crash by returning true. -- if(webView == null){ -- return true; -- } -+ // if webView is null, we cannot return any event -+ // since the view is already dead/disposed -+ // still prevent the app crash by returning true. -+ if(webView == null){ -+ return true; -+ } - -- WritableMap event = createWebViewEvent(webView, webView.getUrl()); -- event.putBoolean("didCrash", detail.didCrash()); -+ WritableMap event = createWebViewEvent(webView, webView.getUrl()); -+ event.putBoolean("didCrash", detail.didCrash()); - - ((RNCWebView) webView).dispatchEvent( -- webView, -- new TopRenderProcessGoneEvent(webView.getId(), event) -- ); -+ webView, -+ new TopRenderProcessGoneEvent(webView.getId(), event) -+ ); - -- // returning false would crash the app. -- return true; -+ // returning false would crash the app. -+ return true; - } - - protected void emitFinishEvent(WebView webView, String url) { -@@ -1138,6 +1453,7 @@ public class RNCWebViewManager extends SimpleViewManager { - - protected View mVideoView; - protected WebChromeClient.CustomViewCallback mCustomViewCallback; -+ protected boolean blockJsDuringLoading = true; //This boolean block JS prompts and alerts from displaying during loading - - /* - * - Permissions - -@@ -1211,8 +1527,8 @@ public class RNCWebViewManager extends SimpleViewManager { - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - @Override - public void onPermissionRequest(final PermissionRequest request) { -- - grantedPermissions = new ArrayList<>(); -+ ArrayList requestPermissionIdentifiers = new ArrayList<>(); - - ArrayList requestedAndroidPermissions = new ArrayList<>(); - for (String requestedResource : request.getResources()) { -@@ -1220,36 +1536,74 @@ public class RNCWebViewManager extends SimpleViewManager { - - if (requestedResource.equals(PermissionRequest.RESOURCE_AUDIO_CAPTURE)) { - androidPermission = Manifest.permission.RECORD_AUDIO; -+ requestPermissionIdentifiers.add("microphone"); - } else if (requestedResource.equals(PermissionRequest.RESOURCE_VIDEO_CAPTURE)) { - androidPermission = Manifest.permission.CAMERA; -+ requestPermissionIdentifiers.add("camera"); - } else if(requestedResource.equals(PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID)) { - androidPermission = PermissionRequest.RESOURCE_PROTECTED_MEDIA_ID; - } - // TODO: RESOURCE_MIDI_SYSEX, RESOURCE_PROTECTED_MEDIA_ID. -- - if (androidPermission != null) { -- if (ContextCompat.checkSelfPermission(mReactContext, androidPermission) == PackageManager.PERMISSION_GRANTED) { -- grantedPermissions.add(requestedResource); -- } else { -- requestedAndroidPermissions.add(androidPermission); -- } -+ if (ContextCompat.checkSelfPermission(mReactContext, androidPermission) == PackageManager.PERMISSION_GRANTED) { -+ grantedPermissions.add(requestedResource); -+ } else { -+ requestedAndroidPermissions.add(androidPermission); -+ } - } - } - -- // If all the permissions are already granted, send the response to the WebView synchronously -- if (requestedAndroidPermissions.isEmpty()) { -- request.grant(grantedPermissions.toArray(new String[0])); -- grantedPermissions = null; -- return; -- } -- -- // Otherwise, ask to Android System for native permissions asynchronously -+ if (!requestedAndroidPermissions.isEmpty()) { -+ // Show the dialog and request the permissions -+ AlertDialog.Builder builder = new AlertDialog.Builder(mReactContext); -+ String permissionsIdentifiers = TextUtils.join(" and ", requestPermissionIdentifiers); -+ builder.setMessage("The app needs access to your " + permissionsIdentifiers + ". Allow?"); -+ builder.setCancelable(false); -+ builder.setPositiveButton("Allow", new DialogInterface.OnClickListener() { -+ public void onClick(DialogInterface dialog, int which) { -+ permissionRequest = request; -+ requestPermissions(requestedAndroidPermissions); -+ } -+ }); -+ builder.setNegativeButton("Don't allow", (DialogInterface.OnClickListener) (dialog, which) -> { -+ request.deny(); -+ }); - -- this.permissionRequest = request; -+ AlertDialog alertDialog = builder.create(); -+ alertDialog.show(); -+ // Delay making `allow` clickable for 500ms -+ Button posButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); -+ posButton.setEnabled(false); -+ this.runDelayed(() -> posButton.setEnabled(true), 500); -+ } else if (!grantedPermissions.isEmpty()) { -+ // You need to show to the user that the website is requesting permissions -+ // If that happens and the permissions are already granted you need to ask again -+ AlertDialog.Builder builder = new AlertDialog.Builder(mReactContext); -+ String permissionsIdentifiers = TextUtils.join(" and ", requestPermissionIdentifiers); -+ builder.setMessage("The app needs access to your " + permissionsIdentifiers + ". Allow?"); -+ builder.setCancelable(false); -+ builder.setPositiveButton("Allow", new DialogInterface.OnClickListener() { -+ public void onClick(DialogInterface dialog, int which) { -+ request.grant(grantedPermissions.toArray(new String[0])); -+ } -+ }); -+ builder.setNegativeButton("Don't allow", (DialogInterface.OnClickListener) (dialog, which) -> { -+ request.deny(); -+ }); - -- requestPermissions(requestedAndroidPermissions); -+ AlertDialog alertDialog = builder.create(); -+ alertDialog.show(); -+ // Delay making `allow` clickable for 500ms -+ Button posButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE); -+ posButton.setEnabled(false); -+ this.runDelayed(() -> posButton.setEnabled(true), 500); -+ } - } - -+ private void runDelayed(Runnable function, long delayMillis) { -+ Handler handler = new Handler(); -+ handler.postDelayed(function, delayMillis); -+ } - - @Override - public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { -@@ -1402,6 +1756,15 @@ public class RNCWebViewManager extends SimpleViewManager { - } - } - -+ @Override -+ public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { -+ if(blockJsDuringLoading) { -+ result.cancel(); -+ return true; -+ } else -+ return super.onJsPrompt(view, url, message, defaultValue, result); -+ } -+ - @Override - public void onHostPause() { } - -@@ -1447,6 +1810,13 @@ public class RNCWebViewManager extends SimpleViewManager { - protected boolean nestedScrollEnabled = false; - protected ProgressChangedFilter progressChangedFilter; - -+ /** -+ * Taken from EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING We can't use that -+ * value directly as it was only added on Oreo, but we can apply the value -+ * anyway. -+ */ -+ private static final int IME_FLAG_NO_PERSONALIZED_LEARNING = 0x1000000; -+ - /** - * WebView must be created with an context of the current activity - *

-@@ -1475,6 +1845,42 @@ public class RNCWebViewManager extends SimpleViewManager { - this.nestedScrollEnabled = nestedScrollEnabled; - } - -+ @Override -+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) { -+ InputConnection inputConnection; -+ if (!usingGoogleKeyboard()) { -+ inputConnection = super.onCreateInputConnection(outAttrs); -+ } else { -+ inputConnection = new BaseInputConnection(this, false); -+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { -+ outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING; -+ } else { -+ // Cover OS versions below Oreo -+ outAttrs.imeOptions = IME_FLAG_NO_PERSONALIZED_LEARNING; -+ } -+ } -+ -+ return inputConnection; -+ } -+ -+ public boolean usingGoogleKeyboard() { -+ final InputMethodManager richImm = -+ (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); -+ -+ boolean isKeyboard = false; -+ -+ final Field field; -+ try { -+ field = richImm.getClass().getDeclaredField("mCurId"); -+ field.setAccessible(true); -+ Object value = field.get(richImm); -+ isKeyboard = Objects.equals(value, "com.google.android.inputmethod.latin/com.android.inputmethod.latin.LatinIME"); -+ } catch (IllegalAccessException | NoSuchFieldException e) { -+ return false; -+ } -+ return isKeyboard; -+ } -+ - @Override - public void onHostResume() { - // do nothing -@@ -1533,6 +1939,8 @@ public class RNCWebViewManager extends SimpleViewManager { - } - } - -+ -+ - public @Nullable - RNCWebViewClient getRNCWebViewClient() { - return mRNCWebViewClient; -@@ -1609,8 +2017,8 @@ public class RNCWebViewManager extends SimpleViewManager { - - public void callInjectedJavaScriptBeforeContentLoaded() { - if (getSettings().getJavaScriptEnabled() && -- injectedJSBeforeContentLoaded != null && -- !TextUtils.isEmpty(injectedJSBeforeContentLoaded)) { -+ injectedJSBeforeContentLoaded != null && -+ !TextUtils.isEmpty(injectedJSBeforeContentLoaded)) { - evaluateJavascriptWithFallback("(function() {\n" + injectedJSBeforeContentLoaded + ";\n})();"); - } - } -@@ -1672,16 +2080,16 @@ public class RNCWebViewManager extends SimpleViewManager { - - if (mOnScrollDispatchHelper.onScrollChanged(x, y)) { - ScrollEvent event = ScrollEvent.obtain( -- this.getId(), -- ScrollEventType.SCROLL, -- x, -- y, -- mOnScrollDispatchHelper.getXFlingVelocity(), -- mOnScrollDispatchHelper.getYFlingVelocity(), -- this.computeHorizontalScrollRange(), -- this.computeVerticalScrollRange(), -- this.getWidth(), -- this.getHeight()); -+ this.getId(), -+ ScrollEventType.SCROLL, -+ x, -+ y, -+ mOnScrollDispatchHelper.getXFlingVelocity(), -+ mOnScrollDispatchHelper.getYFlingVelocity(), -+ this.computeHorizontalScrollRange(), -+ this.computeVerticalScrollRange(), -+ this.getWidth(), -+ this.getHeight()); - - dispatchEvent(this, event); - } -diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/Worker.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/Worker.java -new file mode 100644 -index 0000000..b9581ac ---- /dev/null -+++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/Worker.java -@@ -0,0 +1,21 @@ -+package com.reactnativecommunity.webview; -+ -+import android.os.Handler; -+import android.os.HandlerThread; -+ -+class Worker extends HandlerThread { -+ private Handler handler; -+ -+ private static final String TAG = "WORKER"; -+ -+ public Worker() { -+ super(TAG); -+ start(); -+ handler = new Handler(getLooper()); -+ } -+ -+ public Worker execute(Runnable task) { -+ handler.post(task); -+ return this; -+ } -+} -\ No newline at end of file -diff --git a/node_modules/react-native-webview/apple/RNCWebView.m b/node_modules/react-native-webview/apple/RNCWebView.m -index 28c078a..6f7d0b7 100644 ---- a/node_modules/react-native-webview/apple/RNCWebView.m -+++ b/node_modules/react-native-webview/apple/RNCWebView.m -@@ -105,6 +105,7 @@ static NSDictionary* customCertificatesForHost; - UIStatusBarStyle _savedStatusBarStyle; - #endif // !TARGET_OS_OSX - BOOL _savedStatusBarHidden; -+ BOOL _disablePromptDuringLoading; //Disables the display of prompts during site navigation/loading - - #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ - UIScrollViewContentInsetAdjustmentBehavior _savedContentInsetAdjustmentBehavior; -@@ -139,6 +140,7 @@ static NSDictionary* customCertificatesForHost; - _injectedJavaScriptForMainFrameOnly = YES; - _injectedJavaScriptBeforeContentLoaded = nil; - _injectedJavaScriptBeforeContentLoadedForMainFrameOnly = YES; -+ _disablePromptDuringLoading = YES; - - #if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 /* __IPHONE_11_0 */ - _savedContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; -@@ -417,6 +419,7 @@ static NSDictionary* customCertificatesForHost; - - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ - if ([keyPath isEqual:@"estimatedProgress"] && object == self.webView) { - if(_onLoadingProgress){ -+ _disablePromptDuringLoading = YES; - NSMutableDictionary *event = [self baseEvent]; - [event addEntriesFromDictionary:@{@"progress":[NSNumber numberWithDouble:self.webView.estimatedProgress]}]; - _onLoadingProgress(event); -@@ -492,6 +495,7 @@ static NSDictionary* customCertificatesForHost; - NSMutableDictionary *event = [self baseEvent]; - [event addEntriesFromDictionary: @{@"navigationType": message.body}]; - _onLoadingFinish(event); -+ _disablePromptDuringLoading = NO; - } - } else if ([message.name isEqualToString:MessageHandlerName]) { - if (_onMessage) { -@@ -851,11 +855,13 @@ static NSDictionary* customCertificatesForHost; - - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler - { - #if !TARGET_OS_OSX -- UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert]; -- [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { -- completionHandler(); -- }]]; -- [[self topViewController] presentViewController:alert animated:YES completion:NULL]; -+ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.7 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ -+ UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:message preferredStyle:UIAlertControllerStyleAlert]; -+ [alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { -+ completionHandler(); -+ }]]; -+ [[self topViewController] presentViewController:alert animated:YES completion:NULL]; -+ }); - #else - NSAlert *alert = [[NSAlert alloc] init]; - [alert setMessageText:message]; -@@ -894,44 +900,49 @@ static NSDictionary* customCertificatesForHost; - * prompt - */ - - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString *))completionHandler{ --#if !TARGET_OS_OSX -- UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:prompt preferredStyle:UIAlertControllerStyleAlert]; -- [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { -- textField.text = defaultText; -- }]; -- UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { -- completionHandler([[alert.textFields lastObject] text]); -- }]; -- [alert addAction:okAction]; -- UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { -- completionHandler(nil); -- }]; -- [alert addAction:cancelAction]; -- alert.preferredAction = okAction; -- [[self topViewController] presentViewController:alert animated:YES completion:NULL]; --#else -- NSAlert *alert = [[NSAlert alloc] init]; -- [alert setMessageText:prompt]; - -- const NSRect RCTSingleTextFieldFrame = NSMakeRect(0.0, 0.0, 275.0, 22.0); -- NSTextField *textField = [[NSTextField alloc] initWithFrame:RCTSingleTextFieldFrame]; -- textField.cell.scrollable = YES; -- if (@available(macOS 10.11, *)) { -- textField.maximumNumberOfLines = 1; -- } -- textField.stringValue = defaultText; -- [alert setAccessoryView:textField]; -- -- [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button")]; -- [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"Cancel button")]; -- [alert beginSheetModalForWindow:[NSApp keyWindow] completionHandler:^(NSModalResponse response) { -- if (response == NSAlertFirstButtonReturn) { -- completionHandler([textField stringValue]); -+ if(!_disablePromptDuringLoading) { -+ #if !TARGET_OS_OSX -+ UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"" message:prompt preferredStyle:UIAlertControllerStyleAlert]; -+ [alert addTextFieldWithConfigurationHandler:^(UITextField *textField) { -+ textField.text = defaultText; -+ }]; -+ UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { -+ completionHandler([[alert.textFields lastObject] text]); -+ }]; -+ [alert addAction:okAction]; -+ UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction *action) { -+ completionHandler(nil); -+ }]; -+ [alert addAction:cancelAction]; -+ alert.preferredAction = okAction; -+ [[self topViewController] presentViewController:alert animated:YES completion:NULL]; -+ #else -+ NSAlert *alert = [[NSAlert alloc] init]; -+ [alert setMessageText:prompt]; -+ -+ const NSRect RCTSingleTextFieldFrame = NSMakeRect(0.0, 0.0, 275.0, 22.0); -+ NSTextField *textField = [[NSTextField alloc] initWithFrame:RCTSingleTextFieldFrame]; -+ textField.cell.scrollable = YES; -+ if (@available(macOS 10.11, *)) { -+ textField.maximumNumberOfLines = 1; -+ } -+ textField.stringValue = defaultText; -+ [alert setAccessoryView:textField]; -+ -+ [alert addButtonWithTitle:NSLocalizedString(@"OK", @"OK button")]; -+ [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"Cancel button")]; -+ [alert beginSheetModalForWindow:[NSApp keyWindow] completionHandler:^(NSModalResponse response) { -+ if (response == NSAlertFirstButtonReturn) { -+ completionHandler([textField stringValue]); -+ } else { -+ completionHandler(nil); -+ } -+ }]; -+ #endif // !TARGET_OS_OSX - } else { -- completionHandler(nil); -+ completionHandler(nil); - } -- }]; --#endif // !TARGET_OS_OSX - } - - #if !TARGET_OS_OSX -@@ -1157,6 +1168,7 @@ static NSDictionary* customCertificatesForHost; - } - - if (_onLoadingFinish) { -+ _disablePromptDuringLoading = NO; - _onLoadingFinish([self baseEvent]); - } - } -@@ -1446,3 +1458,4 @@ static NSDictionary* customCertificatesForHost; - } - - @end -+ From a0d2bd5502e717eb1e40eb8d9fb2b09802bb3df4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Fri, 15 Dec 2023 17:20:36 +0000 Subject: [PATCH 04/41] update podfile lock file --- ios/Podfile.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 9274b9f9eb6..f6b5523b53b 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -367,7 +367,7 @@ PODS: - React-Core - react-native-view-shot (3.1.2): - React - - react-native-webview (11.13.0): + - react-native-webview (13.6.3): - React-Core - React-perflogger (0.71.14) - React-RCTActionSheet (0.71.14): @@ -909,7 +909,7 @@ SPEC CHECKSUMS: react-native-splash-screen: 200d11d188e2e78cea3ad319964f6142b6384865 react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253 react-native-view-shot: 4475fde003fe8a210053d1f98fb9e06c1d834e1c - react-native-webview: 133a6a5149f963259646e710b4545c67ef35d7c9 + react-native-webview: 88293a0f23eca8465c0433c023ec632930e644d0 React-perflogger: 4987ad83731c23d11813c84263963b0d3028c966 React-RCTActionSheet: 5ad952b2a9740d87a5bd77280c4bc23f6f89ea0c React-RCTAnimation: d2de22af3f536cc80bb5b3918e1a455114d1b985 From a5381caa3de95bab91e8052ab5f58d4659e0f4aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 1 Feb 2024 16:00:31 +0000 Subject: [PATCH 05/41] Improve web3 provider injection (#8130) --- .iyarc | 3 + app/__mocks__/react-native-webview.tsx | 8 + .../UI/Ramp/buy/Views/Quotes/Quotes.test.tsx | 11 + .../Quotes/__snapshots__/Quotes.test.tsx.snap | 1622 ++++++++++++++++- app/components/Views/BrowserTab/index.js | 2 +- .../Views/Settings/AppInformation/index.js | 17 +- .../__snapshots__/index.test.tsx.snap | 11 +- app/core/BackgroundBridge/Port.ts | 2 - app/lib/ppom/PPOMView.test.tsx | 11 + .../ppom/__snapshots__/PPOMView.test.tsx.snap | 58 +- bitrise.yml | 15 +- patches/react-native+0.71.14.patch | 54 +- scripts/build.sh | 23 +- yarn.lock | 7 - 14 files changed, 1706 insertions(+), 138 deletions(-) create mode 100644 app/__mocks__/react-native-webview.tsx diff --git a/.iyarc b/.iyarc index c96c8d176c8..a946943856f 100644 --- a/.iyarc +++ b/.iyarc @@ -3,3 +3,6 @@ GHSA-p8p7-x288-28g6 # ReDoS vulnerability, no impact to this application, and fix not backported yet to the versions we use GHSA-c2qf-rxjj-qqgw + +#exclude these for now. Revert & handle them before merge to main +GHSA-jchw-25xp-jwwc diff --git a/app/__mocks__/react-native-webview.tsx b/app/__mocks__/react-native-webview.tsx new file mode 100644 index 00000000000..59abe4a8d39 --- /dev/null +++ b/app/__mocks__/react-native-webview.tsx @@ -0,0 +1,8 @@ +import React from 'react'; +import { View, ViewProps } from 'react-native'; + +const WebView = (props: ViewProps) => ; + +export default { + WebView, +}; diff --git a/app/components/UI/Ramp/buy/Views/Quotes/Quotes.test.tsx b/app/components/UI/Ramp/buy/Views/Quotes/Quotes.test.tsx index 61f8b17b29f..6ed3548a512 100644 --- a/app/components/UI/Ramp/buy/Views/Quotes/Quotes.test.tsx +++ b/app/components/UI/Ramp/buy/Views/Quotes/Quotes.test.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { ViewProps } from 'react-native'; import { cloneDeep } from 'lodash'; import { ProviderBuyFeatureBrowserEnum, @@ -44,6 +45,16 @@ function render(Component: React.ComponentType) { jest.unmock('react-redux'); +jest.mock('react-native-webview', () => { + // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires + const { View } = require('react-native'); + const WebView = (props: ViewProps) => ; + + return { + WebView, + }; +}); + const mockSetOptions = jest.fn(); const mockNavigate = jest.fn(); const mockGoBack = jest.fn(); diff --git a/app/components/UI/Ramp/buy/Views/Quotes/__snapshots__/Quotes.test.tsx.snap b/app/components/UI/Ramp/buy/Views/Quotes/__snapshots__/Quotes.test.tsx.snap index 19b7f536e33..b837cf4583c 100644 --- a/app/components/UI/Ramp/buy/Views/Quotes/__snapshots__/Quotes.test.tsx.snap +++ b/app/components/UI/Ramp/buy/Views/Quotes/__snapshots__/Quotes.test.tsx.snap @@ -1181,59 +1181,1591 @@ exports[`Quotes renders animation on first fetching 1`] = ` } > + + + + --- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ", + } + } style={ Array [ Object { + "backgroundColor": "#FFFFFF", "flex": 1, - "overflow": "hidden", }, undefined, ] } - > - - + /> diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index a40a5eee363..716cb06aa4c 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -1485,7 +1485,7 @@ export const BrowserTab = (props) => { )} source={{ uri: initialUrl }} - injectedJavaScriptBeforeContentLoaded={entryScriptWeb3} + injectedJavaScriptBeforeContentLoaded={`window.self.document.addEventListener("DOMContentLoaded", function() {${entryScriptWeb3}});`} style={styles.webview} onLoadStart={onLoadStart} onLoad={onLoad} diff --git a/app/components/Views/Settings/AppInformation/index.js b/app/components/Views/Settings/AppInformation/index.js index a6b4e3f44ef..98a849a01b3 100644 --- a/app/components/Views/Settings/AppInformation/index.js +++ b/app/components/Views/Settings/AppInformation/index.js @@ -23,7 +23,7 @@ import AppConstants from '../../../../core/AppConstants'; import { ThemeContext, mockTheme } from '../../../../util/theme'; import { AboutMetaMaskSelectorsIDs } from '../../../../../e2e/selectors/Settings/AboutMetaMask.selectors'; -const IS_QA = process.env['METAMASK_ENVIRONMENT'] === 'qa'; +const IS_PROD_ENV = process.env['METAMASK_ENVIRONMENT'] === 'production'; const createStyles = (colors) => StyleSheet.create({ @@ -187,11 +187,16 @@ export default class AppInformation extends PureComponent { resizeMethod={'auto'} /> {this.state.appInfo} - {IS_QA ? ( - - {`Branch: ${process.env['GIT_BRANCH']}`} - - ) : null} + {IS_PROD_ENV ? null : ( + <> + + {`Branch: ${process.env['GIT_BRANCH']}`} + + + {`Commit Hash: ${process.env['GIT_COMMIT']}`} + + + )} {strings('app_information.links')} diff --git a/app/components/Views/SimpleWebview/__snapshots__/index.test.tsx.snap b/app/components/Views/SimpleWebview/__snapshots__/index.test.tsx.snap index 157a89b97fa..f704547b60b 100644 --- a/app/components/Views/SimpleWebview/__snapshots__/index.test.tsx.snap +++ b/app/components/Views/SimpleWebview/__snapshots__/index.test.tsx.snap @@ -8,21 +8,12 @@ exports[`SimpleWebview should render correctly 1`] = ` } } > - `; diff --git a/app/core/BackgroundBridge/Port.ts b/app/core/BackgroundBridge/Port.ts index 49c47f97079..19c84ece91e 100644 --- a/app/core/BackgroundBridge/Port.ts +++ b/app/core/BackgroundBridge/Port.ts @@ -19,8 +19,6 @@ class Port extends EventEmitter { const js = this._isMainFrame ? JS_POST_MESSAGE_TO_PROVIDER(msg, origin) : JS_IFRAME_POST_MESSAGE_TO_PROVIDER(msg, origin); - console.log('Post js', js); - console.log('this._window', this._window); this._window?.injectJavaScript(js); }; } diff --git a/app/lib/ppom/PPOMView.test.tsx b/app/lib/ppom/PPOMView.test.tsx index c9093579f93..e902a224875 100644 --- a/app/lib/ppom/PPOMView.test.tsx +++ b/app/lib/ppom/PPOMView.test.tsx @@ -1,8 +1,19 @@ import React from 'react'; +import { ViewProps } from 'react-native'; import { render } from '@testing-library/react-native'; import { PPOMView } from './PPOMView'; +jest.mock('react-native-webview', () => { + // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires + const { View } = require('react-native'); + const WebView = (props: ViewProps) => ; + + return { + WebView, + }; +}); + describe('PPOMView', () => { it('should render correctly deeply', () => { const wrapper = render(); diff --git a/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap b/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap index dbd5255649b..0997b7b04be 100644 --- a/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap +++ b/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap @@ -11,49 +11,21 @@ exports[`PPOMView should render correctly deeply 1`] = ` } > - Webpack App", } - useSharedProcessPool={true} - /> - + } + /> `; diff --git a/bitrise.yml b/bitrise.yml index fb5112677be..4b33b8ce097 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -46,7 +46,7 @@ pipelines: - build_e2e_ios_android_stage: {} - run_e2e_ios_android_stage: {} # - build_regression_e2e_ios_android_stage: {} Enable whenever regression tests are running successfully. - # - run_regression_e2e_ios_android_stage: {} Enable whenever regression tests are running successfully. + # - run_regression_e2e_ios_android_stage: {} Enable whenever regression tests are running successfully. - notify: {} #PR_e2e_verfication (build ios & android), run iOS (smoke), emulator Android pr_smoke_e2e_pipeline: @@ -189,7 +189,7 @@ workflows: - command: audit:ci title: Audit Dependencies - save-cache@1: - title: Save cache dependencies + title: Save cache dependencies inputs: - key: '{{ .OS }}-{{ .Arch }}-node-modules-{{ checksum "yarn.lock" }}' - paths: |- @@ -345,9 +345,9 @@ workflows: title: All Tests Passed is_always_run: false # E2E Steps - + ### This workflow uses a flag (TEST_SUITE) that defines the specific set of tests to be run. - ## in this instance Regression. In future iterations we can rename to ios_test_suite_selection & android_test_suite_selection + ## in this instance Regression. In future iterations we can rename to ios_test_suite_selection & android_test_suite_selection ios_build_regression_tests: envs: - TEST_SUITE: 'Regression' @@ -753,7 +753,12 @@ workflows: - content: |- #!/usr/bin/env bash node -v - GIT_BRANCH=$BITRISE_GIT_BRANCH METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='qa' yarn build:android:pre-release:bundle:qa + COMMIT_SHORT_HASH="${BITRISE_GIT_COMMIT:0:7}" + + if [[ -z "$BITRISE_GIT_COMMIT" ]]; then + COMMIT_SHORT_HASH="$(git rev-parse --short HEAD)" + fi + GIT_BRANCH=$BITRISE_GIT_BRANCH GIT_COMMIT=$COMMIT_SHORT_HASH METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='qa' yarn build:android:pre-release:bundle:qa title: Build Android Pre-Release Bundle is_always_run: false - save-gradle-cache@1: {} diff --git a/patches/react-native+0.71.14.patch b/patches/react-native+0.71.14.patch index 9b3ceaf29d8..12de85fdfaa 100644 --- a/patches/react-native+0.71.14.patch +++ b/patches/react-native+0.71.14.patch @@ -3,9 +3,9 @@ index 1379ffd..e59f511 100644 --- a/node_modules/react-native/Libraries/Core/InitializeCore.js +++ b/node_modules/react-native/Libraries/Core/InitializeCore.js @@ -24,26 +24,53 @@ - + 'use strict'; - + +const Platform = require('../Utilities/Platform'); + +const IS_LOCKDOWN_ENABLED = false; // Temporarily false until CI issues investigated and resolved @@ -29,7 +29,7 @@ index 1379ffd..e59f511 100644 +} + const start = Date.now(); - + require('./setUpGlobals'); +// require('./setUpDOM'); Introduced in RN v0.72, ensure included when upgrading patch require('./setUpPerformance'); @@ -52,18 +52,27 @@ index 1379ffd..e59f511 100644 + require('./setUpDeveloperTools'); // console.log calls visible in Metro from here require('../LogBox/LogBox').install(); } - + -require('../ReactNative/AppRegistry'); +require('../ReactNative/AppRegistry'); // reflect-metadata imported after here causes: https://github.com/LavaMoat/docs/issues/26 - + const GlobalPerformanceLogger = require('../Utilities/GlobalPerformanceLogger'); // We could just call GlobalPerformanceLogger.markPoint at the top of the file, diff --git a/node_modules/react-native/ReactAndroid/build.gradle b/node_modules/react-native/ReactAndroid/build.gradle -index 155cb59..053550c 100644 +index 155cb59..816f559 100644 --- a/node_modules/react-native/ReactAndroid/build.gradle +++ b/node_modules/react-native/ReactAndroid/build.gradle +@@ -241,7 +241,7 @@ task createNativeDepsDirectories { + } + + task downloadBoost(dependsOn: createNativeDepsDirectories, type: Download) { +- src("https://boostorg.jfrog.io/artifactory/main/release/${BOOST_VERSION.replace("_", ".")}/source/boost_${BOOST_VERSION}.tar.gz") ++ src("https://archives.boost.io/release/${BOOST_VERSION.replace("_", ".")}/source/boost_${BOOST_VERSION}.tar.gz") + onlyIfNewer(true) + overwrite(false) + dest(new File(downloadsDir, "boost_${BOOST_VERSION}.tar.gz")) @@ -420,12 +420,9 @@ android { - + // Used to override the NDK path/version on internal CI or by allowing // users to customize the NDK path/version from their root project (e.g. for M1 support) - if (rootProject.hasProperty("ndkPath")) { @@ -75,17 +84,17 @@ index 155cb59..053550c 100644 + + // Added patch to apply ndk Path from MetaMask app gradle.build this is required for M1 Bitrise builds to work + ndkPath = project.getProperties().get("ndkPath") - + defaultConfig { minSdkVersion(21) diff --git a/node_modules/react-native/ReactAndroid/hermes-engine/build.gradle b/node_modules/react-native/ReactAndroid/hermes-engine/build.gradle -index c714f87..dca2750 100644 +index c714f87..65f9ba3 100644 --- a/node_modules/react-native/ReactAndroid/hermes-engine/build.gradle +++ b/node_modules/react-native/ReactAndroid/hermes-engine/build.gradle @@ -43,11 +43,11 @@ def overrideHermesDir = System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR") != nul def hermesDir = System.getenv("REACT_NATIVE_OVERRIDE_HERMES_DIR") ?: new File(reactNativeRootDir, "sdks/hermes") def hermesBuildDir = new File("$buildDir/hermes") - + -def hermesVersion = "main" -def hermesVersionFile = new File(reactNativeRootDir, "sdks/.hermesversion") -if (hermesVersionFile.exists()) { @@ -98,10 +107,10 @@ index c714f87..dca2750 100644 +// } def ndkBuildJobs = Runtime.runtime.availableProcessors().toString() def prefabHeadersDir = new File("$buildDir/prefab-headers") - + @@ -59,7 +59,7 @@ def skipPrefabPublishing = System.getenv("REACT_NATIVE_HERMES_SKIP_PREFAB") != n def jsiDir = new File(reactNativeRootDir, "ReactCommon/jsi") - + task downloadHermes(type: Download) { - src("https://github.com/facebook/hermes/tarball/${hermesVersion}") + src("https://github.com/MetaMask/hermes/tarball/${hermesVersion}") @@ -109,7 +118,7 @@ index c714f87..dca2750 100644 overwrite(false) dest(new File(downloadsDir, "hermes.tar.gz")) @@ -120,12 +120,9 @@ android { - + // Used to override the NDK path/version on internal CI or by allowing // users to customize the NDK path/version from their root project (e.g. for M1 support) - if (rootProject.hasProperty("ndkPath")) { @@ -121,7 +130,7 @@ index c714f87..dca2750 100644 + + // Added patch to apply ndk Path from MetaMask app gradle.build this is required for M1 Bitrise builds to work + ndkPath = project.getProperties().get("ndkPath") - + defaultConfig { minSdkVersion 21 diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/views/textinput/ReactEditText.java @@ -139,7 +148,7 @@ index 290bd23..20d85e0 100644 @@ -94,6 +95,16 @@ public class ReactEditText extends AppCompatEditText /** A count of events sent to JS or C++. */ protected int mNativeEventCount; - + + /** + * Taken from EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING We can't use that + * value directly as it was only added on Oreo, but we can apply the value @@ -151,7 +160,7 @@ index 290bd23..20d85e0 100644 + /** Samsung Device Check */ + private static final Boolean IS_SAMSUNG_DEVICE = Build.MANUFACTURER.equals(SAMSUNG_MANUFACTURER_NAME); private static final int UNSET = -1; - + private @Nullable ArrayList mListeners; @@ -253,16 +264,24 @@ public class ReactEditText extends AppCompatEditText @Override @@ -188,3 +197,16 @@ index 290bd23..20d85e0 100644 } return inputConnection; } +diff --git a/node_modules/react-native/third-party-podspecs/boost.podspec b/node_modules/react-native/third-party-podspecs/boost.podspec +index 3d9331c..bbbb738 100644 +--- a/node_modules/react-native/third-party-podspecs/boost.podspec ++++ b/node_modules/react-native/third-party-podspecs/boost.podspec +@@ -10,7 +10,7 @@ Pod::Spec.new do |spec| + spec.homepage = 'http://www.boost.org' + spec.summary = 'Boost provides free peer-reviewed portable C++ source libraries.' + spec.authors = 'Rene Rivera' +- spec.source = { :http => 'https://boostorg.jfrog.io/artifactory/main/release/1.76.0/source/boost_1_76_0.tar.bz2', ++ spec.source = { :http => 'https://archives.boost.io/release/1.76.0/source/boost_1_76_0.tar.bz2', + :sha256 => 'f0397ba6e982c4450f27bf32a2a83292aba035b827a5623a14636ea583318c41' } + + # Pinning to the same version as React.podspec. diff --git a/scripts/build.sh b/scripts/build.sh index b8a2c094cbd..ba410921b25 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -161,8 +161,6 @@ prebuild_ios(){ } prebuild_android(){ - adb kill-server - adb start-server prebuild # Copy JS files for injection yes | cp -rf app/core/InpageBridgeWeb3.js android/app/src/main/assets/. @@ -403,7 +401,7 @@ buildAndroidRelease(){ buildAndroidFlaskRelease(){ # remap flask env variables to match what the app expects remapFlaskEnvVariables - + if [ "$PRE_RELEASE" = false ] ; then adb uninstall io.metamask.flask || true fi @@ -552,6 +550,25 @@ elif [ "$MODE" == "release" ] || [ "$MODE" == "flask" ]; then export SENTRY_PROPERTIES="${REPO_ROOT_DIR}/sentry.release.properties" fi +# set some defaults +if [ -z "$METAMASK_BUILD_TYPE" ]; then + METAMASK_BUILD_TYPE='main' +fi + +if [ -z "$METAMASK_ENVIRONMENT" ]; then + METAMASK_ENVIRONMENT='local' +fi + +if [ -z "$GIT_COMMIT" ]; then + GIT_COMMIT="$(git rev-parse --short HEAD)" + export GIT_COMMIT +fi + +if [ -z "$GIT_BRANCH" ]; then + GIT_BRANCH="$(git branch --show-current)" + export GIT_BRANCH +fi + if [ -z "$METAMASK_BUILD_TYPE" ]; then printError "Missing METAMASK_BUILD_TYPE; set to 'main' for a standard release, or 'flask' for a canary flask release. The default value is 'main'." exit 1 diff --git a/yarn.lock b/yarn.lock index 9c3dfa9a7d3..5ebaf5a7efa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22637,13 +22637,6 @@ react-native-webview-invoke@^0.6.2: escape-string-regexp "2.0.0" invariant "2.2.4" -"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#f4cafd9fbd7659ca44b6af2a09034ad2f5565aa7": - version "13.6.3" - resolved "https://github.com/MetaMask/react-native-webview-mm#f4cafd9fbd7659ca44b6af2a09034ad2f5565aa7" - dependencies: - escape-string-regexp "2.0.0" - invariant "2.2.4" - react-native@0.71.14: version "0.71.14" resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.14.tgz#df12b405a7913b736de01b0347af14e4be7bf324" From 8594fd7b5192097eaf00fdf089f1b12ad478b2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 1 Feb 2024 16:02:06 +0000 Subject: [PATCH 06/41] remove temporary ignored vuln --- .iyarc | 3 --- 1 file changed, 3 deletions(-) diff --git a/.iyarc b/.iyarc index a946943856f..c96c8d176c8 100644 --- a/.iyarc +++ b/.iyarc @@ -3,6 +3,3 @@ GHSA-p8p7-x288-28g6 # ReDoS vulnerability, no impact to this application, and fix not backported yet to the versions we use GHSA-c2qf-rxjj-qqgw - -#exclude these for now. Revert & handle them before merge to main -GHSA-jchw-25xp-jwwc From 4b60d012eb28a263f309f651575c08d5538365eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Fri, 2 Feb 2024 11:42:09 +0000 Subject: [PATCH 07/41] update PPOMView jest snapshot --- app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap b/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap index 0997b7b04be..dee47e8937a 100644 --- a/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap +++ b/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap @@ -14,16 +14,16 @@ exports[`PPOMView should render correctly deeply 1`] = ` onMessage={[Function]} source={ Object { - "html": "Webpack App", +g.read=function(A,g,Q,I,B){var C,E,D=8*B-I-1,w=(1<>1,o=-7,G=Q?B-1:0,M=Q?-1:1,N=A[g+G];for(G+=M,C=N&(1<<-o)-1,N>>=-o,o+=D;o>0;C=256*C+A[g+G],G+=M,o-=8);for(E=C&(1<<-o)-1,C>>=-o,o+=I;o>0;E=256*E+A[g+G],G+=M,o-=8);if(0===C)C=1-i;else{if(C===w)return E?NaN:1/0*(N?-1:1);E+=Math.pow(2,I),C-=i}return(N?-1:1)*E*Math.pow(2,C-I)},g.write=function(A,g,Q,I,B,C){var E,D,w,i=8*C-B-1,o=(1<>1,M=23===B?Math.pow(2,-24)-Math.pow(2,-77):0,N=I?0:C-1,k=I?1:-1,a=g<0||0===g&&1/g<0?1:0;for(g=Math.abs(g),isNaN(g)||g===1/0?(D=isNaN(g)?1:0,E=o):(E=Math.floor(Math.log(g)/Math.LN2),g*(w=Math.pow(2,-E))<1&&(E--,w*=2),(g+=E+G>=1?M/w:M*Math.pow(2,1-G))*w>=2&&(E++,w/=2),E+G>=o?(D=0,E=o):E+G>=1?(D=(g*w-1)*Math.pow(2,B),E+=G):(D=g*Math.pow(2,G-1)*Math.pow(2,B),E=0));B>=8;A[Q+N]=255&D,N+=k,D/=256,B-=8);for(E=E<0;A[Q+N]=255&E,N+=k,E/=256,i-=8);A[Q+N-k]|=128*a}},204:(A,g,Q)=>{var I=Q(150);A.exports=I,A.exports.default=I},150:A=>{\\"use strict\\";function g(A){return g=\\"function\\"==typeof Symbol&&\\"symbol\\"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&\\"function\\"==typeof Symbol&&A.constructor===Symbol&&A!==Symbol.prototype?\\"symbol\\":typeof A},g(A)}function Q(A){return function(A){if(Array.isArray(A))return I(A)}(A)||function(A){if(\\"undefined\\"!=typeof Symbol&&Symbol.iterator in Object(A))return Array.from(A)}(A)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return I(A,g);var Q=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===Q&&A.constructor&&(Q=A.constructor.name);if(\\"Map\\"===Q||\\"Set\\"===Q)return Array.from(A);if(\\"Arguments\\"===Q||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(Q))return I(A,g)}(A)||function(){throw new TypeError(\\"Invalid attempt to spread non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function I(A,g){(null==g||g>A.length)&&(g=A.length);for(var Q=0,I=new Array(g);Q=0&&I.splice(B,1)}},emitEvent:function(A,Q){A in g&&g[A].forEach((function(A){return A(Q)}))}}),G={},M={},N={};function k(A){return function(){for(var g=arguments.length,Q=new Array(g),I=0;I0&&void 0!==arguments[0]?arguments[0]:[]).filter((function(A){return!N[A]})).map((function(A){N[A]=k(A)})),function(){if(I){var A=I;I=null,A.forEach((function(A){F(A)})),o.emitEvent(\\"ready\\")}}(),Object.keys(M)}function y(){R(Object.keys(M)).then(J)}return a(B,J),{bind:k,define:a,listener:function(A){if(A.reply){var g=i(A);G[g]&&(A.status===E?G[g].reject(A.data):G[g].resolve(A.data))}else if(M[A.command]){var Q=M[A.command](A.data);Q&&Q.then?Q.then((function(g){K(A,g,C)})).catch((function(g){K(A,g,E)})):K(A,Q,C)}else K(A,\\"function \\".concat(A.command,\\" is not defined\\"),E);o.emitEvent(\\"receive\\",A)},ready:y,fn:N,addEventListener:o.addEventListener,removeEventListener:o.removeEventListener,isConnect:function(){return!I}}}((function(A){return G&&o&&o(JSON.stringify(A))})),N=M.bind,k=M.define,a=M.listener,F=M.ready,K=M.fn,R=M.addEventListener,J=M.removeEventListener,y=M.isConnect,h=function(A){var Q=void 0;if(\\"object\\"===g(A))Q=A;else if(\\"string\\"==typeof A)try{Q=JSON.parse(A)}catch(A){}Q&&(Q.command||Q.reply)&&a(Q)};if(G){var U=window.originalPostMessage;if(U)o=function(){var A;return(A=window).postMessage.apply(A,arguments)},F();else{var Y={get:function(){return U},set:function(A){(U=A)&&(o=function(){var A;return(A=window).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,\\"originalPostMessage\\",Y)}var q=window.ReactNativeWebView;if(q)o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},F();else{var c={get:function(){return q},set:function(A){(q=A)&&(o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,\\"ReactNativeWebView\\",c)}window.document.addEventListener(\\"message\\",(function(A){return U&&h(A.data)})),window.addEventListener(\\"message\\",(function(A){return q&&h(A.data)})),window.document.addEventListener(\\"message\\",(function(A){return q&&h(A.data)}))}var L={bind:N,define:k,fn:K,addEventListener:R,removeEventListener:J,isConnect:y};A.exports=L}},g={};function Q(I){var B=g[I];if(void 0!==B)return B.exports;var C=g[I]={exports:{}};return A[I](C,C.exports,Q),C.exports}Q.n=A=>{var g=A&&A.__esModule?()=>A.default:()=>A;return Q.d(g,{a:g}),g},Q.d=(A,g)=>{for(var I in g)Q.o(g,I)&&!Q.o(A,I)&&Object.defineProperty(A,I,{enumerable:!0,get:g[I]})},Q.o=(A,g)=>Object.prototype.hasOwnProperty.call(A,g),(()=>{\\"use strict\\";var A=Q(204),g=Q.n(A);function I(A){return function(A){if(Array.isArray(A))return B(A)}(A)||function(A){if(\\"undefined\\"!=typeof Symbol&&null!=A[Symbol.iterator]||null!=A[\\"@@iterator\\"])return Array.from(A)}(A)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return B(A,g);var Q=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===Q&&A.constructor&&(Q=A.constructor.name);if(\\"Map\\"===Q||\\"Set\\"===Q)return Array.from(A);if(\\"Arguments\\"===Q||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(Q))return B(A,g)}(A)||function(){throw new TypeError(\\"Invalid attempt to spread non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function B(A,g){(null==g||g>A.length)&&(g=A.length);for(var Q=0,I=new Array(g);Q=0;--C){var E=this.tryEntries[C],D=E.completion;if(\\"root\\"===E.tryLoc)return B(\\"end\\");if(E.tryLoc<=this.prev){var w=I.call(E,\\"catchLoc\\"),i=I.call(E,\\"finallyLoc\\");if(w&&i){if(this.prev=0;--Q){var B=this.tryEntries[Q];if(B.tryLoc<=this.prev&&I.call(B,\\"finallyLoc\\")&&this.prev=0;--g){var Q=this.tryEntries[g];if(Q.finallyLoc===A)return this.complete(Q.completion,Q.afterLoc),O(Q),R}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var Q=this.tryEntries[g];if(Q.tryLoc===A){var I=Q.completion;if(\\"throw\\"===I.type){var B=I.arg;O(Q)}return B}}throw new Error(\\"illegal catch attempt\\")},delegateYield:function(g,Q,I){return this.delegate={iterator:t(g),resultName:Q,nextLoc:I},\\"next\\"===this.method&&(this.arg=A),R}},g}function D(A,g,Q,I,B,C,E){try{var D=A[C](E),w=D.value}catch(A){return void Q(A)}D.done?g(w):Promise.resolve(w).then(I,B)}function w(A){return function(){var g=this,Q=arguments;return new Promise((function(I,B){var C=A.apply(g,Q);function E(A){D(C,I,B,E,w,\\"next\\",A)}function w(A){D(C,I,B,E,w,\\"throw\\",A)}E(void 0)}))}}function i(A,g){for(var Q=0;Q>>=0,M.decode(k().subarray(A,A+g))}var F=new Array(128).fill(void 0);F.push(void 0,null,!0,!1);var K=F.length;function R(A){K===F.length&&F.push(F.length+1);var g=K;return K=F[g],F[g]=A,g}function J(A){return F[A]}function y(A){var g=J(A);return function(A){A<132||(F[A]=K,K=A)}(A),g}var h=0,U=\\"undefined\\"!=typeof TextEncoder?new TextEncoder(\\"utf-8\\"):{encode:function(){throw Error(\\"TextEncoder not available\\")}},Y=\\"function\\"==typeof U.encodeInto?function(A,g){return U.encodeInto(A,g)}:function(A,g){var Q=U.encode(A);return g.set(Q),{read:A.length,written:Q.length}};function q(A,g,Q){if(void 0===Q){var I=U.encode(A),B=g(I.length,1)>>>0;return k().subarray(B,B+I.length).set(I),h=I.length,B}for(var C=A.length,E=g(C,1)>>>0,D=k(),w=0;w127)break;D[E+w]=i}if(w!==C){0!==w&&(A=A.slice(w)),E=Q(E,C,C=w+3*A.length,1)>>>0;var o=k().subarray(E+w,E+C);w+=Y(A,o).written}return h=w,E}var c=null;function L(){return null!==c&&0!==c.byteLength||(c=new Int32Array(G.memory.buffer)),c}function S(A){var g=o(A);if(\\"number\\"==g||\\"boolean\\"==g||null==A)return\\"\\".concat(A);if(\\"string\\"==g)return'\\"'.concat(A,'\\"');if(\\"symbol\\"==g){var Q=A.description;return null==Q?\\"Symbol\\":\\"Symbol(\\".concat(Q,\\")\\")}if(\\"function\\"==g){var I=A.name;return\\"string\\"==typeof I&&I.length>0?\\"Function(\\".concat(I,\\")\\"):\\"Function\\"}if(Array.isArray(A)){var B=A.length,C=\\"[\\";B>0&&(C+=S(A[0]));for(var E=1;E1))return toString.call(A);if(\\"Object\\"==(D=w[1]))try{return\\"Object(\\"+JSON.stringify(A)+\\")\\"}catch(A){return\\"Object\\"}return A instanceof Error?\\"\\".concat(A.name,\\": \\").concat(A.message,\\"\\\\n\\").concat(A.stack):D}function H(A,g,Q){G.wasm_bindgen__convert__closures__invoke1_mut(A,g,R(Q))}function s(A,g){G._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy(A,g)}var p=null;function O(A,g){for(var Q=g(4*A.length,4)>>>0,I=(null!==p&&0!==p.byteLength||(p=new Uint32Array(G.memory.buffer)),p),B=0;B>>=0;var Q=Object.create(A.prototype);return Q.__wbg_ptr=g,Q}},{key:\\"new\\",value:function(A,g){var Q=O(g,G.__wbindgen_malloc),I=h;return y(G.ppom_new(R(A),Q,I))}},{key:\\"version\\",value:function(){return y(G.ppom_version())}}],(Q=[{key:\\"__destroy_into_raw\\",value:function(){var A=this.__wbg_ptr;return this.__wbg_ptr=0,A}},{key:\\"free\\",value:function(){var A=this.__destroy_into_raw();G.__wbg_ppom_free(A)}},{key:\\"validateJsonRpc\\",value:function(A){return y(G.ppom_validateJsonRpc(this.__wbg_ptr,R(A)))}}])&&i(g.prototype,Q),I&&i(g,I),Object.defineProperty(g,\\"prototype\\",{writable:!1}),A}();function j(A,g){return T.apply(this,arguments)}function T(){return(T=w(E().mark((function A(g,Q){var I,B;return E().wrap((function(A){for(;;)switch(A.prev=A.next){case 0:if(!(\\"function\\"==typeof Response&&g instanceof Response)){A.next=23;break}if(\\"function\\"!=typeof WebAssembly.instantiateStreaming){A.next=15;break}return A.prev=2,A.next=5,WebAssembly.instantiateStreaming(g,Q);case 5:case 20:return A.abrupt(\\"return\\",A.sent);case 8:if(A.prev=8,A.t0=A.catch(2),\\"application/wasm\\"==g.headers.get(\\"Content-Type\\")){A.next=14;break}console.warn(\\"\`WebAssembly.instantiateStreaming\` failed because your server does not serve wasm with \`application/wasm\` MIME type. Falling back to \`WebAssembly.instantiate\` which is slower. Original error:\\\\n\\",A.t0),A.next=15;break;case 14:throw A.t0;case 15:return A.next=17,g.arrayBuffer();case 17:return I=A.sent,A.next=20,WebAssembly.instantiate(I,Q);case 23:return A.next=25,WebAssembly.instantiate(g,Q);case 25:if(!((B=A.sent)instanceof WebAssembly.Instance)){A.next=30;break}return A.abrupt(\\"return\\",{instance:B,module:g});case 30:return A.abrupt(\\"return\\",B);case 31:case\\"end\\":return A.stop()}}),A,null,[[2,8]])})))).apply(this,arguments)}function d(){var A={wbg:{}};return A.wbg.__wbg_buffer_085ec1f694018c4f=function(A){return R(J(A).buffer)},A.wbg.__wbg_call_01734de55d61e11d=function(){return x((function(A,g,Q){return R(J(A).call(J(g),J(Q)))}),arguments)},A.wbg.__wbg_call_4c92f6aec1e1d6e6=function(){return x((function(A,g,Q,I){return R(J(A).call(J(g),J(Q),J(I)))}),arguments)},A.wbg.__wbg_from_d7c216d4616bb368=function(A){return R(Array.from(J(A)))},A.wbg.__wbg_get_44be0491f933a435=function(A,g){return R(J(A)[g>>>0])},A.wbg.__wbg_length_72e2208bbc0efc61=function(A){return J(A).length},A.wbg.__wbg_length_d813e535247d427e=function(A){return J(A).length},A.wbg.__wbg_length_fff51ee6522a1a18=function(A){return J(A).length},A.wbg.__wbg_new_43f1b47c28813cbd=function(A,g){try{var Q={a:A,b:g},I=new Promise((function(A,g){var I=Q.a;Q.a=0;try{return function(A,g,Q,I){G.wasm_bindgen__convert__closures__invoke2_mut(A,g,R(Q),R(I))}(I,Q.b,A,g)}finally{Q.a=I}}));return R(I)}finally{Q.a=Q.b=0}},A.wbg.__wbg_new_8125e318e6245eed=function(A){return R(new Uint8Array(J(A)))},A.wbg.__wbg_parse_670c19d4e984792e=function(){return x((function(A,g){return R(JSON.parse(a(A,g)))}),arguments)},A.wbg.__wbg_ppom_new=function(A){return R(t.__wrap(A))},A.wbg.__wbg_resolve_53698b95aaf7fcf8=function(A){return R(Promise.resolve(J(A)))},A.wbg.__wbg_set_5cf90238115182c3=function(A,g,Q){J(A).set(J(g),Q>>>0)},A.wbg.__wbg_stringify_e25465938f3f611f=function(){return x((function(A){return R(JSON.stringify(J(A)))}),arguments)},A.wbg.__wbg_then_b2267541e2a73865=function(A,g,Q){return R(J(A).then(J(g),J(Q)))},A.wbg.__wbg_then_f7e06ee3c11698eb=function(A,g){return R(J(A).then(J(g)))},A.wbg.__wbindgen_cb_drop=function(A){var g=y(A).original;if(1==g.cnt--)return g.a=0,!0;return!1},A.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined=function(A,g,Q){var I=function(A,g,Q,I){var B={a:A,b:g,cnt:1},C=function(){B.cnt++;var A=B.a;B.a=0;try{for(var g=arguments.length,C=new Array(g),E=0;E=0;--C){var E=this.tryEntries[C],D=E.completion;if(\\"root\\"===E.tryLoc)return B(\\"end\\");if(E.tryLoc<=this.prev){var w=I.call(E,\\"catchLoc\\"),i=I.call(E,\\"finallyLoc\\");if(w&&i){if(this.prev=0;--Q){var B=this.tryEntries[Q];if(B.tryLoc<=this.prev&&I.call(B,\\"finallyLoc\\")&&this.prev=0;--g){var Q=this.tryEntries[g];if(Q.finallyLoc===A)return this.complete(Q.completion,Q.afterLoc),s(Q),F}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var Q=this.tryEntries[g];if(Q.tryLoc===A){var I=Q.completion;if(\\"throw\\"===I.type){var B=I.arg;s(Q)}return B}}throw new Error(\\"illegal catch attempt\\")},delegateYield:function(g,Q,I){return this.delegate={iterator:O(g),resultName:Q,nextLoc:I},\\"next\\"===this.method&&(this.arg=A),F}},g}function m(A,g){return function(A){if(Array.isArray(A))return A}(A)||function(A,g){var Q=null==A?null:\\"undefined\\"!=typeof Symbol&&A[Symbol.iterator]||A[\\"@@iterator\\"];if(null!=Q){var I,B,C,E,D=[],w=!0,i=!1;try{if(C=(Q=Q.call(A)).next,0===g){if(Object(Q)!==Q)return;w=!1}else for(;!(w=(I=C.call(Q)).done)&&(D.push(I.value),D.length!==g);w=!0);}catch(A){i=!0,B=A}finally{try{if(!w&&null!=Q.return&&(E=Q.return(),Object(E)!==E))return}finally{if(i)throw B}}return D}}(A,g)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return V(A,g);var Q=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===Q&&A.constructor&&(Q=A.constructor.name);if(\\"Map\\"===Q||\\"Set\\"===Q)return Array.from(A);if(\\"Arguments\\"===Q||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(Q))return V(A,g)}(A,g)||function(){throw new TypeError(\\"Invalid attempt to destructure non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function V(A,g){(null==g||g>A.length)&&(g=A.length);for(var Q=0,I=new Array(g);Q", } } /> From 792fec9c3df6ebcc6f8a5834edef56e76c83202e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 15 Feb 2024 15:07:41 +0000 Subject: [PATCH 08/41] REVERTME: show git info on prod builds --- .../Views/Settings/AppInformation/index.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/app/components/Views/Settings/AppInformation/index.js b/app/components/Views/Settings/AppInformation/index.js index 98a849a01b3..48f788d40f6 100644 --- a/app/components/Views/Settings/AppInformation/index.js +++ b/app/components/Views/Settings/AppInformation/index.js @@ -23,8 +23,6 @@ import AppConstants from '../../../../core/AppConstants'; import { ThemeContext, mockTheme } from '../../../../util/theme'; import { AboutMetaMaskSelectorsIDs } from '../../../../../e2e/selectors/Settings/AboutMetaMask.selectors'; -const IS_PROD_ENV = process.env['METAMASK_ENVIRONMENT'] === 'production'; - const createStyles = (colors) => StyleSheet.create({ wrapper: { @@ -187,16 +185,12 @@ export default class AppInformation extends PureComponent { resizeMethod={'auto'} /> {this.state.appInfo} - {IS_PROD_ENV ? null : ( - <> - - {`Branch: ${process.env['GIT_BRANCH']}`} - - - {`Commit Hash: ${process.env['GIT_COMMIT']}`} - - - )} + + {`Branch: ${process.env['GIT_BRANCH']}`} + + + {`Commit Hash: ${process.env['GIT_COMMIT']}`} + {strings('app_information.links')} From 59da6cb53030a8c7da8809f8e2e9285a861e0f9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 6 Mar 2024 16:39:53 +0000 Subject: [PATCH 09/41] update Quotes component jest snapshot --- .../Quotes/__snapshots__/Quotes.test.tsx.snap | 89 +++++-------------- 1 file changed, 23 insertions(+), 66 deletions(-) diff --git a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap index 2fea89ab95d..3f6f729a168 100644 --- a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap +++ b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap @@ -1253,13 +1253,26 @@ exports[`Quotes renders animation on first fetching 1`] = ` } > + @@ -2826,74 +2839,18 @@ exports[`Quotes renders animation on first fetching 1`] = ` ", + } } - } - style={ - Array [ - Object { - "backgroundColor": "#FFFFFF", - "flex": 1, - }, - Object { - "opacity": 0, - }, - ] - } - > - - - + /> From f2bcf802fb01c345c74d10e406f2be34fba26b42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:33:11 +0000 Subject: [PATCH 10/41] update jest snapshots --- .../__snapshots__/index.test.tsx.snap | 28 +++++++++++++++++++ .../ppom/__snapshots__/PPOMView.test.tsx.snap | 6 ++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/app/components/Views/Settings/AppInformation/__snapshots__/index.test.tsx.snap b/app/components/Views/Settings/AppInformation/__snapshots__/index.test.tsx.snap index 2cd2d4c4ae2..3e6ed7a7b88 100644 --- a/app/components/Views/Settings/AppInformation/__snapshots__/index.test.tsx.snap +++ b/app/components/Views/Settings/AppInformation/__snapshots__/index.test.tsx.snap @@ -428,6 +428,34 @@ exports[`AppInformation should render correctly 1`] = ` } } /> + + Branch: undefined + + + Commit Hash: undefined + Webpack App", +g.read=function(A,g,I,B,Q){var C,E,D=8*Q-B-1,w=(1<>1,o=-7,G=I?Q-1:0,M=I?-1:1,N=A[g+G];for(G+=M,C=N&(1<<-o)-1,N>>=-o,o+=D;o>0;C=256*C+A[g+G],G+=M,o-=8);for(E=C&(1<<-o)-1,C>>=-o,o+=B;o>0;E=256*E+A[g+G],G+=M,o-=8);if(0===C)C=1-i;else{if(C===w)return E?NaN:1/0*(N?-1:1);E+=Math.pow(2,B),C-=i}return(N?-1:1)*E*Math.pow(2,C-B)},g.write=function(A,g,I,B,Q,C){var E,D,w,i=8*C-Q-1,o=(1<>1,M=23===Q?Math.pow(2,-24)-Math.pow(2,-77):0,N=B?0:C-1,k=B?1:-1,a=g<0||0===g&&1/g<0?1:0;for(g=Math.abs(g),isNaN(g)||g===1/0?(D=isNaN(g)?1:0,E=o):(E=Math.floor(Math.log(g)/Math.LN2),g*(w=Math.pow(2,-E))<1&&(E--,w*=2),(g+=E+G>=1?M/w:M*Math.pow(2,1-G))*w>=2&&(E++,w/=2),E+G>=o?(D=0,E=o):E+G>=1?(D=(g*w-1)*Math.pow(2,Q),E+=G):(D=g*Math.pow(2,G-1)*Math.pow(2,Q),E=0));Q>=8;A[I+N]=255&D,N+=k,D/=256,Q-=8);for(E=E<0;A[I+N]=255&E,N+=k,E/=256,i-=8);A[I+N-k]|=128*a}},204:(A,g,I)=>{var B=I(150);A.exports=B,A.exports.default=B},150:A=>{\\"use strict\\";function g(A){return g=\\"function\\"==typeof Symbol&&\\"symbol\\"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&\\"function\\"==typeof Symbol&&A.constructor===Symbol&&A!==Symbol.prototype?\\"symbol\\":typeof A},g(A)}function I(A){return function(A){if(Array.isArray(A))return B(A)}(A)||function(A){if(\\"undefined\\"!=typeof Symbol&&Symbol.iterator in Object(A))return Array.from(A)}(A)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return B(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===I&&A.constructor&&(I=A.constructor.name);if(\\"Map\\"===I||\\"Set\\"===I)return Array.from(A);if(\\"Arguments\\"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return B(A,g)}(A)||function(){throw new TypeError(\\"Invalid attempt to spread non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function B(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0&&B.splice(Q,1)}},emitEvent:function(A,I){A in g&&g[A].forEach((function(A){return A(I)}))}}),G={},M={},N={};function k(A){return function(){for(var g=arguments.length,I=new Array(g),B=0;B0&&void 0!==arguments[0]?arguments[0]:[]).filter((function(A){return!N[A]})).map((function(A){N[A]=k(A)})),function(){if(B){var A=B;B=null,A.forEach((function(A){F(A)})),o.emitEvent(\\"ready\\")}}(),Object.keys(M)}function y(){R(Object.keys(M)).then(K)}return a(Q,K),{bind:k,define:a,listener:function(A){if(A.reply){var g=i(A);G[g]&&(A.status===E?G[g].reject(A.data):G[g].resolve(A.data))}else if(M[A.command]){var I=M[A.command](A.data);I&&I.then?I.then((function(g){J(A,g,C)})).catch((function(g){J(A,g,E)})):J(A,I,C)}else J(A,\\"function \\".concat(A.command,\\" is not defined\\"),E);o.emitEvent(\\"receive\\",A)},ready:y,fn:N,addEventListener:o.addEventListener,removeEventListener:o.removeEventListener,isConnect:function(){return!B}}}((function(A){return G&&o&&o(JSON.stringify(A))})),N=M.bind,k=M.define,a=M.listener,F=M.ready,J=M.fn,R=M.addEventListener,K=M.removeEventListener,y=M.isConnect,h=function(A){var I=void 0;if(\\"object\\"===g(A))I=A;else if(\\"string\\"==typeof A)try{I=JSON.parse(A)}catch(A){}I&&(I.command||I.reply)&&a(I)};if(G){var U=window.originalPostMessage;if(U)o=function(){var A;return(A=window).postMessage.apply(A,arguments)},F();else{var q={get:function(){return U},set:function(A){(U=A)&&(o=function(){var A;return(A=window).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,\\"originalPostMessage\\",q)}var Y=window.ReactNativeWebView;if(Y)o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},F();else{var L={get:function(){return Y},set:function(A){(Y=A)&&(o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,\\"ReactNativeWebView\\",L)}window.document.addEventListener(\\"message\\",(function(A){return U&&h(A.data)})),window.addEventListener(\\"message\\",(function(A){return Y&&h(A.data)})),window.document.addEventListener(\\"message\\",(function(A){return Y&&h(A.data)}))}var c={bind:N,define:k,fn:J,addEventListener:R,removeEventListener:K,isConnect:y};A.exports=c}},g={};function I(B){var Q=g[B];if(void 0!==Q)return Q.exports;var C=g[B]={exports:{}};return A[B](C,C.exports,I),C.exports}I.n=A=>{var g=A&&A.__esModule?()=>A.default:()=>A;return I.d(g,{a:g}),g},I.d=(A,g)=>{for(var B in g)I.o(g,B)&&!I.o(A,B)&&Object.defineProperty(A,B,{enumerable:!0,get:g[B]})},I.o=(A,g)=>Object.prototype.hasOwnProperty.call(A,g),(()=>{\\"use strict\\";var A=I(204),g=I.n(A);function B(A){return function(A){if(Array.isArray(A))return Q(A)}(A)||function(A){if(\\"undefined\\"!=typeof Symbol&&null!=A[Symbol.iterator]||null!=A[\\"@@iterator\\"])return Array.from(A)}(A)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return Q(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===I&&A.constructor&&(I=A.constructor.name);if(\\"Map\\"===I||\\"Set\\"===I)return Array.from(A);if(\\"Arguments\\"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return Q(A,g)}(A)||function(){throw new TypeError(\\"Invalid attempt to spread non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function Q(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0;--C){var E=this.tryEntries[C],D=E.completion;if(\\"root\\"===E.tryLoc)return Q(\\"end\\");if(E.tryLoc<=this.prev){var w=B.call(E,\\"catchLoc\\"),i=B.call(E,\\"finallyLoc\\");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,\\"finallyLoc\\")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),O(I),R}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if(\\"throw\\"===B.type){var Q=B.arg;O(I)}return Q}}throw new Error(\\"illegal catch attempt\\")},delegateYield:function(g,I,B){return this.delegate={iterator:T(g),resultName:I,nextLoc:B},\\"next\\"===this.method&&(this.arg=A),R}},g}function D(A,g,I,B,Q,C,E){try{var D=A[C](E),w=D.value}catch(A){return void I(A)}D.done?g(w):Promise.resolve(w).then(B,Q)}function w(A){return function(){var g=this,I=arguments;return new Promise((function(B,Q){var C=A.apply(g,I);function E(A){D(C,B,Q,E,w,\\"next\\",A)}function w(A){D(C,B,Q,E,w,\\"throw\\",A)}E(void 0)}))}}function i(A,g){for(var I=0;I>>=0,M.decode(k().subarray(A,A+g))}var F=new Array(128).fill(void 0);F.push(void 0,null,!0,!1);var J=F.length;function R(A){J===F.length&&F.push(F.length+1);var g=J;return J=F[g],F[g]=A,g}function K(A){return F[A]}function y(A){var g=K(A);return function(A){A<132||(F[A]=J,J=A)}(A),g}var h=0,U=\\"undefined\\"!=typeof TextEncoder?new TextEncoder(\\"utf-8\\"):{encode:function(){throw Error(\\"TextEncoder not available\\")}},q=\\"function\\"==typeof U.encodeInto?function(A,g){return U.encodeInto(A,g)}:function(A,g){var I=U.encode(A);return g.set(I),{read:A.length,written:I.length}};function Y(A,g,I){if(void 0===I){var B=U.encode(A),Q=g(B.length,1)>>>0;return k().subarray(Q,Q+B.length).set(B),h=B.length,Q}for(var C=A.length,E=g(C,1)>>>0,D=k(),w=0;w127)break;D[E+w]=i}if(w!==C){0!==w&&(A=A.slice(w)),E=I(E,C,C=w+3*A.length,1)>>>0;var o=k().subarray(E+w,E+C);w+=q(A,o).written}return h=w,E}var L=null;function c(){return null!==L&&0!==L.byteLength||(L=new Int32Array(G.memory.buffer)),L}function H(A){var g=o(A);if(\\"number\\"==g||\\"boolean\\"==g||null==A)return\\"\\".concat(A);if(\\"string\\"==g)return'\\"'.concat(A,'\\"');if(\\"symbol\\"==g){var I=A.description;return null==I?\\"Symbol\\":\\"Symbol(\\".concat(I,\\")\\")}if(\\"function\\"==g){var B=A.name;return\\"string\\"==typeof B&&B.length>0?\\"Function(\\".concat(B,\\")\\"):\\"Function\\"}if(Array.isArray(A)){var Q=A.length,C=\\"[\\";Q>0&&(C+=H(A[0]));for(var E=1;E1))return toString.call(A);if(\\"Object\\"==(D=w[1]))try{return\\"Object(\\"+JSON.stringify(A)+\\")\\"}catch(A){return\\"Object\\"}return A instanceof Error?\\"\\".concat(A.name,\\": \\").concat(A.message,\\"\\\\n\\").concat(A.stack):D}function S(A,g,I){G.wasm_bindgen__convert__closures__invoke1_mut(A,g,R(I))}function s(A,g){G._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy(A,g)}var p=null;function O(A,g){for(var I=g(4*A.length,4)>>>0,B=(null!==p&&0!==p.byteLength||(p=new Uint32Array(G.memory.buffer)),p),Q=0;Q>>=0;var I=Object.create(A.prototype);return I.__wbg_ptr=g,I}},{key:\\"new\\",value:function(A,g){var I=O(g,G.__wbindgen_malloc),B=h;return y(G.ppom_new(R(A),I,B))}},{key:\\"version\\",value:function(){return y(G.ppom_version())}}],(I=[{key:\\"__destroy_into_raw\\",value:function(){var A=this.__wbg_ptr;return this.__wbg_ptr=0,A}},{key:\\"free\\",value:function(){var A=this.__destroy_into_raw();G.__wbg_ppom_free(A)}},{key:\\"validateJsonRpc\\",value:function(A){return y(G.ppom_validateJsonRpc(this.__wbg_ptr,R(A)))}}])&&i(g.prototype,I),B&&i(g,B),Object.defineProperty(g,\\"prototype\\",{writable:!1}),A}();function t(A,g){return d.apply(this,arguments)}function d(){return(d=w(E().mark((function A(g,I){var B,Q;return E().wrap((function(A){for(;;)switch(A.prev=A.next){case 0:if(!(\\"function\\"==typeof Response&&g instanceof Response)){A.next=23;break}if(\\"function\\"!=typeof WebAssembly.instantiateStreaming){A.next=15;break}return A.prev=2,A.next=5,WebAssembly.instantiateStreaming(g,I);case 5:case 20:return A.abrupt(\\"return\\",A.sent);case 8:if(A.prev=8,A.t0=A.catch(2),\\"application/wasm\\"==g.headers.get(\\"Content-Type\\")){A.next=14;break}console.warn(\\"\`WebAssembly.instantiateStreaming\` failed because your server does not serve wasm with \`application/wasm\` MIME type. Falling back to \`WebAssembly.instantiate\` which is slower. Original error:\\\\n\\",A.t0),A.next=15;break;case 14:throw A.t0;case 15:return A.next=17,g.arrayBuffer();case 17:return B=A.sent,A.next=20,WebAssembly.instantiate(B,I);case 23:return A.next=25,WebAssembly.instantiate(g,I);case 25:if(!((Q=A.sent)instanceof WebAssembly.Instance)){A.next=30;break}return A.abrupt(\\"return\\",{instance:Q,module:g});case 30:return A.abrupt(\\"return\\",Q);case 31:case\\"end\\":return A.stop()}}),A,null,[[2,8]])})))).apply(this,arguments)}function W(){var A={wbg:{}};return A.wbg.__wbg_buffer_085ec1f694018c4f=function(A){return R(K(A).buffer)},A.wbg.__wbg_call_01734de55d61e11d=function(){return x((function(A,g,I){return R(K(A).call(K(g),K(I)))}),arguments)},A.wbg.__wbg_call_4c92f6aec1e1d6e6=function(){return x((function(A,g,I,B){return R(K(A).call(K(g),K(I),K(B)))}),arguments)},A.wbg.__wbg_from_d7c216d4616bb368=function(A){return R(Array.from(K(A)))},A.wbg.__wbg_get_44be0491f933a435=function(A,g){return R(K(A)[g>>>0])},A.wbg.__wbg_length_72e2208bbc0efc61=function(A){return K(A).length},A.wbg.__wbg_length_d813e535247d427e=function(A){return K(A).length},A.wbg.__wbg_length_fff51ee6522a1a18=function(A){return K(A).length},A.wbg.__wbg_new_43f1b47c28813cbd=function(A,g){try{var I={a:A,b:g},B=new Promise((function(A,g){var B=I.a;I.a=0;try{return function(A,g,I,B){G.wasm_bindgen__convert__closures__invoke2_mut(A,g,R(I),R(B))}(B,I.b,A,g)}finally{I.a=B}}));return R(B)}finally{I.a=I.b=0}},A.wbg.__wbg_new_8125e318e6245eed=function(A){return R(new Uint8Array(K(A)))},A.wbg.__wbg_parse_670c19d4e984792e=function(){return x((function(A,g){return R(JSON.parse(a(A,g)))}),arguments)},A.wbg.__wbg_ppom_new=function(A){return R(T.__wrap(A))},A.wbg.__wbg_resolve_53698b95aaf7fcf8=function(A){return R(Promise.resolve(K(A)))},A.wbg.__wbg_set_5cf90238115182c3=function(A,g,I){K(A).set(K(g),I>>>0)},A.wbg.__wbg_stringify_e25465938f3f611f=function(){return x((function(A){return R(JSON.stringify(K(A)))}),arguments)},A.wbg.__wbg_then_b2267541e2a73865=function(A,g,I){return R(K(A).then(K(g),K(I)))},A.wbg.__wbg_then_f7e06ee3c11698eb=function(A,g){return R(K(A).then(K(g)))},A.wbg.__wbindgen_cb_drop=function(A){var g=y(A).original;if(1==g.cnt--)return g.a=0,!0;return!1},A.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined=function(A,g,I){var B=function(A,g,I,B){var Q={a:A,b:g,cnt:1},C=function(){Q.cnt++;var A=Q.a;Q.a=0;try{for(var g=arguments.length,C=new Array(g),E=0;E=0;--C){var E=this.tryEntries[C],D=E.completion;if(\\"root\\"===E.tryLoc)return Q(\\"end\\");if(E.tryLoc<=this.prev){var w=B.call(E,\\"catchLoc\\"),i=B.call(E,\\"finallyLoc\\");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,\\"finallyLoc\\")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),s(I),F}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if(\\"throw\\"===B.type){var Q=B.arg;s(I)}return Q}}throw new Error(\\"illegal catch attempt\\")},delegateYield:function(g,I,B){return this.delegate={iterator:O(g),resultName:I,nextLoc:B},\\"next\\"===this.method&&(this.arg=A),F}},g}function e(A,g){return function(A){if(Array.isArray(A))return A}(A)||function(A,g){var I=null==A?null:\\"undefined\\"!=typeof Symbol&&A[Symbol.iterator]||A[\\"@@iterator\\"];if(null!=I){var B,Q,C,E,D=[],w=!0,i=!1;try{if(C=(I=I.call(A)).next,0===g){if(Object(I)!==I)return;w=!1}else for(;!(w=(B=C.call(I)).done)&&(D.push(B.value),D.length!==g);w=!0);}catch(A){i=!0,Q=A}finally{try{if(!w&&null!=I.return&&(E=I.return(),Object(E)!==E))return}finally{if(i)throw Q}}return D}}(A,g)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return V(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===I&&A.constructor&&(I=A.constructor.name);if(\\"Map\\"===I||\\"Set\\"===I)return Array.from(A);if(\\"Arguments\\"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return V(A,g)}(A,g)||function(){throw new TypeError(\\"Invalid attempt to destructure non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function V(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I", } } /> From 88bdf4227714b9413f004eed527cf9289b6cdb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 20 Mar 2024 06:11:01 +0000 Subject: [PATCH 11/41] patch: (webview upgrade) Android filename validation when downloading from browser (#8654) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change is part of the file react-native-webview+11.13.0.patch, a collection of patches that we need to apply on top of react-native-webview. Original Pull Request: [#6844](https://github.com/MetaMask/metamask-mobile/pull/6844) Webview changes can be reviewed here: [MetaMask/react-native-webview-mm#7](https://github.com/MetaMask/react-native-webview-mm/pull/7) ``` Scenario: Download file with invalid file name Navigate to websites using browser address bar. Given the app displayed the splash animation And I have imported my wallet And I tap No Thanks on the Enable security check screen And I tap No thanks on the onboarding welcome tutorial And I navigate to the browser And I have 1 browser tab displayed When I download a file with invalid filename Then an error message should appear And the file is not download ``` https://github.com/MetaMask/metamask-mobile/assets/1649425/aa7d07a8-ab95-4f36-9325-bdcd6760dcd0 https://github.com/MetaMask/metamask-mobile/assets/1649425/3e3fd1cf-5593-4afb-8045-4666cad494cd - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've clearly explained what problem this PR is solving and how it is solved. - [ ] I've linked related issues - [ ] I've included manual testing steps - [ ] I've included screenshots/recordings if applicable - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. - [ ] I’ve properly set the pull request status: - [ ] In case it's not yet "ready for review", I've set it to "draft". - [ ] In case it's "ready for review", I've changed it from "draft" to "non-draft". - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. From 2c49ea1f163c16fdd9b493033988ae738ef2bbcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 26 Mar 2024 22:44:42 +0000 Subject: [PATCH 12/41] update rnwebview package reference --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 7301530daa5..59a1cebee34 100644 --- a/package.json +++ b/package.json @@ -315,7 +315,7 @@ "react-native-vector-icons": "6.4.2", "react-native-video": "5.2.1", "react-native-view-shot": "^3.1.2", - "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#9386bb762e8c740b676d31e2ef5c20e34421c36a", + "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#53bed05617f0fa46712e3b02cc041872dfc8a601", "react-native-webview-invoke": "^0.6.2", "react-redux": "7.2.4", "readable-stream": "2.3.7", diff --git a/yarn.lock b/yarn.lock index 2ac040cee44..9ee1b1bae10 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24225,9 +24225,9 @@ react-native-webview-invoke@^0.6.2: resolved "https://registry.yarnpkg.com/react-native-webview-invoke/-/react-native-webview-invoke-0.6.2.tgz#75cc27ef98ea1cbc9386269347d3aafe90d33aa3" integrity sha512-PCzP7Zl3XwHU10JYS8nR0gwuR8XiOO0MhC8y9ZuPPI+HeISn95GvNYhOXxeLgfbdbUcpNWh1HqxPDySlfCIqxg== -"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#9386bb762e8c740b676d31e2ef5c20e34421c36a": +"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#53bed05617f0fa46712e3b02cc041872dfc8a601": version "13.6.3" - resolved "https://github.com/MetaMask/react-native-webview-mm#9386bb762e8c740b676d31e2ef5c20e34421c36a" + resolved "https://github.com/MetaMask/react-native-webview-mm#53bed05617f0fa46712e3b02cc041872dfc8a601" dependencies: escape-string-regexp "2.0.0" invariant "2.2.4" From adce8d2d4c5f1ee2596befeccb8df0b392a4f158 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:16:26 +0000 Subject: [PATCH 13/41] update rnwebview package reference --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 59a1cebee34..c39be4552bb 100644 --- a/package.json +++ b/package.json @@ -315,7 +315,7 @@ "react-native-vector-icons": "6.4.2", "react-native-video": "5.2.1", "react-native-view-shot": "^3.1.2", - "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#53bed05617f0fa46712e3b02cc041872dfc8a601", + "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#683473b8ceaa3f5e6ebe22c0f3889d3e4fb51775", "react-native-webview-invoke": "^0.6.2", "react-redux": "7.2.4", "readable-stream": "2.3.7", diff --git a/yarn.lock b/yarn.lock index 9ee1b1bae10..6660b0a2293 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24225,9 +24225,9 @@ react-native-webview-invoke@^0.6.2: resolved "https://registry.yarnpkg.com/react-native-webview-invoke/-/react-native-webview-invoke-0.6.2.tgz#75cc27ef98ea1cbc9386269347d3aafe90d33aa3" integrity sha512-PCzP7Zl3XwHU10JYS8nR0gwuR8XiOO0MhC8y9ZuPPI+HeISn95GvNYhOXxeLgfbdbUcpNWh1HqxPDySlfCIqxg== -"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#53bed05617f0fa46712e3b02cc041872dfc8a601": +"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#683473b8ceaa3f5e6ebe22c0f3889d3e4fb51775": version "13.6.3" - resolved "https://github.com/MetaMask/react-native-webview-mm#53bed05617f0fa46712e3b02cc041872dfc8a601" + resolved "https://github.com/MetaMask/react-native-webview-mm#683473b8ceaa3f5e6ebe22c0f3889d3e4fb51775" dependencies: escape-string-regexp "2.0.0" invariant "2.2.4" From 8282a603f1ca9d6b914359e9c19fac997dc294d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 27 Mar 2024 11:52:45 +0000 Subject: [PATCH 14/41] update rnwebview package reference --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index c39be4552bb..80356fc99c0 100644 --- a/package.json +++ b/package.json @@ -315,7 +315,7 @@ "react-native-vector-icons": "6.4.2", "react-native-video": "5.2.1", "react-native-view-shot": "^3.1.2", - "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#683473b8ceaa3f5e6ebe22c0f3889d3e4fb51775", + "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#6864bed2c57fb9316653e6b9df2b92ffb1bf7caa", "react-native-webview-invoke": "^0.6.2", "react-redux": "7.2.4", "readable-stream": "2.3.7", diff --git a/yarn.lock b/yarn.lock index 6660b0a2293..d614734afc9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24225,9 +24225,9 @@ react-native-webview-invoke@^0.6.2: resolved "https://registry.yarnpkg.com/react-native-webview-invoke/-/react-native-webview-invoke-0.6.2.tgz#75cc27ef98ea1cbc9386269347d3aafe90d33aa3" integrity sha512-PCzP7Zl3XwHU10JYS8nR0gwuR8XiOO0MhC8y9ZuPPI+HeISn95GvNYhOXxeLgfbdbUcpNWh1HqxPDySlfCIqxg== -"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#683473b8ceaa3f5e6ebe22c0f3889d3e4fb51775": +"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#6864bed2c57fb9316653e6b9df2b92ffb1bf7caa": version "13.6.3" - resolved "https://github.com/MetaMask/react-native-webview-mm#683473b8ceaa3f5e6ebe22c0f3889d3e4fb51775" + resolved "https://github.com/MetaMask/react-native-webview-mm#6864bed2c57fb9316653e6b9df2b92ffb1bf7caa" dependencies: escape-string-regexp "2.0.0" invariant "2.2.4" From 4523fb3cb79b1cab1ef410ebdf8408a5843489fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 27 Mar 2024 17:02:04 +0000 Subject: [PATCH 15/41] update webview commit hash --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 80356fc99c0..910f55c7459 100644 --- a/package.json +++ b/package.json @@ -315,7 +315,7 @@ "react-native-vector-icons": "6.4.2", "react-native-video": "5.2.1", "react-native-view-shot": "^3.1.2", - "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#6864bed2c57fb9316653e6b9df2b92ffb1bf7caa", + "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#b27669c0dddf5420a3147113d475f3fbe1a27f60", "react-native-webview-invoke": "^0.6.2", "react-redux": "7.2.4", "readable-stream": "2.3.7", diff --git a/yarn.lock b/yarn.lock index d614734afc9..024c6ac3993 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24225,9 +24225,9 @@ react-native-webview-invoke@^0.6.2: resolved "https://registry.yarnpkg.com/react-native-webview-invoke/-/react-native-webview-invoke-0.6.2.tgz#75cc27ef98ea1cbc9386269347d3aafe90d33aa3" integrity sha512-PCzP7Zl3XwHU10JYS8nR0gwuR8XiOO0MhC8y9ZuPPI+HeISn95GvNYhOXxeLgfbdbUcpNWh1HqxPDySlfCIqxg== -"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#6864bed2c57fb9316653e6b9df2b92ffb1bf7caa": +"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#b27669c0dddf5420a3147113d475f3fbe1a27f60": version "13.6.3" - resolved "https://github.com/MetaMask/react-native-webview-mm#6864bed2c57fb9316653e6b9df2b92ffb1bf7caa" + resolved "https://github.com/MetaMask/react-native-webview-mm#b27669c0dddf5420a3147113d475f3fbe1a27f60" dependencies: escape-string-regexp "2.0.0" invariant "2.2.4" From 49fa4cba110218c8186acfdcd2c700c39d16189c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:23:38 +0000 Subject: [PATCH 16/41] remove build.sh changes --- scripts/build.sh | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/scripts/build.sh b/scripts/build.sh index 78106d02fd4..1022d574ca6 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -181,6 +181,8 @@ prebuild_ios(){ } prebuild_android(){ + adb kill-server + adb start-server prebuild # Copy JS files for injection yes | cp -rf app/core/InpageBridgeWeb3.js android/app/src/main/assets/. @@ -578,25 +580,6 @@ elif [ "$MODE" == "release" ] || [ "$MODE" == "flask" ]; then export SENTRY_PROPERTIES="${REPO_ROOT_DIR}/sentry.release.properties" fi -# set some defaults -if [ -z "$METAMASK_BUILD_TYPE" ]; then - METAMASK_BUILD_TYPE='main' -fi - -if [ -z "$METAMASK_ENVIRONMENT" ]; then - METAMASK_ENVIRONMENT='local' -fi - -if [ -z "$GIT_COMMIT" ]; then - GIT_COMMIT="$(git rev-parse --short HEAD)" - export GIT_COMMIT -fi - -if [ -z "$GIT_BRANCH" ]; then - GIT_BRANCH="$(git branch --show-current)" - export GIT_BRANCH -fi - if [ -z "$METAMASK_BUILD_TYPE" ]; then printError "Missing METAMASK_BUILD_TYPE; set to 'main' for a standard release, or 'flask' for a canary flask release. The default value is 'main'." exit 1 From 44d64806c444a80d9241052e615e2e0b43f732ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:27:38 +0000 Subject: [PATCH 17/41] remove bitrise.yml changes --- bitrise.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/bitrise.yml b/bitrise.yml index a4e44cd3a55..db59f8520a6 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -925,12 +925,7 @@ workflows: - content: |- #!/usr/bin/env bash node -v - COMMIT_SHORT_HASH="${BITRISE_GIT_COMMIT:0:7}" - - if [[ -z "$BITRISE_GIT_COMMIT" ]]; then - COMMIT_SHORT_HASH="$(git rev-parse --short HEAD)" - fi - GIT_BRANCH=$BITRISE_GIT_BRANCH GIT_COMMIT=$COMMIT_SHORT_HASH METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='qa' yarn build:android:pre-release:bundle:qa + GIT_BRANCH=$BITRISE_GIT_BRANCH METAMASK_BUILD_TYPE='main' METAMASK_ENVIRONMENT='qa' yarn build:android:pre-release:bundle:qa title: Build Android Pre-Release Bundle is_always_run: false - save-gradle-cache@1: {} From 4ccb4c3c399654e3d43a146a3b38b5fa37aa5f78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:28:34 +0000 Subject: [PATCH 18/41] remove AppInformation changes --- .../Views/Settings/AppInformation/index.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/app/components/Views/Settings/AppInformation/index.js b/app/components/Views/Settings/AppInformation/index.js index 48f788d40f6..a6b4e3f44ef 100644 --- a/app/components/Views/Settings/AppInformation/index.js +++ b/app/components/Views/Settings/AppInformation/index.js @@ -23,6 +23,8 @@ import AppConstants from '../../../../core/AppConstants'; import { ThemeContext, mockTheme } from '../../../../util/theme'; import { AboutMetaMaskSelectorsIDs } from '../../../../../e2e/selectors/Settings/AboutMetaMask.selectors'; +const IS_QA = process.env['METAMASK_ENVIRONMENT'] === 'qa'; + const createStyles = (colors) => StyleSheet.create({ wrapper: { @@ -185,12 +187,11 @@ export default class AppInformation extends PureComponent { resizeMethod={'auto'} /> {this.state.appInfo} - - {`Branch: ${process.env['GIT_BRANCH']}`} - - - {`Commit Hash: ${process.env['GIT_COMMIT']}`} - + {IS_QA ? ( + + {`Branch: ${process.env['GIT_BRANCH']}`} + + ) : null} {strings('app_information.links')} From 2c5a5857eee0121d4b1b2d8ead5fb3fc5207f432 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 28 Mar 2024 12:32:47 +0000 Subject: [PATCH 19/41] BrowserTab: more context about the eventListener Add better descriptive information on why we want to wait for DOM to be fully loaded before executing the web3 provider for the first time --- app/components/Views/BrowserTab/index.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index 32cb71cfcf7..3e82d47c148 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -1487,6 +1487,12 @@ export const BrowserTab = (props) => { ); + /* + * Wait DOM to be fully loaded before running the web3 provider script. + * This ensures all DOM objects are defined on first run. + */ + const loadJavascriptAfterDOMReady = `window.self.document.addEventListener("DOMContentLoaded", function() {${entryScriptWeb3}});` + /** * Main render */ @@ -1507,7 +1513,7 @@ export const BrowserTab = (props) => { )} source={{ uri: initialUrl }} - injectedJavaScriptBeforeContentLoaded={`window.self.document.addEventListener("DOMContentLoaded", function() {${entryScriptWeb3}});`} + injectedJavaScriptBeforeContentLoaded={loadJavascriptAfterDOMReady} style={styles.webview} onLoadStart={onLoadStart} onLoad={onLoad} From ad376920cebb4ec4e1de3b2533f2381de77deaf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 28 Mar 2024 13:44:57 +0000 Subject: [PATCH 20/41] update jest snapshots --- .../__snapshots__/index.test.tsx.snap | 28 ------------------- .../ppom/__snapshots__/PPOMView.test.tsx.snap | 6 ++-- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/app/components/Views/Settings/AppInformation/__snapshots__/index.test.tsx.snap b/app/components/Views/Settings/AppInformation/__snapshots__/index.test.tsx.snap index 3e6ed7a7b88..2cd2d4c4ae2 100644 --- a/app/components/Views/Settings/AppInformation/__snapshots__/index.test.tsx.snap +++ b/app/components/Views/Settings/AppInformation/__snapshots__/index.test.tsx.snap @@ -428,34 +428,6 @@ exports[`AppInformation should render correctly 1`] = ` } } /> - - Branch: undefined - - - Commit Hash: undefined - Webpack App", +g.read=function(A,g,I,B,Q){var C,E,D=8*Q-B-1,w=(1<>1,o=-7,M=I?Q-1:0,G=I?-1:1,N=A[g+M];for(M+=G,C=N&(1<<-o)-1,N>>=-o,o+=D;o>0;C=256*C+A[g+M],M+=G,o-=8);for(E=C&(1<<-o)-1,C>>=-o,o+=B;o>0;E=256*E+A[g+M],M+=G,o-=8);if(0===C)C=1-i;else{if(C===w)return E?NaN:1/0*(N?-1:1);E+=Math.pow(2,B),C-=i}return(N?-1:1)*E*Math.pow(2,C-B)},g.write=function(A,g,I,B,Q,C){var E,D,w,i=8*C-Q-1,o=(1<>1,G=23===Q?Math.pow(2,-24)-Math.pow(2,-77):0,N=B?0:C-1,k=B?1:-1,a=g<0||0===g&&1/g<0?1:0;for(g=Math.abs(g),isNaN(g)||g===1/0?(D=isNaN(g)?1:0,E=o):(E=Math.floor(Math.log(g)/Math.LN2),g*(w=Math.pow(2,-E))<1&&(E--,w*=2),(g+=E+M>=1?G/w:G*Math.pow(2,1-M))*w>=2&&(E++,w/=2),E+M>=o?(D=0,E=o):E+M>=1?(D=(g*w-1)*Math.pow(2,Q),E+=M):(D=g*Math.pow(2,M-1)*Math.pow(2,Q),E=0));Q>=8;A[I+N]=255&D,N+=k,D/=256,Q-=8);for(E=E<0;A[I+N]=255&E,N+=k,E/=256,i-=8);A[I+N-k]|=128*a}},204:(A,g,I)=>{var B=I(150);A.exports=B,A.exports.default=B},150:A=>{\\"use strict\\";function g(A){return g=\\"function\\"==typeof Symbol&&\\"symbol\\"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&\\"function\\"==typeof Symbol&&A.constructor===Symbol&&A!==Symbol.prototype?\\"symbol\\":typeof A},g(A)}function I(A){return function(A){if(Array.isArray(A))return B(A)}(A)||function(A){if(\\"undefined\\"!=typeof Symbol&&Symbol.iterator in Object(A))return Array.from(A)}(A)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return B(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===I&&A.constructor&&(I=A.constructor.name);if(\\"Map\\"===I||\\"Set\\"===I)return Array.from(A);if(\\"Arguments\\"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return B(A,g)}(A)||function(){throw new TypeError(\\"Invalid attempt to spread non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function B(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0&&B.splice(Q,1)}},emitEvent:function(A,I){A in g&&g[A].forEach((function(A){return A(I)}))}}),M={},G={},N={};function k(A){return function(){for(var g=arguments.length,I=new Array(g),B=0;B0&&void 0!==arguments[0]?arguments[0]:[]).filter((function(A){return!N[A]})).map((function(A){N[A]=k(A)})),function(){if(B){var A=B;B=null,A.forEach((function(A){F(A)})),o.emitEvent(\\"ready\\")}}(),Object.keys(G)}function h(){J(Object.keys(G)).then(K)}return a(Q,K),{bind:k,define:a,listener:function(A){if(A.reply){var g=i(A);M[g]&&(A.status===E?M[g].reject(A.data):M[g].resolve(A.data))}else if(G[A.command]){var I=G[A.command](A.data);I&&I.then?I.then((function(g){U(A,g,C)})).catch((function(g){U(A,g,E)})):U(A,I,C)}else U(A,\\"function \\".concat(A.command,\\" is not defined\\"),E);o.emitEvent(\\"receive\\",A)},ready:h,fn:N,addEventListener:o.addEventListener,removeEventListener:o.removeEventListener,isConnect:function(){return!B}}}((function(A){return M&&o&&o(JSON.stringify(A))})),N=G.bind,k=G.define,a=G.listener,F=G.ready,U=G.fn,J=G.addEventListener,K=G.removeEventListener,h=G.isConnect,y=function(A){var I=void 0;if(\\"object\\"===g(A))I=A;else if(\\"string\\"==typeof A)try{I=JSON.parse(A)}catch(A){}I&&(I.command||I.reply)&&a(I)};if(M){var R=window.originalPostMessage;if(R)o=function(){var A;return(A=window).postMessage.apply(A,arguments)},F();else{var Y={get:function(){return R},set:function(A){(R=A)&&(o=function(){var A;return(A=window).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,\\"originalPostMessage\\",Y)}var q=window.ReactNativeWebView;if(q)o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},F();else{var c={get:function(){return q},set:function(A){(q=A)&&(o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,\\"ReactNativeWebView\\",c)}window.document.addEventListener(\\"message\\",(function(A){return R&&y(A.data)})),window.addEventListener(\\"message\\",(function(A){return q&&y(A.data)})),window.document.addEventListener(\\"message\\",(function(A){return q&&y(A.data)}))}var L={bind:N,define:k,fn:U,addEventListener:J,removeEventListener:K,isConnect:h};A.exports=L}},g={};function I(B){var Q=g[B];if(void 0!==Q)return Q.exports;var C=g[B]={exports:{}};return A[B](C,C.exports,I),C.exports}I.n=A=>{var g=A&&A.__esModule?()=>A.default:()=>A;return I.d(g,{a:g}),g},I.d=(A,g)=>{for(var B in g)I.o(g,B)&&!I.o(A,B)&&Object.defineProperty(A,B,{enumerable:!0,get:g[B]})},I.o=(A,g)=>Object.prototype.hasOwnProperty.call(A,g),(()=>{\\"use strict\\";var A=I(204),g=I.n(A);function B(A){return function(A){if(Array.isArray(A))return Q(A)}(A)||function(A){if(\\"undefined\\"!=typeof Symbol&&null!=A[Symbol.iterator]||null!=A[\\"@@iterator\\"])return Array.from(A)}(A)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return Q(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===I&&A.constructor&&(I=A.constructor.name);if(\\"Map\\"===I||\\"Set\\"===I)return Array.from(A);if(\\"Arguments\\"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return Q(A,g)}(A)||function(){throw new TypeError(\\"Invalid attempt to spread non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function Q(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0;--C){var E=this.tryEntries[C],D=E.completion;if(\\"root\\"===E.tryLoc)return Q(\\"end\\");if(E.tryLoc<=this.prev){var w=B.call(E,\\"catchLoc\\"),i=B.call(E,\\"finallyLoc\\");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,\\"finallyLoc\\")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),p(I),J}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if(\\"throw\\"===B.type){var Q=B.arg;p(I)}return Q}}throw new Error(\\"illegal catch attempt\\")},delegateYield:function(g,I,B){return this.delegate={iterator:x(g),resultName:I,nextLoc:B},\\"next\\"===this.method&&(this.arg=A),J}},g}function D(A,g,I,B,Q,C,E){try{var D=A[C](E),w=D.value}catch(A){return void I(A)}D.done?g(w):Promise.resolve(w).then(B,Q)}function w(A){return function(){var g=this,I=arguments;return new Promise((function(B,Q){var C=A.apply(g,I);function E(A){D(C,B,Q,E,w,\\"next\\",A)}function w(A){D(C,B,Q,E,w,\\"throw\\",A)}E(void 0)}))}}function i(A,g){for(var I=0;I>>=0,G.decode(k().subarray(A,A+g))}var F=new Array(128).fill(void 0);F.push(void 0,null,!0,!1);var U=F.length;function J(A){U===F.length&&F.push(F.length+1);var g=U;return U=F[g],F[g]=A,g}function K(A){return F[A]}function h(A){var g=K(A);return function(A){A<132||(F[A]=U,U=A)}(A),g}var y=0,R=\\"undefined\\"!=typeof TextEncoder?new TextEncoder(\\"utf-8\\"):{encode:function(){throw Error(\\"TextEncoder not available\\")}},Y=\\"function\\"==typeof R.encodeInto?function(A,g){return R.encodeInto(A,g)}:function(A,g){var I=R.encode(A);return g.set(I),{read:A.length,written:I.length}};function q(A,g,I){if(void 0===I){var B=R.encode(A),Q=g(B.length,1)>>>0;return k().subarray(Q,Q+B.length).set(B),y=B.length,Q}for(var C=A.length,E=g(C,1)>>>0,D=k(),w=0;w127)break;D[E+w]=i}if(w!==C){0!==w&&(A=A.slice(w)),E=I(E,C,C=w+3*A.length,1)>>>0;var o=k().subarray(E+w,E+C);w+=Y(A,o).written}return y=w,E}var c=null;function L(){return null!==c&&0!==c.byteLength||(c=new Int32Array(M.memory.buffer)),c}function H(A){var g=o(A);if(\\"number\\"==g||\\"boolean\\"==g||null==A)return\\"\\".concat(A);if(\\"string\\"==g)return'\\"'.concat(A,'\\"');if(\\"symbol\\"==g){var I=A.description;return null==I?\\"Symbol\\":\\"Symbol(\\".concat(I,\\")\\")}if(\\"function\\"==g){var B=A.name;return\\"string\\"==typeof B&&B.length>0?\\"Function(\\".concat(B,\\")\\"):\\"Function\\"}if(Array.isArray(A)){var Q=A.length,C=\\"[\\";Q>0&&(C+=H(A[0]));for(var E=1;E1))return toString.call(A);if(\\"Object\\"==(D=w[1]))try{return\\"Object(\\"+JSON.stringify(A)+\\")\\"}catch(A){return\\"Object\\"}return A instanceof Error?\\"\\".concat(A.name,\\": \\").concat(A.message,\\"\\\\n\\").concat(A.stack):D}function S(A,g,I){M.wasm_bindgen__convert__closures__invoke1_mut(A,g,J(I))}function s(A,g){M._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy(A,g)}var O=null;function p(A,g){for(var I=g(4*A.length,4)>>>0,B=(null!==O&&0!==O.byteLength||(O=new Uint32Array(M.memory.buffer)),O),Q=0;Q>>=0;var I=Object.create(A.prototype);return I.__wbg_ptr=g,I}},{key:\\"new\\",value:function(A,g){var I=p(g,M.__wbindgen_malloc),B=y;return h(M.ppom_new(J(A),I,B))}},{key:\\"version\\",value:function(){return h(M.ppom_version())}}],(I=[{key:\\"__destroy_into_raw\\",value:function(){var A=this.__wbg_ptr;return this.__wbg_ptr=0,A}},{key:\\"free\\",value:function(){var A=this.__destroy_into_raw();M.__wbg_ppom_free(A)}},{key:\\"validateJsonRpc\\",value:function(A){return h(M.ppom_validateJsonRpc(this.__wbg_ptr,J(A)))}}])&&i(g.prototype,I),B&&i(g,B),Object.defineProperty(g,\\"prototype\\",{writable:!1}),A}();function t(A,g){return d.apply(this,arguments)}function d(){return(d=w(E().mark((function A(g,I){var B,Q;return E().wrap((function(A){for(;;)switch(A.prev=A.next){case 0:if(!(\\"function\\"==typeof Response&&g instanceof Response)){A.next=23;break}if(\\"function\\"!=typeof WebAssembly.instantiateStreaming){A.next=15;break}return A.prev=2,A.next=5,WebAssembly.instantiateStreaming(g,I);case 5:case 20:return A.abrupt(\\"return\\",A.sent);case 8:if(A.prev=8,A.t0=A.catch(2),\\"application/wasm\\"==g.headers.get(\\"Content-Type\\")){A.next=14;break}console.warn(\\"\`WebAssembly.instantiateStreaming\` failed because your server does not serve wasm with \`application/wasm\` MIME type. Falling back to \`WebAssembly.instantiate\` which is slower. Original error:\\\\n\\",A.t0),A.next=15;break;case 14:throw A.t0;case 15:return A.next=17,g.arrayBuffer();case 17:return B=A.sent,A.next=20,WebAssembly.instantiate(B,I);case 23:return A.next=25,WebAssembly.instantiate(g,I);case 25:if(!((Q=A.sent)instanceof WebAssembly.Instance)){A.next=30;break}return A.abrupt(\\"return\\",{instance:Q,module:g});case 30:return A.abrupt(\\"return\\",Q);case 31:case\\"end\\":return A.stop()}}),A,null,[[2,8]])})))).apply(this,arguments)}function P(){var A={wbg:{}};return A.wbg.__wbg_buffer_085ec1f694018c4f=function(A){return J(K(A).buffer)},A.wbg.__wbg_call_01734de55d61e11d=function(){return T((function(A,g,I){return J(K(A).call(K(g),K(I)))}),arguments)},A.wbg.__wbg_call_4c92f6aec1e1d6e6=function(){return T((function(A,g,I,B){return J(K(A).call(K(g),K(I),K(B)))}),arguments)},A.wbg.__wbg_from_d7c216d4616bb368=function(A){return J(Array.from(K(A)))},A.wbg.__wbg_get_44be0491f933a435=function(A,g){return J(K(A)[g>>>0])},A.wbg.__wbg_length_72e2208bbc0efc61=function(A){return K(A).length},A.wbg.__wbg_length_d813e535247d427e=function(A){return K(A).length},A.wbg.__wbg_length_fff51ee6522a1a18=function(A){return K(A).length},A.wbg.__wbg_new_43f1b47c28813cbd=function(A,g){try{var I={a:A,b:g},B=new Promise((function(A,g){var B=I.a;I.a=0;try{return function(A,g,I,B){M.wasm_bindgen__convert__closures__invoke2_mut(A,g,J(I),J(B))}(B,I.b,A,g)}finally{I.a=B}}));return J(B)}finally{I.a=I.b=0}},A.wbg.__wbg_new_8125e318e6245eed=function(A){return J(new Uint8Array(K(A)))},A.wbg.__wbg_parse_670c19d4e984792e=function(){return T((function(A,g){return J(JSON.parse(a(A,g)))}),arguments)},A.wbg.__wbg_ppom_new=function(A){return J(x.__wrap(A))},A.wbg.__wbg_resolve_53698b95aaf7fcf8=function(A){return J(Promise.resolve(K(A)))},A.wbg.__wbg_set_5cf90238115182c3=function(A,g,I){K(A).set(K(g),I>>>0)},A.wbg.__wbg_stringify_e25465938f3f611f=function(){return T((function(A){return J(JSON.stringify(K(A)))}),arguments)},A.wbg.__wbg_then_b2267541e2a73865=function(A,g,I){return J(K(A).then(K(g),K(I)))},A.wbg.__wbg_then_f7e06ee3c11698eb=function(A,g){return J(K(A).then(K(g)))},A.wbg.__wbindgen_cb_drop=function(A){var g=h(A).original;if(1==g.cnt--)return g.a=0,!0;return!1},A.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined=function(A,g,I){var B=function(A,g,I,B){var Q={a:A,b:g,cnt:1},C=function(){Q.cnt++;var A=Q.a;Q.a=0;try{for(var g=arguments.length,C=new Array(g),E=0;E=0;--C){var E=this.tryEntries[C],D=E.completion;if(\\"root\\"===E.tryLoc)return Q(\\"end\\");if(E.tryLoc<=this.prev){var w=B.call(E,\\"catchLoc\\"),i=B.call(E,\\"finallyLoc\\");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,\\"finallyLoc\\")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),s(I),F}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if(\\"throw\\"===B.type){var Q=B.arg;s(I)}return Q}}throw new Error(\\"illegal catch attempt\\")},delegateYield:function(g,I,B){return this.delegate={iterator:p(g),resultName:I,nextLoc:B},\\"next\\"===this.method&&(this.arg=A),F}},g}function m(A,g){return function(A){if(Array.isArray(A))return A}(A)||function(A,g){var I=null==A?null:\\"undefined\\"!=typeof Symbol&&A[Symbol.iterator]||A[\\"@@iterator\\"];if(null!=I){var B,Q,C,E,D=[],w=!0,i=!1;try{if(C=(I=I.call(A)).next,0===g){if(Object(I)!==I)return;w=!1}else for(;!(w=(B=C.call(I)).done)&&(D.push(B.value),D.length!==g);w=!0);}catch(A){i=!0,Q=A}finally{try{if(!w&&null!=I.return&&(E=I.return(),Object(E)!==E))return}finally{if(i)throw Q}}return D}}(A,g)||function(A,g){if(!A)return;if(\\"string\\"==typeof A)return V(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);\\"Object\\"===I&&A.constructor&&(I=A.constructor.name);if(\\"Map\\"===I||\\"Set\\"===I)return Array.from(A);if(\\"Arguments\\"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return V(A,g)}(A,g)||function(){throw new TypeError(\\"Invalid attempt to destructure non-iterable instance.\\\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\\")}()}function V(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I", } } /> From 9942634c3688ab64cafb1ea2833cc269a6c2f2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 2 Apr 2024 16:22:26 +0100 Subject: [PATCH 21/41] format code --- app/components/Views/BrowserTab/index.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index 3e82d47c148..9f99061e39b 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -1491,7 +1491,7 @@ export const BrowserTab = (props) => { * Wait DOM to be fully loaded before running the web3 provider script. * This ensures all DOM objects are defined on first run. */ - const loadJavascriptAfterDOMReady = `window.self.document.addEventListener("DOMContentLoaded", function() {${entryScriptWeb3}});` + const loadJavascriptAfterDOMReady = `window.self.document.addEventListener("DOMContentLoaded", function() {${entryScriptWeb3}});`; /** * Main render @@ -1513,7 +1513,9 @@ export const BrowserTab = (props) => { )} source={{ uri: initialUrl }} - injectedJavaScriptBeforeContentLoaded={loadJavascriptAfterDOMReady} + injectedJavaScriptBeforeContentLoaded={ + loadJavascriptAfterDOMReady + } style={styles.webview} onLoadStart={onLoadStart} onLoad={onLoad} From 00b15b44b78329af4de695111557837e4c0ca919 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 2 Apr 2024 17:22:25 +0100 Subject: [PATCH 22/41] move react-native-webview mock to testSetup --- app/__mocks__/react-native-webview.tsx | 8 -------- app/components/UI/Ramp/Views/Quotes/Quotes.test.tsx | 11 ----------- app/lib/ppom/PPOMView.test.tsx | 11 ----------- app/util/test/testSetup.js | 11 +++++++++++ 4 files changed, 11 insertions(+), 30 deletions(-) delete mode 100644 app/__mocks__/react-native-webview.tsx diff --git a/app/__mocks__/react-native-webview.tsx b/app/__mocks__/react-native-webview.tsx deleted file mode 100644 index 59abe4a8d39..00000000000 --- a/app/__mocks__/react-native-webview.tsx +++ /dev/null @@ -1,8 +0,0 @@ -import React from 'react'; -import { View, ViewProps } from 'react-native'; - -const WebView = (props: ViewProps) => ; - -export default { - WebView, -}; diff --git a/app/components/UI/Ramp/Views/Quotes/Quotes.test.tsx b/app/components/UI/Ramp/Views/Quotes/Quotes.test.tsx index 20e266fbad8..609dd618a62 100644 --- a/app/components/UI/Ramp/Views/Quotes/Quotes.test.tsx +++ b/app/components/UI/Ramp/Views/Quotes/Quotes.test.tsx @@ -1,5 +1,4 @@ import React from 'react'; -import { ViewProps } from 'react-native'; import { cloneDeep } from 'lodash'; import { ProviderBuyFeatureBrowserEnum, @@ -45,16 +44,6 @@ function render(Component: React.ComponentType) { jest.unmock('react-redux'); -jest.mock('react-native-webview', () => { - // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires - const { View } = require('react-native'); - const WebView = (props: ViewProps) => ; - - return { - WebView, - }; -}); - const mockSetOptions = jest.fn(); const mockNavigate = jest.fn(); const mockGoBack = jest.fn(); diff --git a/app/lib/ppom/PPOMView.test.tsx b/app/lib/ppom/PPOMView.test.tsx index e902a224875..c9093579f93 100644 --- a/app/lib/ppom/PPOMView.test.tsx +++ b/app/lib/ppom/PPOMView.test.tsx @@ -1,19 +1,8 @@ import React from 'react'; -import { ViewProps } from 'react-native'; import { render } from '@testing-library/react-native'; import { PPOMView } from './PPOMView'; -jest.mock('react-native-webview', () => { - // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires - const { View } = require('react-native'); - const WebView = (props: ViewProps) => ; - - return { - WebView, - }; -}); - describe('PPOMView', () => { it('should render correctly deeply', () => { const wrapper = render(); diff --git a/app/util/test/testSetup.js b/app/util/test/testSetup.js index cb3bef9d931..7126e970117 100644 --- a/app/util/test/testSetup.js +++ b/app/util/test/testSetup.js @@ -20,6 +20,17 @@ jest.mock('react-native', () => { return originalModule; }); +jest.mock('react-native-webview', () => { + // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires + const { View } = require('react-native'); + const WebView = (props) => ; + + return { + WebView, + }; +}); + + jest.mock('react-native-fs', () => ({ CachesDirectoryPath: jest.fn(), DocumentDirectoryPath: jest.fn(), From 976eb1a5b65b756db7b9fdd179cef0c42f45daa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 2 Apr 2024 17:22:39 +0100 Subject: [PATCH 23/41] update SimpleWebview jest snapshot --- .../Views/SimpleWebview/__snapshots__/index.test.tsx.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/Views/SimpleWebview/__snapshots__/index.test.tsx.snap b/app/components/Views/SimpleWebview/__snapshots__/index.test.tsx.snap index f704547b60b..f7f26ced692 100644 --- a/app/components/Views/SimpleWebview/__snapshots__/index.test.tsx.snap +++ b/app/components/Views/SimpleWebview/__snapshots__/index.test.tsx.snap @@ -8,7 +8,7 @@ exports[`SimpleWebview should render correctly 1`] = ` } } > - Date: Thu, 11 Apr 2024 11:47:01 +0100 Subject: [PATCH 24/41] webview jest mock: add GH issue for more context Add note comment to provide more context on why we need to mock webview to run jest --- app/util/test/testSetup.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/util/test/testSetup.js b/app/util/test/testSetup.js index 7126e970117..dae2d4ad005 100644 --- a/app/util/test/testSetup.js +++ b/app/util/test/testSetup.js @@ -20,6 +20,10 @@ jest.mock('react-native', () => { return originalModule; }); + /* + * NOTE: react-native-webview requires a jest mock starting on v12. + * More info on https://github.com/react-native-webview/react-native-webview/issues/2934 + */ jest.mock('react-native-webview', () => { // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires const { View } = require('react-native'); From 1849b1a21e91a7af5c23e4bc75c336c0df50274d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 11 Apr 2024 16:46:34 +0100 Subject: [PATCH 25/41] version bump: set version up for testflight upload --- android/app/build.gradle | 2 +- bitrise.yml | 4 ++-- ios/MetaMask.xcodeproj/project.pbxproj | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index 97bc4dfd830..fa0e5003b9a 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -181,7 +181,7 @@ android { applicationId "io.metamask" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1306 + versionCode 1307 versionName "7.19.1" testBuildType System.getProperty('testBuildType', 'debug') missingDimensionStrategy 'react-native-camera', 'general' diff --git a/bitrise.yml b/bitrise.yml index 9fff778e03b..791914bfcb1 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -1311,13 +1311,13 @@ app: VERSION_NAME: 7.19.1 - opts: is_expand: false - VERSION_NUMBER: 1306 + VERSION_NUMBER: 1307 - opts: is_expand: false FLASK_VERSION_NAME: 7.19.1 - opts: is_expand: false - FLASK_VERSION_NUMBER: 1306 + FLASK_VERSION_NUMBER: 1307 - opts: is_expand: false ANDROID_APK_LINK: '' diff --git a/ios/MetaMask.xcodeproj/project.pbxproj b/ios/MetaMask.xcodeproj/project.pbxproj index 96f00c4ded8..b607fecb2fe 100644 --- a/ios/MetaMask.xcodeproj/project.pbxproj +++ b/ios/MetaMask.xcodeproj/project.pbxproj @@ -1249,7 +1249,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1307; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1314,7 +1314,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1307; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1377,7 +1377,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1307; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1438,7 +1438,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1307; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1596,7 +1596,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1307; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1664,7 +1664,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1306; + CURRENT_PROJECT_VERSION = 1307; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; From 11f51eb20dc2f4616821c0d51cf307b174d2a7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 18 Apr 2024 12:56:34 +0100 Subject: [PATCH 26/41] Revert "version bump: set version up for testflight upload" This reverts commit 1849b1a21e91a7af5c23e4bc75c336c0df50274d. --- android/app/build.gradle | 2 +- bitrise.yml | 4 ++-- ios/MetaMask.xcodeproj/project.pbxproj | 12 ++++++------ 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index fa0e5003b9a..97bc4dfd830 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -181,7 +181,7 @@ android { applicationId "io.metamask" minSdkVersion rootProject.ext.minSdkVersion targetSdkVersion rootProject.ext.targetSdkVersion - versionCode 1307 + versionCode 1306 versionName "7.19.1" testBuildType System.getProperty('testBuildType', 'debug') missingDimensionStrategy 'react-native-camera', 'general' diff --git a/bitrise.yml b/bitrise.yml index 791914bfcb1..9fff778e03b 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -1311,13 +1311,13 @@ app: VERSION_NAME: 7.19.1 - opts: is_expand: false - VERSION_NUMBER: 1307 + VERSION_NUMBER: 1306 - opts: is_expand: false FLASK_VERSION_NAME: 7.19.1 - opts: is_expand: false - FLASK_VERSION_NUMBER: 1307 + FLASK_VERSION_NUMBER: 1306 - opts: is_expand: false ANDROID_APK_LINK: '' diff --git a/ios/MetaMask.xcodeproj/project.pbxproj b/ios/MetaMask.xcodeproj/project.pbxproj index b607fecb2fe..96f00c4ded8 100644 --- a/ios/MetaMask.xcodeproj/project.pbxproj +++ b/ios/MetaMask.xcodeproj/project.pbxproj @@ -1249,7 +1249,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1307; + CURRENT_PROJECT_VERSION = 1306; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1314,7 +1314,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1307; + CURRENT_PROJECT_VERSION = 1306; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1377,7 +1377,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1307; + CURRENT_PROJECT_VERSION = 1306; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1438,7 +1438,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1307; + CURRENT_PROJECT_VERSION = 1306; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; @@ -1596,7 +1596,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMaskDebug.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1307; + CURRENT_PROJECT_VERSION = 1306; DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = 48XVW22RCG; @@ -1664,7 +1664,7 @@ CODE_SIGN_ENTITLEMENTS = MetaMask/MetaMask.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1307; + CURRENT_PROJECT_VERSION = 1306; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 48XVW22RCG; "DEVELOPMENT_TEAM[sdk=iphoneos*]" = 48XVW22RCG; From dada90dcdf2126af40d930ebf89b4b1aec62a431 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 30 Apr 2024 10:43:08 +0100 Subject: [PATCH 27/41] remove event listener --- app/components/Views/BrowserTab/index.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index 9f99061e39b..61fc1c71bbc 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -1487,12 +1487,6 @@ export const BrowserTab = (props) => { ); - /* - * Wait DOM to be fully loaded before running the web3 provider script. - * This ensures all DOM objects are defined on first run. - */ - const loadJavascriptAfterDOMReady = `window.self.document.addEventListener("DOMContentLoaded", function() {${entryScriptWeb3}});`; - /** * Main render */ @@ -1513,9 +1507,7 @@ export const BrowserTab = (props) => { )} source={{ uri: initialUrl }} - injectedJavaScriptBeforeContentLoaded={ - loadJavascriptAfterDOMReady - } + injectedJavaScriptBeforeContentLoaded={entryScriptWeb3} style={styles.webview} onLoadStart={onLoadStart} onLoad={onLoad} From d182af30197908cea334ec22ab75d4d2cae79a6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 2 May 2024 16:07:09 +0100 Subject: [PATCH 28/41] conditional event listener --- app/components/Views/BrowserTab/index.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index 61fc1c71bbc..3a9ee2666d1 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -1487,6 +1487,18 @@ export const BrowserTab = (props) => { ); + /* + * Wait DOM Content to fully load if documentElement is null. + * Otherwise just run the web3 provider + */ + const loadJSSafely = `if (!document.documentElement) { + window.self.document.addEventListener("DOMContentLoaded", function() { + ${entryScriptWeb3} + }); + } else { + ${entryScriptWeb3} + }`; + /** * Main render */ @@ -1507,7 +1519,9 @@ export const BrowserTab = (props) => { )} source={{ uri: initialUrl }} - injectedJavaScriptBeforeContentLoaded={entryScriptWeb3} + injectedJavaScriptBeforeContentLoaded={ + Device.isAndroid() ? loadJSSafely : entryScriptWeb3 + } style={styles.webview} onLoadStart={onLoadStart} onLoad={onLoad} From ff4c36fe592fe32c8bd8756618a7822fec6d478a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 2 May 2024 22:21:05 +0100 Subject: [PATCH 29/41] test reloading page if documentElement is null --- app/components/Views/BrowserTab/index.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index 3a9ee2666d1..318562c8f3e 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -1492,9 +1492,7 @@ export const BrowserTab = (props) => { * Otherwise just run the web3 provider */ const loadJSSafely = `if (!document.documentElement) { - window.self.document.addEventListener("DOMContentLoaded", function() { - ${entryScriptWeb3} - }); + window.location.reload(); } else { ${entryScriptWeb3} }`; From 700f9fbbe933c060833aee6ba0e7137b07500618 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Fri, 3 May 2024 15:15:17 +0100 Subject: [PATCH 30/41] explain Android web3 provider injection workaround --- app/components/Views/BrowserTab/index.js | 30 ++++++++++++++++++------ 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index 318562c8f3e..64425ba0372 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -1488,15 +1488,33 @@ export const BrowserTab = (props) => { ); /* - * Wait DOM Content to fully load if documentElement is null. - * Otherwise just run the web3 provider - */ - const loadJSSafely = `if (!document.documentElement) { + * handleEarlyWeb3ProviderInit workaround. Android only + * + * It avoids the error 'Uncaught TypeError: Cannot read properties of null (reading 'nodeName')' + * by reloading the page if documentElement is not yet defined. + * + * This happens because web3 provider checks for valid HTML document prior initialization with + * document.documentElement.nodeName === 'html' + * + * We must inject the web3 provider at the early stages on the page loading so that + * dapps recognize metamask mobile provider correctly. + * + * This is caused by Android webview lifecycle method `onPageStarted` + * that might execute too early in the document loading phase. + * + * iOS devices aren't affected. + * + */ + const handleEarlyWeb3ProviderInit = `if (!document.documentElement) { window.location.reload(); } else { ${entryScriptWeb3} }`; + const handleInjectedJavaScript = Device.isAndroid() + ? handleEarlyWeb3ProviderInit + : entryScriptWeb3; + /** * Main render */ @@ -1517,9 +1535,7 @@ export const BrowserTab = (props) => { )} source={{ uri: initialUrl }} - injectedJavaScriptBeforeContentLoaded={ - Device.isAndroid() ? loadJSSafely : entryScriptWeb3 - } + injectedJavaScriptBeforeContentLoaded={handleInjectedJavaScript} style={styles.webview} onLoadStart={onLoadStart} onLoad={onLoad} From f3736c3cad77345d183c16d0b38f1a83128edf69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 8 May 2024 16:59:06 +0100 Subject: [PATCH 31/41] test webview fork last commit --- package.json | 2 +- yarn.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e4254e5811f..675262d3ce0 100644 --- a/package.json +++ b/package.json @@ -317,7 +317,7 @@ "react-native-vector-icons": "6.4.2", "react-native-video": "5.2.1", "react-native-view-shot": "^3.1.2", - "react-native-webview": "https://github.com/MetaMask/react-native-webview-mm#b27669c0dddf5420a3147113d475f3fbe1a27f60", + "react-native-webview": "metamask/react-native-webview-mm", "react-native-webview-invoke": "^0.6.2", "react-redux": "7.2.4", "readable-stream": "2.3.7", diff --git a/yarn.lock b/yarn.lock index e8763e93b5a..e34d1500730 100644 --- a/yarn.lock +++ b/yarn.lock @@ -24573,9 +24573,9 @@ react-native-webview-invoke@^0.6.2: resolved "https://registry.yarnpkg.com/react-native-webview-invoke/-/react-native-webview-invoke-0.6.2.tgz#75cc27ef98ea1cbc9386269347d3aafe90d33aa3" integrity sha512-PCzP7Zl3XwHU10JYS8nR0gwuR8XiOO0MhC8y9ZuPPI+HeISn95GvNYhOXxeLgfbdbUcpNWh1HqxPDySlfCIqxg== -"react-native-webview@https://github.com/MetaMask/react-native-webview-mm#b27669c0dddf5420a3147113d475f3fbe1a27f60": +react-native-webview@metamask/react-native-webview-mm: version "13.6.3" - resolved "https://github.com/MetaMask/react-native-webview-mm#b27669c0dddf5420a3147113d475f3fbe1a27f60" + resolved "https://codeload.github.com/metamask/react-native-webview-mm/tar.gz/a1144d9e000ac48e45046ec4ed594a48ddd643b9" dependencies: escape-string-regexp "2.0.0" invariant "2.2.4" From 7a8c028c1395f6b611628c252f5dd04b70ab9e22 Mon Sep 17 00:00:00 2001 From: tommasini <46944231+tommasini@users.noreply.github.com> Date: Mon, 3 Jun 2024 12:11:43 +0100 Subject: [PATCH 32/41] chore: migrate to mm webview npm registry (#9695) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## **Description** This PR migrates `react-native-webview` to `@metamask/react-native-webview` on the webview upgrade branch branch This is the [PR](https://github.com/MetaMask/metamask-mobile/pull/7759) of the main webview upgrade branch. * Removed react native animated fox package and created the component of react native animated fox. ## **Related issues** Fixes: ## **Manual testing steps** 1. Go to this page... 2. 3. ## **Screenshots/Recordings** ### **Before** ### **After** ## **Pre-merge author checklist** - [ ] I’ve followed [MetaMask Coding Standards](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/CODING_GUIDELINES.md). - [ ] I've completed the PR template to the best of my ability - [ ] I’ve included tests if applicable - [ ] I’ve documented my code using [JSDoc](https://jsdoc.app/) format if applicable - [ ] I’ve applied the right labels on the PR (see [labeling guidelines](https://github.com/MetaMask/metamask-mobile/blob/main/.github/guidelines/LABELING_GUIDELINES.md)). Not required for external contributors. ## **Pre-merge reviewer checklist** - [ ] I've manually tested the PR (e.g. pull and build branch, run the app, test code being changed). - [ ] I confirm that this PR addresses all acceptance criteria described in the ticket it closes and includes the necessary testing evidence such as recordings and or screenshots. --------- Co-authored-by: legobt <6wbvkn0j@anonaddy.me> Co-authored-by: sethkfman <10342624+sethkfman@users.noreply.github.com> Co-authored-by: Curtis --- .../Modals/ModalMandatory/ModalMandatory.tsx | 2 +- .../__snapshots__/index.test.tsx.snap | 1510 ++++++++++++++++ .../Base/AnimatedFox/index.test.tsx | 37 + app/components/Base/AnimatedFox/index.tsx | 1580 +++++++++++++++++ app/components/UI/Fox/index.js | 2 +- app/components/UI/Ramp/Views/Checkout.tsx | 2 +- app/components/UI/Ramp/index.tsx | 2 +- app/components/UI/WebviewError/index.js | 2 +- app/components/Views/BrowserTab/index.js | 2 +- app/components/Views/ChoosePassword/index.js | 2 +- app/components/Views/Login/index.js | 2 +- app/components/Views/Onboarding/index.js | 2 +- app/components/Views/ResetPassword/index.js | 2 +- app/components/Views/SimpleWebview/index.js | 2 +- .../ShowBlockExplorer/index.tsx | 2 +- app/lib/ppom/PPOMView.tsx | 2 +- app/lib/snaps/SnapsExecutionWebView.tsx | 4 +- app/util/test/testSetup.js | 10 +- e2e/pages/Browser/BrowserView.js | 15 +- e2e/pages/Browser/TestDApp.js | 26 +- e2e/utils/Matchers.js | 27 +- package.json | 3 +- yarn.lock | 22 +- 23 files changed, 3176 insertions(+), 84 deletions(-) create mode 100644 app/components/Base/AnimatedFox/__snapshots__/index.test.tsx.snap create mode 100644 app/components/Base/AnimatedFox/index.test.tsx create mode 100644 app/components/Base/AnimatedFox/index.tsx diff --git a/app/component-library/components/Modals/ModalMandatory/ModalMandatory.tsx b/app/component-library/components/Modals/ModalMandatory/ModalMandatory.tsx index 19149a50702..e4f585f156e 100644 --- a/app/component-library/components/Modals/ModalMandatory/ModalMandatory.tsx +++ b/app/component-library/components/Modals/ModalMandatory/ModalMandatory.tsx @@ -9,7 +9,7 @@ import { TouchableOpacity, View, } from 'react-native'; -import { WebView } from 'react-native-webview'; +import { WebView } from '@metamask/react-native-webview'; // External dependencies. import ButtonPrimary from '../../Buttons/Button/variants/ButtonPrimary'; diff --git a/app/components/Base/AnimatedFox/__snapshots__/index.test.tsx.snap b/app/components/Base/AnimatedFox/__snapshots__/index.test.tsx.snap new file mode 100644 index 00000000000..cba50627e80 --- /dev/null +++ b/app/components/Base/AnimatedFox/__snapshots__/index.test.tsx.snap @@ -0,0 +1,1510 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AnimatedFox renders correctly and matches snapshot 1`] = ` + + + + + --- + + + +

+ + + + ", + } + } + style={ + { + "flex": 1, + } + } +/> +`; diff --git a/app/components/Base/AnimatedFox/index.test.tsx b/app/components/Base/AnimatedFox/index.test.tsx new file mode 100644 index 00000000000..31d3fde17b3 --- /dev/null +++ b/app/components/Base/AnimatedFox/index.test.tsx @@ -0,0 +1,37 @@ +import React from 'react'; +import { render } from '@testing-library/react-native'; +import AnimatedFox from './'; +import { getTotalMemorySync } from 'react-native-device-info'; + +jest.mock('react-native-device-info', () => ({ + getTotalMemorySync: jest.fn(), +})); + +jest.mock('react-native-sensors', () => ({ + gyroscope: { + subscribe: jest.fn(({ next }) => { + next({ x: 1, y: 2 }); + + return { unsubscribe: jest.fn() }; + }), + }, + setUpdateIntervalForType: jest.fn(), + SensorTypes: { + gyroscope: 'gyroscope', + }, +})); + +describe('AnimatedFox', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + it('renders correctly and matches snapshot', () => { + // Mock device memory to ensure consistent environment for snapshot + (getTotalMemorySync as jest.Mock).mockReturnValueOnce( + 3 * 1024 * 1024 * 1024, + ); // Mock 3GB device + + const { toJSON } = render(); + expect(toJSON()).toMatchSnapshot(); + }); +}); diff --git a/app/components/Base/AnimatedFox/index.tsx b/app/components/Base/AnimatedFox/index.tsx new file mode 100644 index 00000000000..51eb1afc844 --- /dev/null +++ b/app/components/Base/AnimatedFox/index.tsx @@ -0,0 +1,1580 @@ +/* eslint-disable react/prop-types */ +import React, { useEffect, useRef } from 'react'; +import { WebView } from '@metamask/react-native-webview'; +import { + gyroscope, + SensorTypes, + setUpdateIntervalForType, +} from 'react-native-sensors'; +import { getTotalMemorySync } from 'react-native-device-info'; + +interface AnimatedFoxProps { + bgColor: string; +} +const round = (value: number, decimals: number): number => + Number(Math.round(Number(value + 'e' + decimals)) + 'e-' + decimals); + +const styles = { flex: 1 }; + +const AnimatedFox: React.FC = ({ bgColor }) => { + const webviewRef = useRef(null); + const position = useRef({ beta: 0, gamma: 0 }); + + /** + * If a device have lower than 2GB Ram we consider a low end device + * @returns boolean + */ + const isLowEndDevice = () => { + // Total device memory in bytes. + const totalMemory = getTotalMemorySync(); + const oneGigaByte = 1024 * 1024 * 1024; + return totalMemory <= 2 * oneGigaByte; + }; + + useEffect(() => { + const updateInterval = isLowEndDevice() ? 1000 / 30 : 1000 / 60; // 30Hz for low-end, 60Hz for others. + setUpdateIntervalForType(SensorTypes.gyroscope, updateInterval); + + const subscription = gyroscope.subscribe({ + next: ({ x, y }) => { + position.current = { + beta: position.current.beta - round(x * -10, 4), + gamma: position.current.gamma - round(y * -10, 4), + }; + + requestAnimationFrame(() => { + const JS = ` + (function () { + const event = new CustomEvent('nativedeviceorientation', { + detail: { + beta:${position.current.beta}, + gamma:${position.current.gamma} + } + }); + + window.dispatchEvent(event); + })(); + `; + webviewRef.current?.injectJavaScript(JS); + }); + }, + error: () => { + // gyroscope is not available + }, + }); + + return () => { + subscription.unsubscribe(); + }; + }, []); + + return ( + + + + + --- + + + +
+ + + + `, + }} + javaScriptEnabled + bounces={false} + scrollEnabled={false} + injectedJavaScript={`document.body.style.background="${bgColor}"`} + /> + ); +}; + +AnimatedFox.defaultProps = { + bgColor: 'white', +}; + +export default AnimatedFox; diff --git a/app/components/UI/Fox/index.js b/app/components/UI/Fox/index.js index 8e18da54c6f..8767c05f41f 100644 --- a/app/components/UI/Fox/index.js +++ b/app/components/UI/Fox/index.js @@ -1,7 +1,7 @@ import React, { forwardRef } from 'react'; import PropTypes from 'prop-types'; import { StyleSheet } from 'react-native'; -import { WebView } from 'react-native-webview'; +import { WebView } from '@metamask/react-native-webview'; import { useTheme } from '../../../util/theme'; import Animated, { useAnimatedStyle, diff --git a/app/components/UI/Ramp/Views/Checkout.tsx b/app/components/UI/Ramp/Views/Checkout.tsx index f532aee5b94..85eb8b52baf 100644 --- a/app/components/UI/Ramp/Views/Checkout.tsx +++ b/app/components/UI/Ramp/Views/Checkout.tsx @@ -2,7 +2,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import { View } from 'react-native'; import { useDispatch } from 'react-redux'; import { parseUrl } from 'query-string'; -import { WebView, WebViewNavigation } from 'react-native-webview'; +import { WebView, WebViewNavigation } from '@metamask/react-native-webview'; import { useNavigation } from '@react-navigation/native'; import { Provider } from '@consensys/on-ramp-sdk'; import { OrderOrderTypeEnum } from '@consensys/on-ramp-sdk/dist/API'; diff --git a/app/components/UI/Ramp/index.tsx b/app/components/UI/Ramp/index.tsx index d3ee337d6b7..f065676d12f 100644 --- a/app/components/UI/Ramp/index.tsx +++ b/app/components/UI/Ramp/index.tsx @@ -4,7 +4,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { useNavigation } from '@react-navigation/native'; import { Order } from '@consensys/on-ramp-sdk'; import { OrderOrderTypeEnum } from '@consensys/on-ramp-sdk/dist/API'; -import WebView from 'react-native-webview'; +import WebView from '@metamask/react-native-webview'; import AppConstants from '../../../core/AppConstants'; import NotificationManager from '../../../core/NotificationManager'; import { FIAT_ORDER_STATES } from '../../../constants/on-ramp'; diff --git a/app/components/UI/WebviewError/index.js b/app/components/UI/WebviewError/index.js index 0ea91894b55..5665243ee35 100644 --- a/app/components/UI/WebviewError/index.js +++ b/app/components/UI/WebviewError/index.js @@ -4,7 +4,7 @@ import { Image, StyleSheet, View, Text, Platform } from 'react-native'; import StyledButton from '../StyledButton'; import { strings } from '../../../../locales/i18n'; import { fontStyles } from '../../../styles/common'; -import AnimatedFox from '@metamask/react-native-animated-fox'; +import AnimatedFox from '../../Base/AnimatedFox'; import { ThemeContext, mockTheme } from '../../../util/theme'; import Device from '../../../util/device'; import generateTestId from '../../../../wdio/utils/generateTestId'; diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index b69a9f31103..00ab9126797 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -11,7 +11,7 @@ import { } from 'react-native'; import { isEqual } from 'lodash'; import { withNavigation } from '@react-navigation/compat'; -import { WebView } from 'react-native-webview'; +import { WebView } from '@metamask/react-native-webview'; import Icon from 'react-native-vector-icons/FontAwesome'; import MaterialCommunityIcon from 'react-native-vector-icons/MaterialCommunityIcons'; import BrowserBottomBar from '../../UI/BrowserBottomBar'; diff --git a/app/components/Views/ChoosePassword/index.js b/app/components/Views/ChoosePassword/index.js index 2c43cb981b9..a562adfa0da 100644 --- a/app/components/Views/ChoosePassword/index.js +++ b/app/components/Views/ChoosePassword/index.js @@ -57,7 +57,7 @@ import { MetaMetricsEvents } from '../../../core/Analytics'; import { Authentication } from '../../../core'; import AUTHENTICATION_TYPE from '../../../constants/userProperties'; import { ThemeContext, mockTheme } from '../../../util/theme'; -import AnimatedFox from '@metamask/react-native-animated-fox'; +import AnimatedFox from '../../Base/AnimatedFox'; import { LoginOptionsSwitch } from '../../UI/LoginOptionsSwitch'; import navigateTermsOfUse from '../../../util/termsOfUse/termsOfUse'; diff --git a/app/components/Views/Login/index.js b/app/components/Views/Login/index.js index 2a449c674d4..a7558291ec5 100644 --- a/app/components/Views/Login/index.js +++ b/app/components/Views/Login/index.js @@ -47,7 +47,7 @@ import DefaultPreference from 'react-native-default-preference'; import { Authentication } from '../../../core'; import AUTHENTICATION_TYPE from '../../../constants/userProperties'; import { ThemeContext, mockTheme } from '../../../util/theme'; -import AnimatedFox from '@metamask/react-native-animated-fox'; +import AnimatedFox from '../../Base/AnimatedFox'; import { LoginOptionsSwitch } from '../../UI/LoginOptionsSwitch'; import { createRestoreWalletNavDetailsNested } from '../RestoreWallet/RestoreWallet'; import { parseVaultValue } from '../../../util/validators'; diff --git a/app/components/Views/Onboarding/index.js b/app/components/Views/Onboarding/index.js index a94b4179995..7c7599904c6 100644 --- a/app/components/Views/Onboarding/index.js +++ b/app/components/Views/Onboarding/index.js @@ -43,7 +43,7 @@ import { MetaMetricsEvents } from '../../../core/Analytics'; import { withMetricsAwareness } from '../../hooks/useMetrics'; import { Authentication } from '../../../core'; import { ThemeContext, mockTheme } from '../../../util/theme'; -import AnimatedFox from '@metamask/react-native-animated-fox'; +import AnimatedFox from '../../Base/AnimatedFox'; import { OnboardingSelectorIDs } from '../../../../e2e/selectors/Onboarding/Onboarding.selectors'; import Routes from '../../../constants/navigation/Routes'; diff --git a/app/components/Views/ResetPassword/index.js b/app/components/Views/ResetPassword/index.js index c0546a6230c..2a941448c27 100644 --- a/app/components/Views/ResetPassword/index.js +++ b/app/components/Views/ResetPassword/index.js @@ -49,7 +49,7 @@ import { import { Authentication } from '../../../core'; import AUTHENTICATION_TYPE from '../../../constants/userProperties'; import { ThemeContext, mockTheme } from '../../../util/theme'; -import AnimatedFox from '@metamask/react-native-animated-fox'; +import AnimatedFox from '../../Base/AnimatedFox'; import { LoginOptionsSwitch } from '../../UI/LoginOptionsSwitch'; import { recreateVaultWithNewPassword } from '../../../core/Vault'; import Logger from '../../../util/Logger'; diff --git a/app/components/Views/SimpleWebview/index.js b/app/components/Views/SimpleWebview/index.js index c9b9dd933b3..5ff7318ca50 100644 --- a/app/components/Views/SimpleWebview/index.js +++ b/app/components/Views/SimpleWebview/index.js @@ -1,7 +1,7 @@ import React, { PureComponent } from 'react'; import PropTypes from 'prop-types'; import { View } from 'react-native'; -import { WebView } from 'react-native-webview'; +import { WebView } from '@metamask/react-native-webview'; import { getWebviewNavbar } from '../../UI/Navbar'; import Share from 'react-native-share'; // eslint-disable-line import/default import Logger from '../../../util/Logger'; diff --git a/app/components/Views/confirmations/components/ApproveTransactionReview/ShowBlockExplorer/index.tsx b/app/components/Views/confirmations/components/ApproveTransactionReview/ShowBlockExplorer/index.tsx index 43698e04a31..bce30493f6e 100644 --- a/app/components/Views/confirmations/components/ApproveTransactionReview/ShowBlockExplorer/index.tsx +++ b/app/components/Views/confirmations/components/ApproveTransactionReview/ShowBlockExplorer/index.tsx @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import { SafeAreaView, StyleSheet, View } from 'react-native'; import AntDesignIcon from 'react-native-vector-icons/AntDesign'; -import { WebView } from 'react-native-webview'; +import { WebView } from '@metamask/react-native-webview'; import type { NetworkState } from '@metamask/network-controller'; import Text, { diff --git a/app/lib/ppom/PPOMView.tsx b/app/lib/ppom/PPOMView.tsx index 956bea9b3ec..57d9acb3ab0 100644 --- a/app/lib/ppom/PPOMView.tsx +++ b/app/lib/ppom/PPOMView.tsx @@ -1,6 +1,6 @@ import React, { Component, RefObject } from 'react'; import { StyleSheet, View } from 'react-native'; -import { WebView } from 'react-native-webview'; +import { WebView } from '@metamask/react-native-webview'; import createInvoke from 'react-native-webview-invoke/native'; import { fromByteArray } from 'react-native-quick-base64'; diff --git a/app/lib/snaps/SnapsExecutionWebView.tsx b/app/lib/snaps/SnapsExecutionWebView.tsx index 5b92a9a7d72..a1d5a6c6294 100644 --- a/app/lib/snaps/SnapsExecutionWebView.tsx +++ b/app/lib/snaps/SnapsExecutionWebView.tsx @@ -4,10 +4,10 @@ ///: BEGIN:ONLY_INCLUDE_IF(snaps) import React, { Component, RefObject } from 'react'; import { View, ScrollView, NativeSyntheticEvent } from 'react-native'; -import WebView, { WebViewMessageEvent } from 'react-native-webview'; +import WebView, { WebViewMessageEvent } from '@metamask/react-native-webview'; import { createStyles } from './styles'; import { WebViewInterface } from '@metamask/snaps-controllers/dist/types/services/webview/WebViewMessageStream'; -import { WebViewError } from 'react-native-webview/lib/WebViewTypes'; +import { WebViewError } from '@metamask/react-native-webview/lib/WebViewTypes'; import { PostMessageEvent } from '@metamask/post-message-stream'; const styles = createStyles(); diff --git a/app/util/test/testSetup.js b/app/util/test/testSetup.js index 3b5be676516..71168659c40 100644 --- a/app/util/test/testSetup.js +++ b/app/util/test/testSetup.js @@ -20,11 +20,11 @@ jest.mock('react-native', () => { return originalModule; }); - /* - * NOTE: react-native-webview requires a jest mock starting on v12. - * More info on https://github.com/react-native-webview/react-native-webview/issues/2934 - */ -jest.mock('react-native-webview', () => { +/* + * NOTE: react-native-webview requires a jest mock starting on v12. + * More info on https://github.com/react-native-webview/react-native-webview/issues/2934 + */ +jest.mock('@metamask/react-native-webview', () => { // eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires const { View } = require('react-native'); const WebView = (props) => ; diff --git a/e2e/pages/Browser/BrowserView.js b/e2e/pages/Browser/BrowserView.js index f7a8357bd1f..cfeb40bba7f 100644 --- a/e2e/pages/Browser/BrowserView.js +++ b/e2e/pages/Browser/BrowserView.js @@ -63,22 +63,13 @@ class Browser { ); } get HomePageFavourtiesTab() { - return Matchers.getElementByXPath( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - BrowserViewSelectorsXPaths.FAVORITE_TAB, - ); + return Matchers.getElementByXPath(BrowserViewSelectorsXPaths.FAVORITE_TAB); } get TestDappURLInFavourtiesTab() { return device.getPlatform() === 'ios' - ? Matchers.getElementByXPath( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - BrowserViewSelectorsXPaths.TEST_DAPP_LINK, - ) - : Matchers.getElementByXPath( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - BrowserViewSelectorsXPaths.TEST_DAPP_TEXT, - ); + ? Matchers.getElementByXPath(BrowserViewSelectorsXPaths.TEST_DAPP_LINK) + : Matchers.getElementByXPath(BrowserViewSelectorsXPaths.TEST_DAPP_TEXT); } get multiTabButton() { diff --git a/e2e/pages/Browser/TestDApp.js b/e2e/pages/Browser/TestDApp.js index aee463497bd..fe25042909f 100644 --- a/e2e/pages/Browser/TestDApp.js +++ b/e2e/pages/Browser/TestDApp.js @@ -23,59 +23,42 @@ class TestDApp { } get DappConnectButton() { - return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - TestDappSelectorsWebIDs.CONNECT_BUTTON, - ); + return Matchers.getElementByWebID(TestDappSelectorsWebIDs.CONNECT_BUTTON); } get ApproveButton() { return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.APPROVE_TOKENS_BUTTON_ID, ); } // This taps on the transfer tokens button under the "SEND TOKENS section" get erc20TransferTokensButton() { return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.ERC_20_SEND_TOKENS_TRANSFER_TOKENS_BUTTON_ID, ); } get ethSignButton() { - return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - TestDappSelectorsWebIDs.ETH_SIGN, - ); + return Matchers.getElementByWebID(TestDappSelectorsWebIDs.ETH_SIGN); } get personalSignButton() { - return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - TestDappSelectorsWebIDs.PERSONAL_SIGN, - ); + return Matchers.getElementByWebID(TestDappSelectorsWebIDs.PERSONAL_SIGN); } get signTypedDataButton() { - return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, - TestDappSelectorsWebIDs.SIGN_TYPE_DATA, - ); + return Matchers.getElementByWebID(TestDappSelectorsWebIDs.SIGN_TYPE_DATA); } get signTypedDataV3Button() { return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.SIGN_TYPE_DATA_V3, ); } get signTypedDataV4Button() { return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.SIGN_TYPE_DATA_V4, ); } // This taps on the transfer tokens button under the "SEND TOKENS section" get nftTransferFromTokensButton() { return Matchers.getElementByWebID( - BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.NFT_TRANSFER_FROM_BUTTON_ID, ); } @@ -119,7 +102,6 @@ class TestDApp { } async tapButton(elementId) { - await Gestures.scrollToWebViewPort(elementId); await Gestures.tapWebElement(elementId); } diff --git a/e2e/utils/Matchers.js b/e2e/utils/Matchers.js index 8f9c1afc6aa..722cd7eabbb 100644 --- a/e2e/utils/Matchers.js +++ b/e2e/utils/Matchers.js @@ -76,13 +76,16 @@ class Matchers { /** * Get element by web ID. * - * * @param {string} webviewID - The web ID of the inner element to locate within the webview * @param {string} innerID - The web ID of the browser webview * @return {Promise} Resolves to the located element */ - static async getElementByWebID(webviewID, innerID) { - const myWebView = web(by.id(webviewID)); - return myWebView.element(by.web.id(innerID)); + static async getElementByWebID(innerID) { + if ((await device.getPlatform()) === 'android') { + return web.element(by.web.id(innerID)); + } else if ((await device.getPlatform()) === 'ios') { + const myWebView = web(by.id('browser-webview')); + return myWebView.element(by.web.id(innerID)); + } } /** @@ -92,9 +95,8 @@ class Matchers { * @return {Promise} - Resolves to the located element */ - static async getElementByCSS(webviewID, selector) { - const myWebView = web(by.id(webviewID)); - return myWebView.element(by.web.cssSelector(selector)).atIndex(0); + static async getElementByCSS(selector) { + return web.element(by.web.cssSelector(selector)); } /** @@ -103,19 +105,16 @@ class Matchers { * @param {string} xpath - XPath expression to locate the element * @return {Promise} - Resolves to the located element */ - static async getElementByXPath(webviewID, xpath) { - const myWebView = web(by.id(webviewID)); - return myWebView.element(by.web.xpath(xpath)).atIndex(0); + static async getElementByXPath(xpath) { + return web.element(by.web.xpath(xpath)).atIndex(0); } /** * Get element by href. - * @param {string} webviewID - The web ID of the browser webview * @param {string} xpath - XPath expression to locate the element * @return {Promise} - Resolves to the located element */ - static async getElementByHref(webviewID, url) { - const myWebView = web(by.id(webviewID)); - return myWebView.element(by.web.href(url)).atIndex(0); + static async getElementByHref(url) { + return web.element(by.web.href(url)).atIndex(0); } /** diff --git a/package.json b/package.json index 8ec1a71d7b7..29d19104d05 100644 --- a/package.json +++ b/package.json @@ -160,11 +160,11 @@ "@metamask/ppom-validator": "0.30.0", "@metamask/preferences-controller": "^8.0.0", "@metamask/react-native-actionsheet": "2.4.2", - "@metamask/react-native-animated-fox": "^2.1.0", "@metamask/react-native-button": "^3.0.0", "@metamask/react-native-payments": "^2.0.0", "@metamask/react-native-search-api": "1.0.1", "@metamask/react-native-splash-screen": "^3.2.0", + "@metamask/react-native-webview": "^14.0.1", "@metamask/rpc-errors": "^6.2.1", "@metamask/scure-bip39": "^2.1.0", "@metamask/sdk-communication-layer": "^0.20.2", @@ -318,7 +318,6 @@ "react-native-vector-icons": "6.4.2", "react-native-video": "5.2.1", "react-native-view-shot": "^3.1.2", - "react-native-webview": "metamask/react-native-webview-mm", "react-native-webview-invoke": "^0.6.2", "react-redux": "^8.1.3", "readable-stream": "2.3.7", diff --git a/yarn.lock b/yarn.lock index 2b8df1310d6..162584760df 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4600,13 +4600,6 @@ resolved "https://registry.yarnpkg.com/@metamask/react-native-actionsheet/-/react-native-actionsheet-2.4.2.tgz#9f956fe9e784d92c8e33656877fcfaabe4a482f1" integrity sha512-oibRXUzF+7DB0Nyzp2cMGN7ztB9Sl21W1NFq1IMa00mB4/X43JY+u+LCkx625WvQUeq0GO2ZQ6hG1L5XjMumSA== -"@metamask/react-native-animated-fox@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@metamask/react-native-animated-fox/-/react-native-animated-fox-2.1.0.tgz#504e1f68e13ad273fb193c6f6a3832f3a5242518" - integrity sha512-Hc+DyaEIXYa7NjzqXfgh01bsoP9WbE/ENNKZ4A65YwSBmJk5ZDvhMgTMFz+qybkUllx4kn4ENkmr0SXERZ2wmg== - dependencies: - prop-types "^15.5.10" - "@metamask/react-native-button@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@metamask/react-native-button/-/react-native-button-3.0.0.tgz#4af8affd11e2b285cfc1b1752280797e1b33e62b" @@ -4633,6 +4626,14 @@ resolved "https://registry.yarnpkg.com/@metamask/react-native-splash-screen/-/react-native-splash-screen-3.2.0.tgz#06a6547c143b088e47af40eacea9ac6657ac937f" integrity sha512-V8Cn0MXe9jdaUli/DK3PoJ71tx7k3IW2v2slqflvNstvHiO3MpCtdylsYIyu+tiPwI2JiyLRzLK8s02/3jxk6g== +"@metamask/react-native-webview@^14.0.1": + version "14.0.1" + resolved "https://registry.yarnpkg.com/@metamask/react-native-webview/-/react-native-webview-14.0.1.tgz#db1a1f4abea077b17fcc163538db4fcd7b2890bd" + integrity sha512-euctbS170XwxCCOIP36pr3N2bW8hQdZIKzpoEpWFK+5aumQ7UrTmwswcD3OCqnlk5JvpsRvlixIje8AA+6Gmtg== + dependencies: + escape-string-regexp "2.0.0" + invariant "2.2.4" + "@metamask/rpc-errors@^6.0.0", "@metamask/rpc-errors@^6.1.0", "@metamask/rpc-errors@^6.2.1": version "6.2.1" resolved "https://registry.yarnpkg.com/@metamask/rpc-errors/-/rpc-errors-6.2.1.tgz#f5daf429ededa7cb83069dc621bd5738fe2a1d80" @@ -24839,13 +24840,6 @@ react-native-webview-invoke@^0.6.2: resolved "https://registry.yarnpkg.com/react-native-webview-invoke/-/react-native-webview-invoke-0.6.2.tgz#75cc27ef98ea1cbc9386269347d3aafe90d33aa3" integrity sha512-PCzP7Zl3XwHU10JYS8nR0gwuR8XiOO0MhC8y9ZuPPI+HeISn95GvNYhOXxeLgfbdbUcpNWh1HqxPDySlfCIqxg== -react-native-webview@metamask/react-native-webview-mm: - version "13.6.3" - resolved "https://codeload.github.com/metamask/react-native-webview-mm/tar.gz/a1144d9e000ac48e45046ec4ed594a48ddd643b9" - dependencies: - escape-string-regexp "2.0.0" - invariant "2.2.4" - react-native@0.71.15: version "0.71.15" resolved "https://registry.yarnpkg.com/react-native/-/react-native-0.71.15.tgz#7d99f478238c559b8b3fdaad2514f11d53ef135a" From c509878a9ba893ce83eb00aba23497cf0ac36ea9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:02:24 +0100 Subject: [PATCH 33/41] update podfile lock --- ios/Podfile.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 6e0bca3a5d0..b0636a31545 100755 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -500,7 +500,7 @@ PODS: - React-Core - react-native-view-shot (3.1.2): - React - - react-native-webview (13.6.3): + - react-native-webview-mm (14.0.1): - React-Core - React-perflogger (0.71.15) - React-RCTActionSheet (0.71.15): @@ -762,7 +762,7 @@ DEPENDENCIES: - "react-native-splash-screen (from `../node_modules/@metamask/react-native-splash-screen`)" - react-native-video (from `../node_modules/react-native-video`) - react-native-view-shot (from `../node_modules/react-native-view-shot`) - - react-native-webview (from `../node_modules/react-native-webview`) + - "react-native-webview-mm (from `../node_modules/@metamask/react-native-webview`)" - React-perflogger (from `../node_modules/react-native/ReactCommon/reactperflogger`) - React-RCTActionSheet (from `../node_modules/react-native/Libraries/ActionSheetIOS`) - React-RCTAnimation (from `../node_modules/react-native/Libraries/NativeAnimation`) @@ -939,8 +939,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-video" react-native-view-shot: :path: "../node_modules/react-native-view-shot" - react-native-webview: - :path: "../node_modules/react-native-webview" + react-native-webview-mm: + :path: "../node_modules/@metamask/react-native-webview" React-perflogger: :path: "../node_modules/react-native/ReactCommon/reactperflogger" React-RCTActionSheet: @@ -1028,7 +1028,7 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: Base64: cecfb41a004124895a7bcee567a89bae5a89d49b - boost: 7dcd2de282d72e344012f7d6564d024930a6a440 + boost: 57d2868c099736d80fcd648bf211b4431e51a558 Branch: 4ac024cb3c29b0ef628048694db3c4cfa679beb0 BVLinearGradient: e3aad03778a456d77928f594a649e96995f1c872 CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99 @@ -1104,7 +1104,7 @@ SPEC CHECKSUMS: react-native-splash-screen: 49a7160705f32169d27ab8dff9dda53331592412 react-native-video: c26780b224543c62d5e1b2a7244a5cd1b50e8253 react-native-view-shot: 4475fde003fe8a210053d1f98fb9e06c1d834e1c - react-native-webview: 88293a0f23eca8465c0433c023ec632930e644d0 + react-native-webview-mm: 067bec145f395c6c46c598c8721f557dc3deafcd React-perflogger: 0cc42978a483a47f3696171dac2e7033936fc82d React-RCTActionSheet: ea922b476d24f6d40b8e02ac3228412bd3637468 React-RCTAnimation: 7be2c148398eaa5beac950b2b5ec7102389ec3ad From d02a0481fadb82c13da4b72bd2d8a5660a279ccb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 11 Jun 2024 16:09:44 +0100 Subject: [PATCH 34/41] RNWebView upgrade: Fix e2e tests on CI (#9935) Update detox matchers to grab the correct webview instance to test. Even though e2e tests pass locally, they fail on the CI Using a combination of detox matchers, such as, by.id, by.type and withAncestor. we can select the single webview instance we want to interact with. See also detox documentation: https://wix.github.io/Detox/docs/guide/testing-webviews/#step-1-locating-the-webview --- e2e/pages/Browser/BrowserView.js | 15 ++++++++--- e2e/pages/Browser/TestDApp.js | 26 ++++++++++++++++--- e2e/utils/Matchers.js | 43 +++++++++++++++++++++----------- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/e2e/pages/Browser/BrowserView.js b/e2e/pages/Browser/BrowserView.js index cfeb40bba7f..f7a8357bd1f 100644 --- a/e2e/pages/Browser/BrowserView.js +++ b/e2e/pages/Browser/BrowserView.js @@ -63,13 +63,22 @@ class Browser { ); } get HomePageFavourtiesTab() { - return Matchers.getElementByXPath(BrowserViewSelectorsXPaths.FAVORITE_TAB); + return Matchers.getElementByXPath( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + BrowserViewSelectorsXPaths.FAVORITE_TAB, + ); } get TestDappURLInFavourtiesTab() { return device.getPlatform() === 'ios' - ? Matchers.getElementByXPath(BrowserViewSelectorsXPaths.TEST_DAPP_LINK) - : Matchers.getElementByXPath(BrowserViewSelectorsXPaths.TEST_DAPP_TEXT); + ? Matchers.getElementByXPath( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + BrowserViewSelectorsXPaths.TEST_DAPP_LINK, + ) + : Matchers.getElementByXPath( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + BrowserViewSelectorsXPaths.TEST_DAPP_TEXT, + ); } get multiTabButton() { diff --git a/e2e/pages/Browser/TestDApp.js b/e2e/pages/Browser/TestDApp.js index fe25042909f..aee463497bd 100644 --- a/e2e/pages/Browser/TestDApp.js +++ b/e2e/pages/Browser/TestDApp.js @@ -23,42 +23,59 @@ class TestDApp { } get DappConnectButton() { - return Matchers.getElementByWebID(TestDappSelectorsWebIDs.CONNECT_BUTTON); + return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + TestDappSelectorsWebIDs.CONNECT_BUTTON, + ); } get ApproveButton() { return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.APPROVE_TOKENS_BUTTON_ID, ); } // This taps on the transfer tokens button under the "SEND TOKENS section" get erc20TransferTokensButton() { return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.ERC_20_SEND_TOKENS_TRANSFER_TOKENS_BUTTON_ID, ); } get ethSignButton() { - return Matchers.getElementByWebID(TestDappSelectorsWebIDs.ETH_SIGN); + return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + TestDappSelectorsWebIDs.ETH_SIGN, + ); } get personalSignButton() { - return Matchers.getElementByWebID(TestDappSelectorsWebIDs.PERSONAL_SIGN); + return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + TestDappSelectorsWebIDs.PERSONAL_SIGN, + ); } get signTypedDataButton() { - return Matchers.getElementByWebID(TestDappSelectorsWebIDs.SIGN_TYPE_DATA); + return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, + TestDappSelectorsWebIDs.SIGN_TYPE_DATA, + ); } get signTypedDataV3Button() { return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.SIGN_TYPE_DATA_V3, ); } get signTypedDataV4Button() { return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.SIGN_TYPE_DATA_V4, ); } // This taps on the transfer tokens button under the "SEND TOKENS section" get nftTransferFromTokensButton() { return Matchers.getElementByWebID( + BrowserViewSelectorsIDs.BROWSER_WEBVIEW_ID, TestDappSelectorsWebIDs.NFT_TRANSFER_FROM_BUTTON_ID, ); } @@ -102,6 +119,7 @@ class TestDApp { } async tapButton(elementId) { + await Gestures.scrollToWebViewPort(elementId); await Gestures.tapWebElement(elementId); } diff --git a/e2e/utils/Matchers.js b/e2e/utils/Matchers.js index 722cd7eabbb..decd85e0bbc 100644 --- a/e2e/utils/Matchers.js +++ b/e2e/utils/Matchers.js @@ -73,19 +73,30 @@ class Matchers { return element(by.id(childElement).withAncestor(by.id(parentElement))); } + /** + * Get Native WebView instance by elementId + * + * Because Android Webview might have more that one WebView instance present on the main activity, the correct element + * is select based on its parent element id. + * @param {string} elementId The web ID of the browser webview + * @returns {Detox.WebViewElement} WebView element + */ + static getWebViewByID(elementId) { + return device.getPlatform() === 'ios' + ? web(by.id(elementId)) + : web(by.type('android.webkit.WebView').withAncestor(by.id(elementId))); + } + /** * Get element by web ID. * - * @param {string} innerID - The web ID of the browser webview + * @param {string} webviewID - The web ID of the inner element to locate within the webview + * @param {string} innerID - The web ID of the browser webview * @return {Promise} Resolves to the located element */ - static async getElementByWebID(innerID) { - if ((await device.getPlatform()) === 'android') { - return web.element(by.web.id(innerID)); - } else if ((await device.getPlatform()) === 'ios') { - const myWebView = web(by.id('browser-webview')); - return myWebView.element(by.web.id(innerID)); - } + static async getElementByWebID(webviewID, innerID) { + const myWebView = this.getWebViewByID(webviewID); + return myWebView.element(by.web.id(innerID)); } /** @@ -95,8 +106,9 @@ class Matchers { * @return {Promise} - Resolves to the located element */ - static async getElementByCSS(selector) { - return web.element(by.web.cssSelector(selector)); + static async getElementByCSS(webviewID, selector) { + const myWebView = web(by.id(webviewID)); + return myWebView.element(by.web.cssSelector(selector)).atIndex(0); } /** @@ -105,16 +117,19 @@ class Matchers { * @param {string} xpath - XPath expression to locate the element * @return {Promise} - Resolves to the located element */ - static async getElementByXPath(xpath) { - return web.element(by.web.xpath(xpath)).atIndex(0); + static async getElementByXPath(webviewID, xpath) { + const myWebView = this.getWebViewByID(webviewID); + return myWebView.element(by.web.xpath(xpath)); } /** * Get element by href. + * @param {string} webviewID - The web ID of the browser webview * @param {string} xpath - XPath expression to locate the element * @return {Promise} - Resolves to the located element */ - static async getElementByHref(url) { - return web.element(by.web.href(url)).atIndex(0); + static async getElementByHref(webviewID, url) { + const myWebView = web(by.id(webviewID)); + return myWebView.element(by.web.href(url)).atIndex(0); } /** From 1d680ba050eb54b14ee2399be471a1cd2ef688ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 12 Jun 2024 16:24:09 +0100 Subject: [PATCH 35/41] update PPOMView jest snapshot --- app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap b/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap index 652fae2ffd4..8ed1988a3b7 100644 --- a/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap +++ b/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap @@ -14,16 +14,16 @@ exports[`PPOMView should render correctly deeply 1`] = ` onMessage={[Function]} source={ { - "html": "Webpack App", +g.read=function(A,g,I,B,Q){var C,E,D=8*Q-B-1,w=(1<>1,o=-7,M=I?Q-1:0,G=I?-1:1,N=A[g+M];for(M+=G,C=N&(1<<-o)-1,N>>=-o,o+=D;o>0;C=256*C+A[g+M],M+=G,o-=8);for(E=C&(1<<-o)-1,C>>=-o,o+=B;o>0;E=256*E+A[g+M],M+=G,o-=8);if(0===C)C=1-i;else{if(C===w)return E?NaN:1/0*(N?-1:1);E+=Math.pow(2,B),C-=i}return(N?-1:1)*E*Math.pow(2,C-B)},g.write=function(A,g,I,B,Q,C){var E,D,w,i=8*C-Q-1,o=(1<>1,G=23===Q?Math.pow(2,-24)-Math.pow(2,-77):0,N=B?0:C-1,k=B?1:-1,a=g<0||0===g&&1/g<0?1:0;for(g=Math.abs(g),isNaN(g)||g===1/0?(D=isNaN(g)?1:0,E=o):(E=Math.floor(Math.log(g)/Math.LN2),g*(w=Math.pow(2,-E))<1&&(E--,w*=2),(g+=E+M>=1?G/w:G*Math.pow(2,1-M))*w>=2&&(E++,w/=2),E+M>=o?(D=0,E=o):E+M>=1?(D=(g*w-1)*Math.pow(2,Q),E+=M):(D=g*Math.pow(2,M-1)*Math.pow(2,Q),E=0));Q>=8;A[I+N]=255&D,N+=k,D/=256,Q-=8);for(E=E<0;A[I+N]=255&E,N+=k,E/=256,i-=8);A[I+N-k]|=128*a}},204:(A,g,I)=>{var B=I(150);A.exports=B,A.exports.default=B},150:A=>{"use strict";function g(A){return g="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&"function"==typeof Symbol&&A.constructor===Symbol&&A!==Symbol.prototype?"symbol":typeof A},g(A)}function I(A){return function(A){if(Array.isArray(A))return B(A)}(A)||function(A){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(A))return Array.from(A)}(A)||function(A,g){if(!A)return;if("string"==typeof A)return B(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return B(A,g)}(A)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function B(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0&&B.splice(Q,1)}},emitEvent:function(A,I){A in g&&g[A].forEach((function(A){return A(I)}))}}),M={},G={},N={};function k(A){return function(){for(var g=arguments.length,I=new Array(g),B=0;B0&&void 0!==arguments[0]?arguments[0]:[]).filter((function(A){return!N[A]})).map((function(A){N[A]=k(A)})),function(){if(B){var A=B;B=null,A.forEach((function(A){F(A)})),o.emitEvent("ready")}}(),Object.keys(G)}function y(){h(Object.keys(G)).then(J)}return a(Q,J),{bind:k,define:a,listener:function(A){if(A.reply){var g=i(A);M[g]&&(A.status===E?M[g].reject(A.data):M[g].resolve(A.data))}else if(G[A.command]){var I=G[A.command](A.data);I&&I.then?I.then((function(g){U(A,g,C)})).catch((function(g){U(A,g,E)})):U(A,I,C)}else U(A,"function ".concat(A.command," is not defined"),E);o.emitEvent("receive",A)},ready:y,fn:N,addEventListener:o.addEventListener,removeEventListener:o.removeEventListener,isConnect:function(){return!B}}}((function(A){return M&&o&&o(JSON.stringify(A))})),N=G.bind,k=G.define,a=G.listener,F=G.ready,U=G.fn,h=G.addEventListener,J=G.removeEventListener,y=G.isConnect,K=function(A){var I=void 0;if("object"===g(A))I=A;else if("string"==typeof A)try{I=JSON.parse(A)}catch(A){}I&&(I.command||I.reply)&&a(I)};if(M){var R=window.originalPostMessage;if(R)o=function(){var A;return(A=window).postMessage.apply(A,arguments)},F();else{var Y={get:function(){return R},set:function(A){(R=A)&&(o=function(){var A;return(A=window).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,"originalPostMessage",Y)}var q=window.ReactNativeWebView;if(q)o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},F();else{var c={get:function(){return q},set:function(A){(q=A)&&(o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,"ReactNativeWebView",c)}window.document.addEventListener("message",(function(A){return R&&K(A.data)})),window.addEventListener("message",(function(A){return q&&K(A.data)})),window.document.addEventListener("message",(function(A){return q&&K(A.data)}))}var s={bind:N,define:k,fn:U,addEventListener:h,removeEventListener:J,isConnect:y};A.exports=s}},g={};function I(B){var Q=g[B];if(void 0!==Q)return Q.exports;var C=g[B]={exports:{}};return A[B](C,C.exports,I),C.exports}I.n=A=>{var g=A&&A.__esModule?()=>A.default:()=>A;return I.d(g,{a:g}),g},I.d=(A,g)=>{for(var B in g)I.o(g,B)&&!I.o(A,B)&&Object.defineProperty(A,B,{enumerable:!0,get:g[B]})},I.o=(A,g)=>Object.prototype.hasOwnProperty.call(A,g),(()=>{"use strict";var A=I(204),g=I.n(A);function B(A){return function(A){if(Array.isArray(A))return Q(A)}(A)||function(A){if("undefined"!=typeof Symbol&&null!=A[Symbol.iterator]||null!=A["@@iterator"])return Array.from(A)}(A)||function(A,g){if(!A)return;if("string"==typeof A)return Q(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return Q(A,g)}(A)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Q(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0;--C){var E=this.tryEntries[C],D=E.completion;if("root"===E.tryLoc)return Q("end");if(E.tryLoc<=this.prev){var w=B.call(E,"catchLoc"),i=B.call(E,"finallyLoc");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,"finallyLoc")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),p(I),h}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if("throw"===B.type){var Q=B.arg;p(I)}return Q}}throw Error("illegal catch attempt")},delegateYield:function(g,I,B){return this.delegate={iterator:x(g),resultName:I,nextLoc:B},"next"===this.method&&(this.arg=A),h}},g}function D(A,g,I,B,Q,C,E){try{var D=A[C](E),w=D.value}catch(A){return void I(A)}D.done?g(w):Promise.resolve(w).then(B,Q)}function w(A){return function(){var g=this,I=arguments;return new Promise((function(B,Q){var C=A.apply(g,I);function E(A){D(C,B,Q,E,w,"next",A)}function w(A){D(C,B,Q,E,w,"throw",A)}E(void 0)}))}}function i(A,g){for(var I=0;I>>=0,N.decode(a().subarray(A,A+g))}var U=new Array(128).fill(void 0);U.push(void 0,null,!0,!1);var h=U.length;function J(A){h===U.length&&U.push(U.length+1);var g=h;return h=U[g],U[g]=A,g}function y(A){return U[A]}function K(A){var g=y(A);return function(A){A<132||(U[A]=h,h=A)}(A),g}var R=0,Y="undefined"!=typeof TextEncoder?new TextEncoder("utf-8"):{encode:function(){throw Error("TextEncoder not available")}},q="function"==typeof Y.encodeInto?function(A,g){return Y.encodeInto(A,g)}:function(A,g){var I=Y.encode(A);return g.set(I),{read:A.length,written:I.length}};function c(A,g,I){if(void 0===I){var B=Y.encode(A),Q=g(B.length,1)>>>0;return a().subarray(Q,Q+B.length).set(B),R=B.length,Q}for(var C=A.length,E=g(C,1)>>>0,D=a(),w=0;w127)break;D[E+w]=i}if(w!==C){0!==w&&(A=A.slice(w)),E=I(E,C,C=w+3*A.length,1)>>>0;var o=a().subarray(E+w,E+C);w+=q(A,o).written}return R=w,E}var s=null;function L(){return null!==s&&0!==s.byteLength||(s=new Int32Array(G.memory.buffer)),s}function H(A){var g=M(A);if("number"==g||"boolean"==g||null==A)return"".concat(A);if("string"==g)return'"'.concat(A,'"');if("symbol"==g){var I=A.description;return null==I?"Symbol":"Symbol(".concat(I,")")}if("function"==g){var B=A.name;return"string"==typeof B&&B.length>0?"Function(".concat(B,")"):"Function"}if(Array.isArray(A)){var Q=A.length,C="[";Q>0&&(C+=H(A[0]));for(var E=1;E1))return toString.call(A);if("Object"==(D=w[1]))try{return"Object("+JSON.stringify(A)+")"}catch(A){return"Object"}return A instanceof Error?"".concat(A.name,": ").concat(A.message,"\\n").concat(A.stack):D}function S(A,g,I){G.wasm_bindgen__convert__closures__invoke1_mut(A,g,J(I))}function O(A,g){G._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy(A,g)}var p=null;function T(A,g){for(var I=g(4*A.length,4)>>>0,B=(null!==p&&0!==p.byteLength||(p=new Uint32Array(G.memory.buffer)),p),Q=0;Q>>=0;var I=Object.create(A.prototype);return I.__wbg_ptr=g,I}},{key:"new",value:function(A,g){var I=T(g,G.__wbindgen_malloc),B=R;return K(G.ppom_new(J(A),I,B))}},{key:"version",value:function(){return K(G.ppom_version())}}],(I=[{key:"__destroy_into_raw",value:function(){var A=this.__wbg_ptr;return this.__wbg_ptr=0,A}},{key:"free",value:function(){var A=this.__destroy_into_raw();G.__wbg_ppom_free(A)}},{key:"validateJsonRpc",value:function(A){return K(G.ppom_validateJsonRpc(this.__wbg_ptr,J(A)))}}])&&i(g.prototype,I),B&&i(g,B),Object.defineProperty(g,"prototype",{writable:!1}),A}();function d(A,g){return W.apply(this,arguments)}function W(){return(W=w(E().mark((function A(g,I){var B,Q;return E().wrap((function(A){for(;;)switch(A.prev=A.next){case 0:if(!("function"==typeof Response&&g instanceof Response)){A.next=23;break}if("function"!=typeof WebAssembly.instantiateStreaming){A.next=15;break}return A.prev=2,A.next=5,WebAssembly.instantiateStreaming(g,I);case 5:case 20:return A.abrupt("return",A.sent);case 8:if(A.prev=8,A.t0=A.catch(2),"application/wasm"==g.headers.get("Content-Type")){A.next=14;break}console.warn("\`WebAssembly.instantiateStreaming\` failed because your server does not serve wasm with \`application/wasm\` MIME type. Falling back to \`WebAssembly.instantiate\` which is slower. Original error:\\n",A.t0),A.next=15;break;case 14:throw A.t0;case 15:return A.next=17,g.arrayBuffer();case 17:return B=A.sent,A.next=20,WebAssembly.instantiate(B,I);case 23:return A.next=25,WebAssembly.instantiate(g,I);case 25:if(!((Q=A.sent)instanceof WebAssembly.Instance)){A.next=30;break}return A.abrupt("return",{instance:Q,module:g});case 30:return A.abrupt("return",Q);case 31:case"end":return A.stop()}}),A,null,[[2,8]])})))).apply(this,arguments)}function j(){var A={wbg:{}};return A.wbg.__wbg_buffer_085ec1f694018c4f=function(A){return J(y(A).buffer)},A.wbg.__wbg_call_01734de55d61e11d=function(){return x((function(A,g,I){return J(y(A).call(y(g),y(I)))}),arguments)},A.wbg.__wbg_call_4c92f6aec1e1d6e6=function(){return x((function(A,g,I,B){return J(y(A).call(y(g),y(I),y(B)))}),arguments)},A.wbg.__wbg_from_d7c216d4616bb368=function(A){return J(Array.from(y(A)))},A.wbg.__wbg_get_44be0491f933a435=function(A,g){return J(y(A)[g>>>0])},A.wbg.__wbg_length_72e2208bbc0efc61=function(A){return y(A).length},A.wbg.__wbg_length_d813e535247d427e=function(A){return y(A).length},A.wbg.__wbg_length_fff51ee6522a1a18=function(A){return y(A).length},A.wbg.__wbg_new_43f1b47c28813cbd=function(A,g){try{var I={a:A,b:g},B=new Promise((function(A,g){var B=I.a;I.a=0;try{return function(A,g,I,B){G.wasm_bindgen__convert__closures__invoke2_mut(A,g,J(I),J(B))}(B,I.b,A,g)}finally{I.a=B}}));return J(B)}finally{I.a=I.b=0}},A.wbg.__wbg_new_8125e318e6245eed=function(A){return J(new Uint8Array(y(A)))},A.wbg.__wbg_parse_670c19d4e984792e=function(){return x((function(A,g){return J(JSON.parse(F(A,g)))}),arguments)},A.wbg.__wbg_ppom_new=function(A){return J(t.__wrap(A))},A.wbg.__wbg_resolve_53698b95aaf7fcf8=function(A){return J(Promise.resolve(y(A)))},A.wbg.__wbg_set_5cf90238115182c3=function(A,g,I){y(A).set(y(g),I>>>0)},A.wbg.__wbg_stringify_e25465938f3f611f=function(){return x((function(A){return J(JSON.stringify(y(A)))}),arguments)},A.wbg.__wbg_then_b2267541e2a73865=function(A,g,I){return J(y(A).then(y(g),y(I)))},A.wbg.__wbg_then_f7e06ee3c11698eb=function(A,g){return J(y(A).then(y(g)))},A.wbg.__wbindgen_cb_drop=function(A){var g=K(A).original;if(1==g.cnt--)return g.a=0,!0;return!1},A.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined=function(A,g,I){var B=function(A,g,I,B){var Q={a:A,b:g,cnt:1},C=function(){Q.cnt++;var A=Q.a;Q.a=0;try{for(var g=arguments.length,C=new Array(g),E=0;E=0;--C){var E=this.tryEntries[C],D=E.completion;if("root"===E.tryLoc)return Q("end");if(E.tryLoc<=this.prev){var w=B.call(E,"catchLoc"),i=B.call(E,"finallyLoc");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,"finallyLoc")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),S(I),F}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if("throw"===B.type){var Q=B.arg;S(I)}return Q}}throw Error("illegal catch attempt")},delegateYield:function(g,I,B){return this.delegate={iterator:p(g),resultName:I,nextLoc:B},"next"===this.method&&(this.arg=A),F}},g}function m(A,g){return function(A){if(Array.isArray(A))return A}(A)||function(A,g){var I=null==A?null:"undefined"!=typeof Symbol&&A[Symbol.iterator]||A["@@iterator"];if(null!=I){var B,Q,C,E,D=[],w=!0,i=!1;try{if(C=(I=I.call(A)).next,0===g){if(Object(I)!==I)return;w=!1}else for(;!(w=(B=C.call(I)).done)&&(D.push(B.value),D.length!==g);w=!0);}catch(A){i=!0,Q=A}finally{try{if(!w&&null!=I.return&&(E=I.return(),Object(E)!==E))return}finally{if(i)throw Q}}return D}}(A,g)||function(A,g){if(!A)return;if("string"==typeof A)return e(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return e(A,g)}(A,g)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function e(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I", } } /> From 05e7e80573e91684022157dae6997a86a310edd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Wed, 19 Jun 2024 15:27:08 +0100 Subject: [PATCH 36/41] bring quotes snapshot from main --- .../Quotes/__snapshots__/Quotes.test.tsx.snap | 2048 +++-------------- 1 file changed, 258 insertions(+), 1790 deletions(-) diff --git a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap index 0d68b42a820..8efadd056c1 100644 --- a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap +++ b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap @@ -24,7 +24,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "borderColor": "#BBC0C5", + "borderColor": "#bbc0c5", "borderRadius": 8, "borderWidth": 1.5, "padding": 16, @@ -60,7 +60,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "color": "#24272A", + "color": "#141618", "fontFamily": "EuclidCircularB-Regular", "fontSize": 30, "fontWeight": "400", @@ -91,7 +91,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` undefined, [ { - "color": "#24272A", + "color": "#141618", "fontSize": 15, }, undefined, @@ -103,7 +103,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "backgroundColor": "#F2F4F6", + "backgroundColor": "#f2f4f6", "borderRadius": 30, "padding": 14, }, @@ -143,7 +143,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "backgroundColor": "#F2F4F6", + "backgroundColor": "#f2f4f6", "borderRadius": 30, "padding": 14, }, @@ -193,7 +193,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "backgroundColor": "#F2F4F6", + "backgroundColor": "#f2f4f6", "borderRadius": 30, "padding": 14, }, @@ -232,7 +232,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "backgroundColor": "#F2F4F6", + "backgroundColor": "#f2f4f6", "borderRadius": 30, "padding": 14, }, @@ -284,7 +284,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "borderColor": "#BBC0C5", + "borderColor": "#bbc0c5", "borderRadius": 8, "borderWidth": 1.5, "padding": 16, @@ -320,7 +320,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "color": "#24272A", + "color": "#141618", "fontFamily": "EuclidCircularB-Regular", "fontSize": 30, "fontWeight": "400", @@ -351,7 +351,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` undefined, [ { - "color": "#24272A", + "color": "#141618", "fontSize": 15, }, undefined, @@ -363,7 +363,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "backgroundColor": "#F2F4F6", + "backgroundColor": "#f2f4f6", "borderRadius": 30, "padding": 14, }, @@ -403,7 +403,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "backgroundColor": "#F2F4F6", + "backgroundColor": "#f2f4f6", "borderRadius": 30, "padding": 14, }, @@ -451,7 +451,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "borderColor": "#BBC0C5", + "borderColor": "#bbc0c5", "borderRadius": 8, "borderWidth": 1.5, "padding": 16, @@ -487,7 +487,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "color": "#24272A", + "color": "#141618", "fontFamily": "EuclidCircularB-Regular", "fontSize": 30, "fontWeight": "400", @@ -518,7 +518,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` undefined, [ { - "color": "#24272A", + "color": "#141618", "fontSize": 15, }, undefined, @@ -530,7 +530,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "backgroundColor": "#F2F4F6", + "backgroundColor": "#f2f4f6", "borderRadius": 30, "padding": 14, }, @@ -570,7 +570,7 @@ exports[`LoadingQuotes component renders correctly 1`] = ` style={ [ { - "backgroundColor": "#F2F4F6", + "backgroundColor": "#f2f4f6", "borderRadius": 30, "padding": 14, }, @@ -655,7 +655,7 @@ exports[`Quotes renders animation on first fetching 1`] = ` collapsable={false} style={ { - "backgroundColor": "#FFFFFF", + "backgroundColor": "#ffffff", "borderBottomColor": "rgb(216, 216, 216)", "elevation": 0, "flex": 1, @@ -731,7 +731,7 @@ exports[`Quotes renders animation on first fetching 1`] = ` - - - - --- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ", - } - } style={ [ { - "backgroundColor": "#FFFFFF", "flex": 1, + "overflow": "hidden", }, undefined, ] } - /> + > + + @@ -2931,7 +1399,7 @@ exports[`Quotes renders correctly after animation with quotes 1`] = ` collapsable={false} style={ { - "backgroundColor": "#FFFFFF", + "backgroundColor": "#ffffff", "borderBottomColor": "rgb(216, 216, 216)", "elevation": 0, "flex": 1, @@ -3007,7 +1475,7 @@ exports[`Quotes renders correctly after animation with quotes 1`] = ` Date: Wed, 19 Jun 2024 15:36:11 +0100 Subject: [PATCH 37/41] update jest Quotes snapshot --- .../Quotes/__snapshots__/Quotes.test.tsx.snap | 1622 ++++++++++++++++- 1 file changed, 1577 insertions(+), 45 deletions(-) diff --git a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap index 8efadd056c1..442f0245b8a 100644 --- a/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap +++ b/app/components/UI/Ramp/Views/Quotes/__snapshots__/Quotes.test.tsx.snap @@ -1273,59 +1273,1591 @@ exports[`Quotes renders animation on first fetching 1`] = ` } > + + + + --- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ", + } + } style={ [ { + "backgroundColor": "#ffffff", "flex": 1, - "overflow": "hidden", }, undefined, ] } - > - - + /> From 3e42146bb985f5d7ad2ad35fc87f9e7f7e2efa47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 25 Jun 2024 15:24:12 +0100 Subject: [PATCH 38/41] update PPOMView jest snapshot --- app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap b/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap index 8ed1988a3b7..d3de6215cac 100644 --- a/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap +++ b/app/lib/ppom/__snapshots__/PPOMView.test.tsx.snap @@ -21,9 +21,9 @@ exports[`PPOMView should render correctly deeply 1`] = ` * @author Feross Aboukhadijeh * @license MIT */ -const B=I(742),Q=I(645),C="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;g.lW=w,g.h2=50;const E=2147483647;function D(A){if(A>E)throw new RangeError('The value "'+A+'" is invalid for option "size"');const g=new Uint8Array(A);return Object.setPrototypeOf(g,w.prototype),g}function w(A,g,I){if("number"==typeof A){if("string"==typeof g)throw new TypeError('The "string" argument must be of type string. Received type number');return M(A)}return i(A,g,I)}function i(A,g,I){if("string"==typeof A)return function(A,g){"string"==typeof g&&""!==g||(g="utf8");if(!w.isEncoding(g))throw new TypeError("Unknown encoding: "+g);const I=0|a(A,g);let B=D(I);const Q=B.write(A,g);Q!==I&&(B=B.slice(0,Q));return B}(A,g);if(ArrayBuffer.isView(A))return function(A){if(u(A,Uint8Array)){const g=new Uint8Array(A);return N(g.buffer,g.byteOffset,g.byteLength)}return G(A)}(A);if(null==A)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof A);if(u(A,ArrayBuffer)||A&&u(A.buffer,ArrayBuffer))return N(A,g,I);if("undefined"!=typeof SharedArrayBuffer&&(u(A,SharedArrayBuffer)||A&&u(A.buffer,SharedArrayBuffer)))return N(A,g,I);if("number"==typeof A)throw new TypeError('The "value" argument must not be of type number. Received type number');const B=A.valueOf&&A.valueOf();if(null!=B&&B!==A)return w.from(B,g,I);const Q=function(A){if(w.isBuffer(A)){const g=0|k(A.length),I=D(g);return 0===I.length||A.copy(I,0,0,g),I}if(void 0!==A.length)return"number"!=typeof A.length||v(A.length)?D(0):G(A);if("Buffer"===A.type&&Array.isArray(A.data))return G(A.data)}(A);if(Q)return Q;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof A[Symbol.toPrimitive])return w.from(A[Symbol.toPrimitive]("string"),g,I);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof A)}function o(A){if("number"!=typeof A)throw new TypeError('"size" argument must be of type number');if(A<0)throw new RangeError('The value "'+A+'" is invalid for option "size"')}function M(A){return o(A),D(A<0?0:0|k(A))}function G(A){const g=A.length<0?0:0|k(A.length),I=D(g);for(let B=0;B=E)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+E.toString(16)+" bytes");return 0|A}function a(A,g){if(w.isBuffer(A))return A.length;if(ArrayBuffer.isView(A)||u(A,ArrayBuffer))return A.byteLength;if("string"!=typeof A)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof A);const I=A.length,B=arguments.length>2&&!0===arguments[2];if(!B&&0===I)return 0;let Q=!1;for(;;)switch(g){case"ascii":case"latin1":case"binary":return I;case"utf8":case"utf-8":return e(A).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*I;case"hex":return I>>>1;case"base64":return V(A).length;default:if(Q)return B?-1:e(A).length;g=(""+g).toLowerCase(),Q=!0}}function F(A,g,I){let B=!1;if((void 0===g||g<0)&&(g=0),g>this.length)return"";if((void 0===I||I>this.length)&&(I=this.length),I<=0)return"";if((I>>>=0)<=(g>>>=0))return"";for(A||(A="utf8");;)switch(A){case"hex":return O(this,g,I);case"utf8":case"utf-8":return s(this,g,I);case"ascii":return H(this,g,I);case"latin1":case"binary":return S(this,g,I);case"base64":return c(this,g,I);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return p(this,g,I);default:if(B)throw new TypeError("Unknown encoding: "+A);A=(A+"").toLowerCase(),B=!0}}function U(A,g,I){const B=A[g];A[g]=A[I],A[I]=B}function h(A,g,I,B,Q){if(0===A.length)return-1;if("string"==typeof I?(B=I,I=0):I>2147483647?I=2147483647:I<-2147483648&&(I=-2147483648),v(I=+I)&&(I=Q?0:A.length-1),I<0&&(I=A.length+I),I>=A.length){if(Q)return-1;I=A.length-1}else if(I<0){if(!Q)return-1;I=0}if("string"==typeof g&&(g=w.from(g,B)),w.isBuffer(g))return 0===g.length?-1:J(A,g,I,B,Q);if("number"==typeof g)return g&=255,"function"==typeof Uint8Array.prototype.indexOf?Q?Uint8Array.prototype.indexOf.call(A,g,I):Uint8Array.prototype.lastIndexOf.call(A,g,I):J(A,[g],I,B,Q);throw new TypeError("val must be string, number or Buffer")}function J(A,g,I,B,Q){let C,E=1,D=A.length,w=g.length;if(void 0!==B&&("ucs2"===(B=String(B).toLowerCase())||"ucs-2"===B||"utf16le"===B||"utf-16le"===B)){if(A.length<2||g.length<2)return-1;E=2,D/=2,w/=2,I/=2}function i(A,g){return 1===E?A[g]:A.readUInt16BE(g*E)}if(Q){let B=-1;for(C=I;CD&&(I=D-w),C=I;C>=0;C--){let I=!0;for(let B=0;BQ&&(B=Q):B=Q;const C=g.length;let E;for(B>C/2&&(B=C/2),E=0;E>8,Q=I%256,C.push(Q),C.push(B);return C}(g,A.length-I),A,I,B)}function c(A,g,I){return 0===g&&I===A.length?B.fromByteArray(A):B.fromByteArray(A.slice(g,I))}function s(A,g,I){I=Math.min(A.length,I);const B=[];let Q=g;for(;Q239?4:g>223?3:g>191?2:1;if(Q+E<=I){let I,B,D,w;switch(E){case 1:g<128&&(C=g);break;case 2:I=A[Q+1],128==(192&I)&&(w=(31&g)<<6|63&I,w>127&&(C=w));break;case 3:I=A[Q+1],B=A[Q+2],128==(192&I)&&128==(192&B)&&(w=(15&g)<<12|(63&I)<<6|63&B,w>2047&&(w<55296||w>57343)&&(C=w));break;case 4:I=A[Q+1],B=A[Q+2],D=A[Q+3],128==(192&I)&&128==(192&B)&&128==(192&D)&&(w=(15&g)<<18|(63&I)<<12|(63&B)<<6|63&D,w>65535&&w<1114112&&(C=w))}}null===C?(C=65533,E=1):C>65535&&(C-=65536,B.push(C>>>10&1023|55296),C=56320|1023&C),B.push(C),Q+=E}return function(A){const g=A.length;if(g<=L)return String.fromCharCode.apply(String,A);let I="",B=0;for(;BB.length?(w.isBuffer(g)||(g=w.from(g)),g.copy(B,Q)):Uint8Array.prototype.set.call(B,g,Q);else{if(!w.isBuffer(g))throw new TypeError('"list" argument must be an Array of Buffers');g.copy(B,Q)}Q+=g.length}return B},w.byteLength=a,w.prototype._isBuffer=!0,w.prototype.swap16=function(){const A=this.length;if(A%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let g=0;gI&&(A+=" ... "),""},C&&(w.prototype[C]=w.prototype.inspect),w.prototype.compare=function(A,g,I,B,Q){if(u(A,Uint8Array)&&(A=w.from(A,A.offset,A.byteLength)),!w.isBuffer(A))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof A);if(void 0===g&&(g=0),void 0===I&&(I=A?A.length:0),void 0===B&&(B=0),void 0===Q&&(Q=this.length),g<0||I>A.length||B<0||Q>this.length)throw new RangeError("out of range index");if(B>=Q&&g>=I)return 0;if(B>=Q)return-1;if(g>=I)return 1;if(this===A)return 0;let C=(Q>>>=0)-(B>>>=0),E=(I>>>=0)-(g>>>=0);const D=Math.min(C,E),i=this.slice(B,Q),o=A.slice(g,I);for(let A=0;A>>=0,isFinite(I)?(I>>>=0,void 0===B&&(B="utf8")):(B=I,I=void 0)}const Q=this.length-g;if((void 0===I||I>Q)&&(I=Q),A.length>0&&(I<0||g<0)||g>this.length)throw new RangeError("Attempt to write outside buffer bounds");B||(B="utf8");let C=!1;for(;;)switch(B){case"hex":return y(this,A,g,I);case"utf8":case"utf-8":return K(this,A,g,I);case"ascii":case"latin1":case"binary":return R(this,A,g,I);case"base64":return Y(this,A,g,I);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return q(this,A,g,I);default:if(C)throw new TypeError("Unknown encoding: "+B);B=(""+B).toLowerCase(),C=!0}},w.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};const L=4096;function H(A,g,I){let B="";I=Math.min(A.length,I);for(let Q=g;QB)&&(I=B);let Q="";for(let B=g;BI)throw new RangeError("Trying to access beyond buffer length")}function x(A,g,I,B,Q,C){if(!w.isBuffer(A))throw new TypeError('"buffer" argument must be a Buffer instance');if(g>Q||gA.length)throw new RangeError("Index out of range")}function t(A,g,I,B,Q){Z(g,B,Q,A,I,7);let C=Number(g&BigInt(4294967295));A[I++]=C,C>>=8,A[I++]=C,C>>=8,A[I++]=C,C>>=8,A[I++]=C;let E=Number(g>>BigInt(32)&BigInt(4294967295));return A[I++]=E,E>>=8,A[I++]=E,E>>=8,A[I++]=E,E>>=8,A[I++]=E,I}function d(A,g,I,B,Q){Z(g,B,Q,A,I,7);let C=Number(g&BigInt(4294967295));A[I+7]=C,C>>=8,A[I+6]=C,C>>=8,A[I+5]=C,C>>=8,A[I+4]=C;let E=Number(g>>BigInt(32)&BigInt(4294967295));return A[I+3]=E,E>>=8,A[I+2]=E,E>>=8,A[I+1]=E,E>>=8,A[I]=E,I+8}function W(A,g,I,B,Q,C){if(I+B>A.length)throw new RangeError("Index out of range");if(I<0)throw new RangeError("Index out of range")}function j(A,g,I,B,C){return g=+g,I>>>=0,C||W(A,0,I,4),Q.write(A,g,I,B,23,4),I+4}function f(A,g,I,B,C){return g=+g,I>>>=0,C||W(A,0,I,8),Q.write(A,g,I,B,52,8),I+8}w.prototype.slice=function(A,g){const I=this.length;(A=~~A)<0?(A+=I)<0&&(A=0):A>I&&(A=I),(g=void 0===g?I:~~g)<0?(g+=I)<0&&(g=0):g>I&&(g=I),g>>=0,g>>>=0,I||T(A,g,this.length);let B=this[A],Q=1,C=0;for(;++C>>=0,g>>>=0,I||T(A,g,this.length);let B=this[A+--g],Q=1;for(;g>0&&(Q*=256);)B+=this[A+--g]*Q;return B},w.prototype.readUint8=w.prototype.readUInt8=function(A,g){return A>>>=0,g||T(A,1,this.length),this[A]},w.prototype.readUint16LE=w.prototype.readUInt16LE=function(A,g){return A>>>=0,g||T(A,2,this.length),this[A]|this[A+1]<<8},w.prototype.readUint16BE=w.prototype.readUInt16BE=function(A,g){return A>>>=0,g||T(A,2,this.length),this[A]<<8|this[A+1]},w.prototype.readUint32LE=w.prototype.readUInt32LE=function(A,g){return A>>>=0,g||T(A,4,this.length),(this[A]|this[A+1]<<8|this[A+2]<<16)+16777216*this[A+3]},w.prototype.readUint32BE=w.prototype.readUInt32BE=function(A,g){return A>>>=0,g||T(A,4,this.length),16777216*this[A]+(this[A+1]<<16|this[A+2]<<8|this[A+3])},w.prototype.readBigUInt64LE=_((function(A){n(A>>>=0,"offset");const g=this[A],I=this[A+7];void 0!==g&&void 0!==I||b(A,this.length-8);const B=g+256*this[++A]+65536*this[++A]+this[++A]*2**24,Q=this[++A]+256*this[++A]+65536*this[++A]+I*2**24;return BigInt(B)+(BigInt(Q)<>>=0,"offset");const g=this[A],I=this[A+7];void 0!==g&&void 0!==I||b(A,this.length-8);const B=g*2**24+65536*this[++A]+256*this[++A]+this[++A],Q=this[++A]*2**24+65536*this[++A]+256*this[++A]+I;return(BigInt(B)<>>=0,g>>>=0,I||T(A,g,this.length);let B=this[A],Q=1,C=0;for(;++C=Q&&(B-=Math.pow(2,8*g)),B},w.prototype.readIntBE=function(A,g,I){A>>>=0,g>>>=0,I||T(A,g,this.length);let B=g,Q=1,C=this[A+--B];for(;B>0&&(Q*=256);)C+=this[A+--B]*Q;return Q*=128,C>=Q&&(C-=Math.pow(2,8*g)),C},w.prototype.readInt8=function(A,g){return A>>>=0,g||T(A,1,this.length),128&this[A]?-1*(255-this[A]+1):this[A]},w.prototype.readInt16LE=function(A,g){A>>>=0,g||T(A,2,this.length);const I=this[A]|this[A+1]<<8;return 32768&I?4294901760|I:I},w.prototype.readInt16BE=function(A,g){A>>>=0,g||T(A,2,this.length);const I=this[A+1]|this[A]<<8;return 32768&I?4294901760|I:I},w.prototype.readInt32LE=function(A,g){return A>>>=0,g||T(A,4,this.length),this[A]|this[A+1]<<8|this[A+2]<<16|this[A+3]<<24},w.prototype.readInt32BE=function(A,g){return A>>>=0,g||T(A,4,this.length),this[A]<<24|this[A+1]<<16|this[A+2]<<8|this[A+3]},w.prototype.readBigInt64LE=_((function(A){n(A>>>=0,"offset");const g=this[A],I=this[A+7];void 0!==g&&void 0!==I||b(A,this.length-8);const B=this[A+4]+256*this[A+5]+65536*this[A+6]+(I<<24);return(BigInt(B)<>>=0,"offset");const g=this[A],I=this[A+7];void 0!==g&&void 0!==I||b(A,this.length-8);const B=(g<<24)+65536*this[++A]+256*this[++A]+this[++A];return(BigInt(B)<>>=0,g||T(A,4,this.length),Q.read(this,A,!0,23,4)},w.prototype.readFloatBE=function(A,g){return A>>>=0,g||T(A,4,this.length),Q.read(this,A,!1,23,4)},w.prototype.readDoubleLE=function(A,g){return A>>>=0,g||T(A,8,this.length),Q.read(this,A,!0,52,8)},w.prototype.readDoubleBE=function(A,g){return A>>>=0,g||T(A,8,this.length),Q.read(this,A,!1,52,8)},w.prototype.writeUintLE=w.prototype.writeUIntLE=function(A,g,I,B){if(A=+A,g>>>=0,I>>>=0,!B){x(this,A,g,I,Math.pow(2,8*I)-1,0)}let Q=1,C=0;for(this[g]=255&A;++C>>=0,I>>>=0,!B){x(this,A,g,I,Math.pow(2,8*I)-1,0)}let Q=I-1,C=1;for(this[g+Q]=255&A;--Q>=0&&(C*=256);)this[g+Q]=A/C&255;return g+I},w.prototype.writeUint8=w.prototype.writeUInt8=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,1,255,0),this[g]=255&A,g+1},w.prototype.writeUint16LE=w.prototype.writeUInt16LE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,2,65535,0),this[g]=255&A,this[g+1]=A>>>8,g+2},w.prototype.writeUint16BE=w.prototype.writeUInt16BE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,2,65535,0),this[g]=A>>>8,this[g+1]=255&A,g+2},w.prototype.writeUint32LE=w.prototype.writeUInt32LE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,4,4294967295,0),this[g+3]=A>>>24,this[g+2]=A>>>16,this[g+1]=A>>>8,this[g]=255&A,g+4},w.prototype.writeUint32BE=w.prototype.writeUInt32BE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,4,4294967295,0),this[g]=A>>>24,this[g+1]=A>>>16,this[g+2]=A>>>8,this[g+3]=255&A,g+4},w.prototype.writeBigUInt64LE=_((function(A,g=0){return t(this,A,g,BigInt(0),BigInt("0xffffffffffffffff"))})),w.prototype.writeBigUInt64BE=_((function(A,g=0){return d(this,A,g,BigInt(0),BigInt("0xffffffffffffffff"))})),w.prototype.writeIntLE=function(A,g,I,B){if(A=+A,g>>>=0,!B){const B=Math.pow(2,8*I-1);x(this,A,g,I,B-1,-B)}let Q=0,C=1,E=0;for(this[g]=255&A;++Q>0)-E&255;return g+I},w.prototype.writeIntBE=function(A,g,I,B){if(A=+A,g>>>=0,!B){const B=Math.pow(2,8*I-1);x(this,A,g,I,B-1,-B)}let Q=I-1,C=1,E=0;for(this[g+Q]=255&A;--Q>=0&&(C*=256);)A<0&&0===E&&0!==this[g+Q+1]&&(E=1),this[g+Q]=(A/C>>0)-E&255;return g+I},w.prototype.writeInt8=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,1,127,-128),A<0&&(A=255+A+1),this[g]=255&A,g+1},w.prototype.writeInt16LE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,2,32767,-32768),this[g]=255&A,this[g+1]=A>>>8,g+2},w.prototype.writeInt16BE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,2,32767,-32768),this[g]=A>>>8,this[g+1]=255&A,g+2},w.prototype.writeInt32LE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,4,2147483647,-2147483648),this[g]=255&A,this[g+1]=A>>>8,this[g+2]=A>>>16,this[g+3]=A>>>24,g+4},w.prototype.writeInt32BE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,4,2147483647,-2147483648),A<0&&(A=4294967295+A+1),this[g]=A>>>24,this[g+1]=A>>>16,this[g+2]=A>>>8,this[g+3]=255&A,g+4},w.prototype.writeBigInt64LE=_((function(A,g=0){return t(this,A,g,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),w.prototype.writeBigInt64BE=_((function(A,g=0){return d(this,A,g,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),w.prototype.writeFloatLE=function(A,g,I){return j(this,A,g,!0,I)},w.prototype.writeFloatBE=function(A,g,I){return j(this,A,g,!1,I)},w.prototype.writeDoubleLE=function(A,g,I){return f(this,A,g,!0,I)},w.prototype.writeDoubleBE=function(A,g,I){return f(this,A,g,!1,I)},w.prototype.copy=function(A,g,I,B){if(!w.isBuffer(A))throw new TypeError("argument should be a Buffer");if(I||(I=0),B||0===B||(B=this.length),g>=A.length&&(g=A.length),g||(g=0),B>0&&B=this.length)throw new RangeError("Index out of range");if(B<0)throw new RangeError("sourceEnd out of bounds");B>this.length&&(B=this.length),A.length-g>>=0,I=void 0===I?this.length:I>>>0,A||(A=0),"number"==typeof A)for(Q=g;Q=B+4;I-=3)g=\`_\${A.slice(I-3,I)}\${g}\`;return\`\${A.slice(0,I)}\${g}\`}function Z(A,g,I,B,Q,C){if(A>I||A3?0===g||g===BigInt(0)?\`>= 0\${B} and < 2\${B} ** \${8*(C+1)}\${B}\`:\`>= -(2\${B} ** \${8*(C+1)-1}\${B}) and < 2 ** \${8*(C+1)-1}\${B}\`:\`>= \${g}\${B} and <= \${I}\${B}\`,new z.ERR_OUT_OF_RANGE("value",Q,A)}!function(A,g,I){n(g,"offset"),void 0!==A[g]&&void 0!==A[g+I]||b(g,A.length-(I+1))}(B,Q,C)}function n(A,g){if("number"!=typeof A)throw new z.ERR_INVALID_ARG_TYPE(g,"number",A)}function b(A,g,I){if(Math.floor(A)!==A)throw n(A,I),new z.ERR_OUT_OF_RANGE(I||"offset","an integer",A);if(g<0)throw new z.ERR_BUFFER_OUT_OF_BOUNDS;throw new z.ERR_OUT_OF_RANGE(I||"offset",\`>= \${I?1:0} and <= \${g}\`,A)}r("ERR_BUFFER_OUT_OF_BOUNDS",(function(A){return A?\`\${A} is outside of buffer bounds\`:"Attempt to access memory outside buffer bounds"}),RangeError),r("ERR_INVALID_ARG_TYPE",(function(A,g){return\`The "\${A}" argument must be of type number. Received type \${typeof g}\`}),TypeError),r("ERR_OUT_OF_RANGE",(function(A,g,I){let B=\`The value of "\${A}" is out of range.\`,Q=I;return Number.isInteger(I)&&Math.abs(I)>2**32?Q=P(String(I)):"bigint"==typeof I&&(Q=String(I),(I>BigInt(2)**BigInt(32)||I<-(BigInt(2)**BigInt(32)))&&(Q=P(Q)),Q+="n"),B+=\` It must be \${g}. Received \${Q}\`,B}),RangeError);const m=/[^+/0-9A-Za-z-_]/g;function e(A,g){let I;g=g||1/0;const B=A.length;let Q=null;const C=[];for(let E=0;E55295&&I<57344){if(!Q){if(I>56319){(g-=3)>-1&&C.push(239,191,189);continue}if(E+1===B){(g-=3)>-1&&C.push(239,191,189);continue}Q=I;continue}if(I<56320){(g-=3)>-1&&C.push(239,191,189),Q=I;continue}I=65536+(Q-55296<<10|I-56320)}else Q&&(g-=3)>-1&&C.push(239,191,189);if(Q=null,I<128){if((g-=1)<0)break;C.push(I)}else if(I<2048){if((g-=2)<0)break;C.push(I>>6|192,63&I|128)}else if(I<65536){if((g-=3)<0)break;C.push(I>>12|224,I>>6&63|128,63&I|128)}else{if(!(I<1114112))throw new Error("Invalid code point");if((g-=4)<0)break;C.push(I>>18|240,I>>12&63|128,I>>6&63|128,63&I|128)}}return C}function V(A){return B.toByteArray(function(A){if((A=(A=A.split("=")[0]).trim().replace(m,"")).length<2)return"";for(;A.length%4!=0;)A+="=";return A}(A))}function l(A,g,I,B){let Q;for(Q=0;Q=g.length||Q>=A.length);++Q)g[Q+I]=A[Q];return Q}function u(A,g){return A instanceof g||null!=A&&null!=A.constructor&&null!=A.constructor.name&&A.constructor.name===g.name}function v(A){return A!=A}const X=function(){const A="0123456789abcdef",g=new Array(256);for(let I=0;I<16;++I){const B=16*I;for(let Q=0;Q<16;++Q)g[B+Q]=A[I]+A[Q]}return g}();function _(A){return"undefined"==typeof BigInt?$:A}function $(){throw new Error("BigInt not supported")}},645:(A,g)=>{ +const B=I(742),Q=I(645),C="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;g.lW=w,g.h2=50;const E=2147483647;function D(A){if(A>E)throw new RangeError('The value "'+A+'" is invalid for option "size"');const g=new Uint8Array(A);return Object.setPrototypeOf(g,w.prototype),g}function w(A,g,I){if("number"==typeof A){if("string"==typeof g)throw new TypeError('The "string" argument must be of type string. Received type number');return M(A)}return i(A,g,I)}function i(A,g,I){if("string"==typeof A)return function(A,g){"string"==typeof g&&""!==g||(g="utf8");if(!w.isEncoding(g))throw new TypeError("Unknown encoding: "+g);const I=0|a(A,g);let B=D(I);const Q=B.write(A,g);Q!==I&&(B=B.slice(0,Q));return B}(A,g);if(ArrayBuffer.isView(A))return function(A){if(u(A,Uint8Array)){const g=new Uint8Array(A);return N(g.buffer,g.byteOffset,g.byteLength)}return G(A)}(A);if(null==A)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof A);if(u(A,ArrayBuffer)||A&&u(A.buffer,ArrayBuffer))return N(A,g,I);if("undefined"!=typeof SharedArrayBuffer&&(u(A,SharedArrayBuffer)||A&&u(A.buffer,SharedArrayBuffer)))return N(A,g,I);if("number"==typeof A)throw new TypeError('The "value" argument must not be of type number. Received type number');const B=A.valueOf&&A.valueOf();if(null!=B&&B!==A)return w.from(B,g,I);const Q=function(A){if(w.isBuffer(A)){const g=0|k(A.length),I=D(g);return 0===I.length||A.copy(I,0,0,g),I}if(void 0!==A.length)return"number"!=typeof A.length||v(A.length)?D(0):G(A);if("Buffer"===A.type&&Array.isArray(A.data))return G(A.data)}(A);if(Q)return Q;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof A[Symbol.toPrimitive])return w.from(A[Symbol.toPrimitive]("string"),g,I);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof A)}function o(A){if("number"!=typeof A)throw new TypeError('"size" argument must be of type number');if(A<0)throw new RangeError('The value "'+A+'" is invalid for option "size"')}function M(A){return o(A),D(A<0?0:0|k(A))}function G(A){const g=A.length<0?0:0|k(A.length),I=D(g);for(let B=0;B=E)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+E.toString(16)+" bytes");return 0|A}function a(A,g){if(w.isBuffer(A))return A.length;if(ArrayBuffer.isView(A)||u(A,ArrayBuffer))return A.byteLength;if("string"!=typeof A)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof A);const I=A.length,B=arguments.length>2&&!0===arguments[2];if(!B&&0===I)return 0;let Q=!1;for(;;)switch(g){case"ascii":case"latin1":case"binary":return I;case"utf8":case"utf-8":return V(A).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*I;case"hex":return I>>>1;case"base64":return e(A).length;default:if(Q)return B?-1:V(A).length;g=(""+g).toLowerCase(),Q=!0}}function F(A,g,I){let B=!1;if((void 0===g||g<0)&&(g=0),g>this.length)return"";if((void 0===I||I>this.length)&&(I=this.length),I<=0)return"";if((I>>>=0)<=(g>>>=0))return"";for(A||(A="utf8");;)switch(A){case"hex":return O(this,g,I);case"utf8":case"utf-8":return s(this,g,I);case"ascii":return H(this,g,I);case"latin1":case"binary":return S(this,g,I);case"base64":return c(this,g,I);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return p(this,g,I);default:if(B)throw new TypeError("Unknown encoding: "+A);A=(A+"").toLowerCase(),B=!0}}function U(A,g,I){const B=A[g];A[g]=A[I],A[I]=B}function J(A,g,I,B,Q){if(0===A.length)return-1;if("string"==typeof I?(B=I,I=0):I>2147483647?I=2147483647:I<-2147483648&&(I=-2147483648),v(I=+I)&&(I=Q?0:A.length-1),I<0&&(I=A.length+I),I>=A.length){if(Q)return-1;I=A.length-1}else if(I<0){if(!Q)return-1;I=0}if("string"==typeof g&&(g=w.from(g,B)),w.isBuffer(g))return 0===g.length?-1:h(A,g,I,B,Q);if("number"==typeof g)return g&=255,"function"==typeof Uint8Array.prototype.indexOf?Q?Uint8Array.prototype.indexOf.call(A,g,I):Uint8Array.prototype.lastIndexOf.call(A,g,I):h(A,[g],I,B,Q);throw new TypeError("val must be string, number or Buffer")}function h(A,g,I,B,Q){let C,E=1,D=A.length,w=g.length;if(void 0!==B&&("ucs2"===(B=String(B).toLowerCase())||"ucs-2"===B||"utf16le"===B||"utf-16le"===B)){if(A.length<2||g.length<2)return-1;E=2,D/=2,w/=2,I/=2}function i(A,g){return 1===E?A[g]:A.readUInt16BE(g*E)}if(Q){let B=-1;for(C=I;CD&&(I=D-w),C=I;C>=0;C--){let I=!0;for(let B=0;BQ&&(B=Q):B=Q;const C=g.length;let E;for(B>C/2&&(B=C/2),E=0;E>8,Q=I%256,C.push(Q),C.push(B);return C}(g,A.length-I),A,I,B)}function c(A,g,I){return 0===g&&I===A.length?B.fromByteArray(A):B.fromByteArray(A.slice(g,I))}function s(A,g,I){I=Math.min(A.length,I);const B=[];let Q=g;for(;Q239?4:g>223?3:g>191?2:1;if(Q+E<=I){let I,B,D,w;switch(E){case 1:g<128&&(C=g);break;case 2:I=A[Q+1],128==(192&I)&&(w=(31&g)<<6|63&I,w>127&&(C=w));break;case 3:I=A[Q+1],B=A[Q+2],128==(192&I)&&128==(192&B)&&(w=(15&g)<<12|(63&I)<<6|63&B,w>2047&&(w<55296||w>57343)&&(C=w));break;case 4:I=A[Q+1],B=A[Q+2],D=A[Q+3],128==(192&I)&&128==(192&B)&&128==(192&D)&&(w=(15&g)<<18|(63&I)<<12|(63&B)<<6|63&D,w>65535&&w<1114112&&(C=w))}}null===C?(C=65533,E=1):C>65535&&(C-=65536,B.push(C>>>10&1023|55296),C=56320|1023&C),B.push(C),Q+=E}return function(A){const g=A.length;if(g<=L)return String.fromCharCode.apply(String,A);let I="",B=0;for(;BB.length?(w.isBuffer(g)||(g=w.from(g)),g.copy(B,Q)):Uint8Array.prototype.set.call(B,g,Q);else{if(!w.isBuffer(g))throw new TypeError('"list" argument must be an Array of Buffers');g.copy(B,Q)}Q+=g.length}return B},w.byteLength=a,w.prototype._isBuffer=!0,w.prototype.swap16=function(){const A=this.length;if(A%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let g=0;gI&&(A+=" ... "),""},C&&(w.prototype[C]=w.prototype.inspect),w.prototype.compare=function(A,g,I,B,Q){if(u(A,Uint8Array)&&(A=w.from(A,A.offset,A.byteLength)),!w.isBuffer(A))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof A);if(void 0===g&&(g=0),void 0===I&&(I=A?A.length:0),void 0===B&&(B=0),void 0===Q&&(Q=this.length),g<0||I>A.length||B<0||Q>this.length)throw new RangeError("out of range index");if(B>=Q&&g>=I)return 0;if(B>=Q)return-1;if(g>=I)return 1;if(this===A)return 0;let C=(Q>>>=0)-(B>>>=0),E=(I>>>=0)-(g>>>=0);const D=Math.min(C,E),i=this.slice(B,Q),o=A.slice(g,I);for(let A=0;A>>=0,isFinite(I)?(I>>>=0,void 0===B&&(B="utf8")):(B=I,I=void 0)}const Q=this.length-g;if((void 0===I||I>Q)&&(I=Q),A.length>0&&(I<0||g<0)||g>this.length)throw new RangeError("Attempt to write outside buffer bounds");B||(B="utf8");let C=!1;for(;;)switch(B){case"hex":return K(this,A,g,I);case"utf8":case"utf-8":return y(this,A,g,I);case"ascii":case"latin1":case"binary":return R(this,A,g,I);case"base64":return Y(this,A,g,I);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return q(this,A,g,I);default:if(C)throw new TypeError("Unknown encoding: "+B);B=(""+B).toLowerCase(),C=!0}},w.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};const L=4096;function H(A,g,I){let B="";I=Math.min(A.length,I);for(let Q=g;QB)&&(I=B);let Q="";for(let B=g;BI)throw new RangeError("Trying to access beyond buffer length")}function x(A,g,I,B,Q,C){if(!w.isBuffer(A))throw new TypeError('"buffer" argument must be a Buffer instance');if(g>Q||gA.length)throw new RangeError("Index out of range")}function t(A,g,I,B,Q){Z(g,B,Q,A,I,7);let C=Number(g&BigInt(4294967295));A[I++]=C,C>>=8,A[I++]=C,C>>=8,A[I++]=C,C>>=8,A[I++]=C;let E=Number(g>>BigInt(32)&BigInt(4294967295));return A[I++]=E,E>>=8,A[I++]=E,E>>=8,A[I++]=E,E>>=8,A[I++]=E,I}function d(A,g,I,B,Q){Z(g,B,Q,A,I,7);let C=Number(g&BigInt(4294967295));A[I+7]=C,C>>=8,A[I+6]=C,C>>=8,A[I+5]=C,C>>=8,A[I+4]=C;let E=Number(g>>BigInt(32)&BigInt(4294967295));return A[I+3]=E,E>>=8,A[I+2]=E,E>>=8,A[I+1]=E,E>>=8,A[I]=E,I+8}function W(A,g,I,B,Q,C){if(I+B>A.length)throw new RangeError("Index out of range");if(I<0)throw new RangeError("Index out of range")}function f(A,g,I,B,C){return g=+g,I>>>=0,C||W(A,0,I,4),Q.write(A,g,I,B,23,4),I+4}function j(A,g,I,B,C){return g=+g,I>>>=0,C||W(A,0,I,8),Q.write(A,g,I,B,52,8),I+8}w.prototype.slice=function(A,g){const I=this.length;(A=~~A)<0?(A+=I)<0&&(A=0):A>I&&(A=I),(g=void 0===g?I:~~g)<0?(g+=I)<0&&(g=0):g>I&&(g=I),g>>=0,g>>>=0,I||T(A,g,this.length);let B=this[A],Q=1,C=0;for(;++C>>=0,g>>>=0,I||T(A,g,this.length);let B=this[A+--g],Q=1;for(;g>0&&(Q*=256);)B+=this[A+--g]*Q;return B},w.prototype.readUint8=w.prototype.readUInt8=function(A,g){return A>>>=0,g||T(A,1,this.length),this[A]},w.prototype.readUint16LE=w.prototype.readUInt16LE=function(A,g){return A>>>=0,g||T(A,2,this.length),this[A]|this[A+1]<<8},w.prototype.readUint16BE=w.prototype.readUInt16BE=function(A,g){return A>>>=0,g||T(A,2,this.length),this[A]<<8|this[A+1]},w.prototype.readUint32LE=w.prototype.readUInt32LE=function(A,g){return A>>>=0,g||T(A,4,this.length),(this[A]|this[A+1]<<8|this[A+2]<<16)+16777216*this[A+3]},w.prototype.readUint32BE=w.prototype.readUInt32BE=function(A,g){return A>>>=0,g||T(A,4,this.length),16777216*this[A]+(this[A+1]<<16|this[A+2]<<8|this[A+3])},w.prototype.readBigUInt64LE=_((function(A){b(A>>>=0,"offset");const g=this[A],I=this[A+7];void 0!==g&&void 0!==I||n(A,this.length-8);const B=g+256*this[++A]+65536*this[++A]+this[++A]*2**24,Q=this[++A]+256*this[++A]+65536*this[++A]+I*2**24;return BigInt(B)+(BigInt(Q)<>>=0,"offset");const g=this[A],I=this[A+7];void 0!==g&&void 0!==I||n(A,this.length-8);const B=g*2**24+65536*this[++A]+256*this[++A]+this[++A],Q=this[++A]*2**24+65536*this[++A]+256*this[++A]+I;return(BigInt(B)<>>=0,g>>>=0,I||T(A,g,this.length);let B=this[A],Q=1,C=0;for(;++C=Q&&(B-=Math.pow(2,8*g)),B},w.prototype.readIntBE=function(A,g,I){A>>>=0,g>>>=0,I||T(A,g,this.length);let B=g,Q=1,C=this[A+--B];for(;B>0&&(Q*=256);)C+=this[A+--B]*Q;return Q*=128,C>=Q&&(C-=Math.pow(2,8*g)),C},w.prototype.readInt8=function(A,g){return A>>>=0,g||T(A,1,this.length),128&this[A]?-1*(255-this[A]+1):this[A]},w.prototype.readInt16LE=function(A,g){A>>>=0,g||T(A,2,this.length);const I=this[A]|this[A+1]<<8;return 32768&I?4294901760|I:I},w.prototype.readInt16BE=function(A,g){A>>>=0,g||T(A,2,this.length);const I=this[A+1]|this[A]<<8;return 32768&I?4294901760|I:I},w.prototype.readInt32LE=function(A,g){return A>>>=0,g||T(A,4,this.length),this[A]|this[A+1]<<8|this[A+2]<<16|this[A+3]<<24},w.prototype.readInt32BE=function(A,g){return A>>>=0,g||T(A,4,this.length),this[A]<<24|this[A+1]<<16|this[A+2]<<8|this[A+3]},w.prototype.readBigInt64LE=_((function(A){b(A>>>=0,"offset");const g=this[A],I=this[A+7];void 0!==g&&void 0!==I||n(A,this.length-8);const B=this[A+4]+256*this[A+5]+65536*this[A+6]+(I<<24);return(BigInt(B)<>>=0,"offset");const g=this[A],I=this[A+7];void 0!==g&&void 0!==I||n(A,this.length-8);const B=(g<<24)+65536*this[++A]+256*this[++A]+this[++A];return(BigInt(B)<>>=0,g||T(A,4,this.length),Q.read(this,A,!0,23,4)},w.prototype.readFloatBE=function(A,g){return A>>>=0,g||T(A,4,this.length),Q.read(this,A,!1,23,4)},w.prototype.readDoubleLE=function(A,g){return A>>>=0,g||T(A,8,this.length),Q.read(this,A,!0,52,8)},w.prototype.readDoubleBE=function(A,g){return A>>>=0,g||T(A,8,this.length),Q.read(this,A,!1,52,8)},w.prototype.writeUintLE=w.prototype.writeUIntLE=function(A,g,I,B){if(A=+A,g>>>=0,I>>>=0,!B){x(this,A,g,I,Math.pow(2,8*I)-1,0)}let Q=1,C=0;for(this[g]=255&A;++C>>=0,I>>>=0,!B){x(this,A,g,I,Math.pow(2,8*I)-1,0)}let Q=I-1,C=1;for(this[g+Q]=255&A;--Q>=0&&(C*=256);)this[g+Q]=A/C&255;return g+I},w.prototype.writeUint8=w.prototype.writeUInt8=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,1,255,0),this[g]=255&A,g+1},w.prototype.writeUint16LE=w.prototype.writeUInt16LE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,2,65535,0),this[g]=255&A,this[g+1]=A>>>8,g+2},w.prototype.writeUint16BE=w.prototype.writeUInt16BE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,2,65535,0),this[g]=A>>>8,this[g+1]=255&A,g+2},w.prototype.writeUint32LE=w.prototype.writeUInt32LE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,4,4294967295,0),this[g+3]=A>>>24,this[g+2]=A>>>16,this[g+1]=A>>>8,this[g]=255&A,g+4},w.prototype.writeUint32BE=w.prototype.writeUInt32BE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,4,4294967295,0),this[g]=A>>>24,this[g+1]=A>>>16,this[g+2]=A>>>8,this[g+3]=255&A,g+4},w.prototype.writeBigUInt64LE=_((function(A,g=0){return t(this,A,g,BigInt(0),BigInt("0xffffffffffffffff"))})),w.prototype.writeBigUInt64BE=_((function(A,g=0){return d(this,A,g,BigInt(0),BigInt("0xffffffffffffffff"))})),w.prototype.writeIntLE=function(A,g,I,B){if(A=+A,g>>>=0,!B){const B=Math.pow(2,8*I-1);x(this,A,g,I,B-1,-B)}let Q=0,C=1,E=0;for(this[g]=255&A;++Q>0)-E&255;return g+I},w.prototype.writeIntBE=function(A,g,I,B){if(A=+A,g>>>=0,!B){const B=Math.pow(2,8*I-1);x(this,A,g,I,B-1,-B)}let Q=I-1,C=1,E=0;for(this[g+Q]=255&A;--Q>=0&&(C*=256);)A<0&&0===E&&0!==this[g+Q+1]&&(E=1),this[g+Q]=(A/C>>0)-E&255;return g+I},w.prototype.writeInt8=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,1,127,-128),A<0&&(A=255+A+1),this[g]=255&A,g+1},w.prototype.writeInt16LE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,2,32767,-32768),this[g]=255&A,this[g+1]=A>>>8,g+2},w.prototype.writeInt16BE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,2,32767,-32768),this[g]=A>>>8,this[g+1]=255&A,g+2},w.prototype.writeInt32LE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,4,2147483647,-2147483648),this[g]=255&A,this[g+1]=A>>>8,this[g+2]=A>>>16,this[g+3]=A>>>24,g+4},w.prototype.writeInt32BE=function(A,g,I){return A=+A,g>>>=0,I||x(this,A,g,4,2147483647,-2147483648),A<0&&(A=4294967295+A+1),this[g]=A>>>24,this[g+1]=A>>>16,this[g+2]=A>>>8,this[g+3]=255&A,g+4},w.prototype.writeBigInt64LE=_((function(A,g=0){return t(this,A,g,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),w.prototype.writeBigInt64BE=_((function(A,g=0){return d(this,A,g,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),w.prototype.writeFloatLE=function(A,g,I){return f(this,A,g,!0,I)},w.prototype.writeFloatBE=function(A,g,I){return f(this,A,g,!1,I)},w.prototype.writeDoubleLE=function(A,g,I){return j(this,A,g,!0,I)},w.prototype.writeDoubleBE=function(A,g,I){return j(this,A,g,!1,I)},w.prototype.copy=function(A,g,I,B){if(!w.isBuffer(A))throw new TypeError("argument should be a Buffer");if(I||(I=0),B||0===B||(B=this.length),g>=A.length&&(g=A.length),g||(g=0),B>0&&B=this.length)throw new RangeError("Index out of range");if(B<0)throw new RangeError("sourceEnd out of bounds");B>this.length&&(B=this.length),A.length-g>>=0,I=void 0===I?this.length:I>>>0,A||(A=0),"number"==typeof A)for(Q=g;Q=B+4;I-=3)g=\`_\${A.slice(I-3,I)}\${g}\`;return\`\${A.slice(0,I)}\${g}\`}function Z(A,g,I,B,Q,C){if(A>I||A3?0===g||g===BigInt(0)?\`>= 0\${B} and < 2\${B} ** \${8*(C+1)}\${B}\`:\`>= -(2\${B} ** \${8*(C+1)-1}\${B}) and < 2 ** \${8*(C+1)-1}\${B}\`:\`>= \${g}\${B} and <= \${I}\${B}\`,new z.ERR_OUT_OF_RANGE("value",Q,A)}!function(A,g,I){b(g,"offset"),void 0!==A[g]&&void 0!==A[g+I]||n(g,A.length-(I+1))}(B,Q,C)}function b(A,g){if("number"!=typeof A)throw new z.ERR_INVALID_ARG_TYPE(g,"number",A)}function n(A,g,I){if(Math.floor(A)!==A)throw b(A,I),new z.ERR_OUT_OF_RANGE(I||"offset","an integer",A);if(g<0)throw new z.ERR_BUFFER_OUT_OF_BOUNDS;throw new z.ERR_OUT_OF_RANGE(I||"offset",\`>= \${I?1:0} and <= \${g}\`,A)}r("ERR_BUFFER_OUT_OF_BOUNDS",(function(A){return A?\`\${A} is outside of buffer bounds\`:"Attempt to access memory outside buffer bounds"}),RangeError),r("ERR_INVALID_ARG_TYPE",(function(A,g){return\`The "\${A}" argument must be of type number. Received type \${typeof g}\`}),TypeError),r("ERR_OUT_OF_RANGE",(function(A,g,I){let B=\`The value of "\${A}" is out of range.\`,Q=I;return Number.isInteger(I)&&Math.abs(I)>2**32?Q=P(String(I)):"bigint"==typeof I&&(Q=String(I),(I>BigInt(2)**BigInt(32)||I<-(BigInt(2)**BigInt(32)))&&(Q=P(Q)),Q+="n"),B+=\` It must be \${g}. Received \${Q}\`,B}),RangeError);const m=/[^+/0-9A-Za-z-_]/g;function V(A,g){let I;g=g||1/0;const B=A.length;let Q=null;const C=[];for(let E=0;E55295&&I<57344){if(!Q){if(I>56319){(g-=3)>-1&&C.push(239,191,189);continue}if(E+1===B){(g-=3)>-1&&C.push(239,191,189);continue}Q=I;continue}if(I<56320){(g-=3)>-1&&C.push(239,191,189),Q=I;continue}I=65536+(Q-55296<<10|I-56320)}else Q&&(g-=3)>-1&&C.push(239,191,189);if(Q=null,I<128){if((g-=1)<0)break;C.push(I)}else if(I<2048){if((g-=2)<0)break;C.push(I>>6|192,63&I|128)}else if(I<65536){if((g-=3)<0)break;C.push(I>>12|224,I>>6&63|128,63&I|128)}else{if(!(I<1114112))throw new Error("Invalid code point");if((g-=4)<0)break;C.push(I>>18|240,I>>12&63|128,I>>6&63|128,63&I|128)}}return C}function e(A){return B.toByteArray(function(A){if((A=(A=A.split("=")[0]).trim().replace(m,"")).length<2)return"";for(;A.length%4!=0;)A+="=";return A}(A))}function l(A,g,I,B){let Q;for(Q=0;Q=g.length||Q>=A.length);++Q)g[Q+I]=A[Q];return Q}function u(A,g){return A instanceof g||null!=A&&null!=A.constructor&&null!=A.constructor.name&&A.constructor.name===g.name}function v(A){return A!=A}const X=function(){const A="0123456789abcdef",g=new Array(256);for(let I=0;I<16;++I){const B=16*I;for(let Q=0;Q<16;++Q)g[B+Q]=A[I]+A[Q]}return g}();function _(A){return"undefined"==typeof BigInt?$:A}function $(){throw new Error("BigInt not supported")}},645:(A,g)=>{ /*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh */ -g.read=function(A,g,I,B,Q){var C,E,D=8*Q-B-1,w=(1<>1,o=-7,M=I?Q-1:0,G=I?-1:1,N=A[g+M];for(M+=G,C=N&(1<<-o)-1,N>>=-o,o+=D;o>0;C=256*C+A[g+M],M+=G,o-=8);for(E=C&(1<<-o)-1,C>>=-o,o+=B;o>0;E=256*E+A[g+M],M+=G,o-=8);if(0===C)C=1-i;else{if(C===w)return E?NaN:1/0*(N?-1:1);E+=Math.pow(2,B),C-=i}return(N?-1:1)*E*Math.pow(2,C-B)},g.write=function(A,g,I,B,Q,C){var E,D,w,i=8*C-Q-1,o=(1<>1,G=23===Q?Math.pow(2,-24)-Math.pow(2,-77):0,N=B?0:C-1,k=B?1:-1,a=g<0||0===g&&1/g<0?1:0;for(g=Math.abs(g),isNaN(g)||g===1/0?(D=isNaN(g)?1:0,E=o):(E=Math.floor(Math.log(g)/Math.LN2),g*(w=Math.pow(2,-E))<1&&(E--,w*=2),(g+=E+M>=1?G/w:G*Math.pow(2,1-M))*w>=2&&(E++,w/=2),E+M>=o?(D=0,E=o):E+M>=1?(D=(g*w-1)*Math.pow(2,Q),E+=M):(D=g*Math.pow(2,M-1)*Math.pow(2,Q),E=0));Q>=8;A[I+N]=255&D,N+=k,D/=256,Q-=8);for(E=E<0;A[I+N]=255&E,N+=k,E/=256,i-=8);A[I+N-k]|=128*a}},204:(A,g,I)=>{var B=I(150);A.exports=B,A.exports.default=B},150:A=>{"use strict";function g(A){return g="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&"function"==typeof Symbol&&A.constructor===Symbol&&A!==Symbol.prototype?"symbol":typeof A},g(A)}function I(A){return function(A){if(Array.isArray(A))return B(A)}(A)||function(A){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(A))return Array.from(A)}(A)||function(A,g){if(!A)return;if("string"==typeof A)return B(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return B(A,g)}(A)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function B(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0&&B.splice(Q,1)}},emitEvent:function(A,I){A in g&&g[A].forEach((function(A){return A(I)}))}}),M={},G={},N={};function k(A){return function(){for(var g=arguments.length,I=new Array(g),B=0;B0&&void 0!==arguments[0]?arguments[0]:[]).filter((function(A){return!N[A]})).map((function(A){N[A]=k(A)})),function(){if(B){var A=B;B=null,A.forEach((function(A){F(A)})),o.emitEvent("ready")}}(),Object.keys(G)}function y(){h(Object.keys(G)).then(J)}return a(Q,J),{bind:k,define:a,listener:function(A){if(A.reply){var g=i(A);M[g]&&(A.status===E?M[g].reject(A.data):M[g].resolve(A.data))}else if(G[A.command]){var I=G[A.command](A.data);I&&I.then?I.then((function(g){U(A,g,C)})).catch((function(g){U(A,g,E)})):U(A,I,C)}else U(A,"function ".concat(A.command," is not defined"),E);o.emitEvent("receive",A)},ready:y,fn:N,addEventListener:o.addEventListener,removeEventListener:o.removeEventListener,isConnect:function(){return!B}}}((function(A){return M&&o&&o(JSON.stringify(A))})),N=G.bind,k=G.define,a=G.listener,F=G.ready,U=G.fn,h=G.addEventListener,J=G.removeEventListener,y=G.isConnect,K=function(A){var I=void 0;if("object"===g(A))I=A;else if("string"==typeof A)try{I=JSON.parse(A)}catch(A){}I&&(I.command||I.reply)&&a(I)};if(M){var R=window.originalPostMessage;if(R)o=function(){var A;return(A=window).postMessage.apply(A,arguments)},F();else{var Y={get:function(){return R},set:function(A){(R=A)&&(o=function(){var A;return(A=window).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,"originalPostMessage",Y)}var q=window.ReactNativeWebView;if(q)o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},F();else{var c={get:function(){return q},set:function(A){(q=A)&&(o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,"ReactNativeWebView",c)}window.document.addEventListener("message",(function(A){return R&&K(A.data)})),window.addEventListener("message",(function(A){return q&&K(A.data)})),window.document.addEventListener("message",(function(A){return q&&K(A.data)}))}var s={bind:N,define:k,fn:U,addEventListener:h,removeEventListener:J,isConnect:y};A.exports=s}},g={};function I(B){var Q=g[B];if(void 0!==Q)return Q.exports;var C=g[B]={exports:{}};return A[B](C,C.exports,I),C.exports}I.n=A=>{var g=A&&A.__esModule?()=>A.default:()=>A;return I.d(g,{a:g}),g},I.d=(A,g)=>{for(var B in g)I.o(g,B)&&!I.o(A,B)&&Object.defineProperty(A,B,{enumerable:!0,get:g[B]})},I.o=(A,g)=>Object.prototype.hasOwnProperty.call(A,g),(()=>{"use strict";var A=I(204),g=I.n(A);function B(A){return function(A){if(Array.isArray(A))return Q(A)}(A)||function(A){if("undefined"!=typeof Symbol&&null!=A[Symbol.iterator]||null!=A["@@iterator"])return Array.from(A)}(A)||function(A,g){if(!A)return;if("string"==typeof A)return Q(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return Q(A,g)}(A)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Q(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0;--C){var E=this.tryEntries[C],D=E.completion;if("root"===E.tryLoc)return Q("end");if(E.tryLoc<=this.prev){var w=B.call(E,"catchLoc"),i=B.call(E,"finallyLoc");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,"finallyLoc")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),p(I),h}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if("throw"===B.type){var Q=B.arg;p(I)}return Q}}throw Error("illegal catch attempt")},delegateYield:function(g,I,B){return this.delegate={iterator:x(g),resultName:I,nextLoc:B},"next"===this.method&&(this.arg=A),h}},g}function D(A,g,I,B,Q,C,E){try{var D=A[C](E),w=D.value}catch(A){return void I(A)}D.done?g(w):Promise.resolve(w).then(B,Q)}function w(A){return function(){var g=this,I=arguments;return new Promise((function(B,Q){var C=A.apply(g,I);function E(A){D(C,B,Q,E,w,"next",A)}function w(A){D(C,B,Q,E,w,"throw",A)}E(void 0)}))}}function i(A,g){for(var I=0;I>>=0,N.decode(a().subarray(A,A+g))}var U=new Array(128).fill(void 0);U.push(void 0,null,!0,!1);var h=U.length;function J(A){h===U.length&&U.push(U.length+1);var g=h;return h=U[g],U[g]=A,g}function y(A){return U[A]}function K(A){var g=y(A);return function(A){A<132||(U[A]=h,h=A)}(A),g}var R=0,Y="undefined"!=typeof TextEncoder?new TextEncoder("utf-8"):{encode:function(){throw Error("TextEncoder not available")}},q="function"==typeof Y.encodeInto?function(A,g){return Y.encodeInto(A,g)}:function(A,g){var I=Y.encode(A);return g.set(I),{read:A.length,written:I.length}};function c(A,g,I){if(void 0===I){var B=Y.encode(A),Q=g(B.length,1)>>>0;return a().subarray(Q,Q+B.length).set(B),R=B.length,Q}for(var C=A.length,E=g(C,1)>>>0,D=a(),w=0;w127)break;D[E+w]=i}if(w!==C){0!==w&&(A=A.slice(w)),E=I(E,C,C=w+3*A.length,1)>>>0;var o=a().subarray(E+w,E+C);w+=q(A,o).written}return R=w,E}var s=null;function L(){return null!==s&&0!==s.byteLength||(s=new Int32Array(G.memory.buffer)),s}function H(A){var g=M(A);if("number"==g||"boolean"==g||null==A)return"".concat(A);if("string"==g)return'"'.concat(A,'"');if("symbol"==g){var I=A.description;return null==I?"Symbol":"Symbol(".concat(I,")")}if("function"==g){var B=A.name;return"string"==typeof B&&B.length>0?"Function(".concat(B,")"):"Function"}if(Array.isArray(A)){var Q=A.length,C="[";Q>0&&(C+=H(A[0]));for(var E=1;E1))return toString.call(A);if("Object"==(D=w[1]))try{return"Object("+JSON.stringify(A)+")"}catch(A){return"Object"}return A instanceof Error?"".concat(A.name,": ").concat(A.message,"\\n").concat(A.stack):D}function S(A,g,I){G.wasm_bindgen__convert__closures__invoke1_mut(A,g,J(I))}function O(A,g){G._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy(A,g)}var p=null;function T(A,g){for(var I=g(4*A.length,4)>>>0,B=(null!==p&&0!==p.byteLength||(p=new Uint32Array(G.memory.buffer)),p),Q=0;Q>>=0;var I=Object.create(A.prototype);return I.__wbg_ptr=g,I}},{key:"new",value:function(A,g){var I=T(g,G.__wbindgen_malloc),B=R;return K(G.ppom_new(J(A),I,B))}},{key:"version",value:function(){return K(G.ppom_version())}}],(I=[{key:"__destroy_into_raw",value:function(){var A=this.__wbg_ptr;return this.__wbg_ptr=0,A}},{key:"free",value:function(){var A=this.__destroy_into_raw();G.__wbg_ppom_free(A)}},{key:"validateJsonRpc",value:function(A){return K(G.ppom_validateJsonRpc(this.__wbg_ptr,J(A)))}}])&&i(g.prototype,I),B&&i(g,B),Object.defineProperty(g,"prototype",{writable:!1}),A}();function d(A,g){return W.apply(this,arguments)}function W(){return(W=w(E().mark((function A(g,I){var B,Q;return E().wrap((function(A){for(;;)switch(A.prev=A.next){case 0:if(!("function"==typeof Response&&g instanceof Response)){A.next=23;break}if("function"!=typeof WebAssembly.instantiateStreaming){A.next=15;break}return A.prev=2,A.next=5,WebAssembly.instantiateStreaming(g,I);case 5:case 20:return A.abrupt("return",A.sent);case 8:if(A.prev=8,A.t0=A.catch(2),"application/wasm"==g.headers.get("Content-Type")){A.next=14;break}console.warn("\`WebAssembly.instantiateStreaming\` failed because your server does not serve wasm with \`application/wasm\` MIME type. Falling back to \`WebAssembly.instantiate\` which is slower. Original error:\\n",A.t0),A.next=15;break;case 14:throw A.t0;case 15:return A.next=17,g.arrayBuffer();case 17:return B=A.sent,A.next=20,WebAssembly.instantiate(B,I);case 23:return A.next=25,WebAssembly.instantiate(g,I);case 25:if(!((Q=A.sent)instanceof WebAssembly.Instance)){A.next=30;break}return A.abrupt("return",{instance:Q,module:g});case 30:return A.abrupt("return",Q);case 31:case"end":return A.stop()}}),A,null,[[2,8]])})))).apply(this,arguments)}function j(){var A={wbg:{}};return A.wbg.__wbg_buffer_085ec1f694018c4f=function(A){return J(y(A).buffer)},A.wbg.__wbg_call_01734de55d61e11d=function(){return x((function(A,g,I){return J(y(A).call(y(g),y(I)))}),arguments)},A.wbg.__wbg_call_4c92f6aec1e1d6e6=function(){return x((function(A,g,I,B){return J(y(A).call(y(g),y(I),y(B)))}),arguments)},A.wbg.__wbg_from_d7c216d4616bb368=function(A){return J(Array.from(y(A)))},A.wbg.__wbg_get_44be0491f933a435=function(A,g){return J(y(A)[g>>>0])},A.wbg.__wbg_length_72e2208bbc0efc61=function(A){return y(A).length},A.wbg.__wbg_length_d813e535247d427e=function(A){return y(A).length},A.wbg.__wbg_length_fff51ee6522a1a18=function(A){return y(A).length},A.wbg.__wbg_new_43f1b47c28813cbd=function(A,g){try{var I={a:A,b:g},B=new Promise((function(A,g){var B=I.a;I.a=0;try{return function(A,g,I,B){G.wasm_bindgen__convert__closures__invoke2_mut(A,g,J(I),J(B))}(B,I.b,A,g)}finally{I.a=B}}));return J(B)}finally{I.a=I.b=0}},A.wbg.__wbg_new_8125e318e6245eed=function(A){return J(new Uint8Array(y(A)))},A.wbg.__wbg_parse_670c19d4e984792e=function(){return x((function(A,g){return J(JSON.parse(F(A,g)))}),arguments)},A.wbg.__wbg_ppom_new=function(A){return J(t.__wrap(A))},A.wbg.__wbg_resolve_53698b95aaf7fcf8=function(A){return J(Promise.resolve(y(A)))},A.wbg.__wbg_set_5cf90238115182c3=function(A,g,I){y(A).set(y(g),I>>>0)},A.wbg.__wbg_stringify_e25465938f3f611f=function(){return x((function(A){return J(JSON.stringify(y(A)))}),arguments)},A.wbg.__wbg_then_b2267541e2a73865=function(A,g,I){return J(y(A).then(y(g),y(I)))},A.wbg.__wbg_then_f7e06ee3c11698eb=function(A,g){return J(y(A).then(y(g)))},A.wbg.__wbindgen_cb_drop=function(A){var g=K(A).original;if(1==g.cnt--)return g.a=0,!0;return!1},A.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined=function(A,g,I){var B=function(A,g,I,B){var Q={a:A,b:g,cnt:1},C=function(){Q.cnt++;var A=Q.a;Q.a=0;try{for(var g=arguments.length,C=new Array(g),E=0;E=0;--C){var E=this.tryEntries[C],D=E.completion;if("root"===E.tryLoc)return Q("end");if(E.tryLoc<=this.prev){var w=B.call(E,"catchLoc"),i=B.call(E,"finallyLoc");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,"finallyLoc")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),S(I),F}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if("throw"===B.type){var Q=B.arg;S(I)}return Q}}throw Error("illegal catch attempt")},delegateYield:function(g,I,B){return this.delegate={iterator:p(g),resultName:I,nextLoc:B},"next"===this.method&&(this.arg=A),F}},g}function m(A,g){return function(A){if(Array.isArray(A))return A}(A)||function(A,g){var I=null==A?null:"undefined"!=typeof Symbol&&A[Symbol.iterator]||A["@@iterator"];if(null!=I){var B,Q,C,E,D=[],w=!0,i=!1;try{if(C=(I=I.call(A)).next,0===g){if(Object(I)!==I)return;w=!1}else for(;!(w=(B=C.call(I)).done)&&(D.push(B.value),D.length!==g);w=!0);}catch(A){i=!0,Q=A}finally{try{if(!w&&null!=I.return&&(E=I.return(),Object(E)!==E))return}finally{if(i)throw Q}}return D}}(A,g)||function(A,g){if(!A)return;if("string"==typeof A)return e(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return e(A,g)}(A,g)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function e(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I", +g.read=function(A,g,I,B,Q){var C,E,D=8*Q-B-1,w=(1<>1,o=-7,M=I?Q-1:0,G=I?-1:1,N=A[g+M];for(M+=G,C=N&(1<<-o)-1,N>>=-o,o+=D;o>0;C=256*C+A[g+M],M+=G,o-=8);for(E=C&(1<<-o)-1,C>>=-o,o+=B;o>0;E=256*E+A[g+M],M+=G,o-=8);if(0===C)C=1-i;else{if(C===w)return E?NaN:1/0*(N?-1:1);E+=Math.pow(2,B),C-=i}return(N?-1:1)*E*Math.pow(2,C-B)},g.write=function(A,g,I,B,Q,C){var E,D,w,i=8*C-Q-1,o=(1<>1,G=23===Q?Math.pow(2,-24)-Math.pow(2,-77):0,N=B?0:C-1,k=B?1:-1,a=g<0||0===g&&1/g<0?1:0;for(g=Math.abs(g),isNaN(g)||g===1/0?(D=isNaN(g)?1:0,E=o):(E=Math.floor(Math.log(g)/Math.LN2),g*(w=Math.pow(2,-E))<1&&(E--,w*=2),(g+=E+M>=1?G/w:G*Math.pow(2,1-M))*w>=2&&(E++,w/=2),E+M>=o?(D=0,E=o):E+M>=1?(D=(g*w-1)*Math.pow(2,Q),E+=M):(D=g*Math.pow(2,M-1)*Math.pow(2,Q),E=0));Q>=8;A[I+N]=255&D,N+=k,D/=256,Q-=8);for(E=E<0;A[I+N]=255&E,N+=k,E/=256,i-=8);A[I+N-k]|=128*a}},204:(A,g,I)=>{var B=I(150);A.exports=B,A.exports.default=B},150:A=>{"use strict";function g(A){return g="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(A){return typeof A}:function(A){return A&&"function"==typeof Symbol&&A.constructor===Symbol&&A!==Symbol.prototype?"symbol":typeof A},g(A)}function I(A){return function(A){if(Array.isArray(A))return B(A)}(A)||function(A){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(A))return Array.from(A)}(A)||function(A,g){if(!A)return;if("string"==typeof A)return B(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return B(A,g)}(A)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function B(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0&&B.splice(Q,1)}},emitEvent:function(A,I){A in g&&g[A].forEach((function(A){return A(I)}))}}),M={},G={},N={};function k(A){return function(){for(var g=arguments.length,I=new Array(g),B=0;B0&&void 0!==arguments[0]?arguments[0]:[]).filter((function(A){return!N[A]})).map((function(A){N[A]=k(A)})),function(){if(B){var A=B;B=null,A.forEach((function(A){F(A)})),o.emitEvent("ready")}}(),Object.keys(G)}function K(){J(Object.keys(G)).then(h)}return a(Q,h),{bind:k,define:a,listener:function(A){if(A.reply){var g=i(A);M[g]&&(A.status===E?M[g].reject(A.data):M[g].resolve(A.data))}else if(G[A.command]){var I=G[A.command](A.data);I&&I.then?I.then((function(g){U(A,g,C)})).catch((function(g){U(A,g,E)})):U(A,I,C)}else U(A,"function ".concat(A.command," is not defined"),E);o.emitEvent("receive",A)},ready:K,fn:N,addEventListener:o.addEventListener,removeEventListener:o.removeEventListener,isConnect:function(){return!B}}}((function(A){return M&&o&&o(JSON.stringify(A))})),N=G.bind,k=G.define,a=G.listener,F=G.ready,U=G.fn,J=G.addEventListener,h=G.removeEventListener,K=G.isConnect,y=function(A){var I=void 0;if("object"===g(A))I=A;else if("string"==typeof A)try{I=JSON.parse(A)}catch(A){}I&&(I.command||I.reply)&&a(I)};if(M){var R=window.originalPostMessage;if(R)o=function(){var A;return(A=window).postMessage.apply(A,arguments)},F();else{var Y={get:function(){return R},set:function(A){(R=A)&&(o=function(){var A;return(A=window).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,"originalPostMessage",Y)}var q=window.ReactNativeWebView;if(q)o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},F();else{var c={get:function(){return q},set:function(A){(q=A)&&(o=function(){var A;return(A=window.ReactNativeWebView).postMessage.apply(A,arguments)},setTimeout(F,50))}};Object.defineProperty(window,"ReactNativeWebView",c)}window.document.addEventListener("message",(function(A){return R&&y(A.data)})),window.addEventListener("message",(function(A){return q&&y(A.data)})),window.document.addEventListener("message",(function(A){return q&&y(A.data)}))}var s={bind:N,define:k,fn:U,addEventListener:J,removeEventListener:h,isConnect:K};A.exports=s}},g={};function I(B){var Q=g[B];if(void 0!==Q)return Q.exports;var C=g[B]={exports:{}};return A[B](C,C.exports,I),C.exports}I.n=A=>{var g=A&&A.__esModule?()=>A.default:()=>A;return I.d(g,{a:g}),g},I.d=(A,g)=>{for(var B in g)I.o(g,B)&&!I.o(A,B)&&Object.defineProperty(A,B,{enumerable:!0,get:g[B]})},I.o=(A,g)=>Object.prototype.hasOwnProperty.call(A,g),(()=>{"use strict";var A=I(204),g=I.n(A);function B(A){return function(A){if(Array.isArray(A))return Q(A)}(A)||function(A){if("undefined"!=typeof Symbol&&null!=A[Symbol.iterator]||null!=A["@@iterator"])return Array.from(A)}(A)||function(A,g){if(!A)return;if("string"==typeof A)return Q(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return Q(A,g)}(A)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Q(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I=0;--C){var E=this.tryEntries[C],D=E.completion;if("root"===E.tryLoc)return Q("end");if(E.tryLoc<=this.prev){var w=B.call(E,"catchLoc"),i=B.call(E,"finallyLoc");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,"finallyLoc")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),p(I),J}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if("throw"===B.type){var Q=B.arg;p(I)}return Q}}throw Error("illegal catch attempt")},delegateYield:function(g,I,B){return this.delegate={iterator:x(g),resultName:I,nextLoc:B},"next"===this.method&&(this.arg=A),J}},g}function D(A,g,I,B,Q,C,E){try{var D=A[C](E),w=D.value}catch(A){return void I(A)}D.done?g(w):Promise.resolve(w).then(B,Q)}function w(A){return function(){var g=this,I=arguments;return new Promise((function(B,Q){var C=A.apply(g,I);function E(A){D(C,B,Q,E,w,"next",A)}function w(A){D(C,B,Q,E,w,"throw",A)}E(void 0)}))}}function i(A,g){for(var I=0;I>>=0,N.decode(a().subarray(A,A+g))}var U=new Array(128).fill(void 0);U.push(void 0,null,!0,!1);var J=U.length;function h(A){J===U.length&&U.push(U.length+1);var g=J;return J=U[g],U[g]=A,g}function K(A){return U[A]}function y(A){var g=K(A);return function(A){A<132||(U[A]=J,J=A)}(A),g}var R=0,Y="undefined"!=typeof TextEncoder?new TextEncoder("utf-8"):{encode:function(){throw Error("TextEncoder not available")}},q="function"==typeof Y.encodeInto?function(A,g){return Y.encodeInto(A,g)}:function(A,g){var I=Y.encode(A);return g.set(I),{read:A.length,written:I.length}};function c(A,g,I){if(void 0===I){var B=Y.encode(A),Q=g(B.length,1)>>>0;return a().subarray(Q,Q+B.length).set(B),R=B.length,Q}for(var C=A.length,E=g(C,1)>>>0,D=a(),w=0;w127)break;D[E+w]=i}if(w!==C){0!==w&&(A=A.slice(w)),E=I(E,C,C=w+3*A.length,1)>>>0;var o=a().subarray(E+w,E+C);w+=q(A,o).written}return R=w,E}var s=null;function L(){return null!==s&&0!==s.byteLength||(s=new Int32Array(G.memory.buffer)),s}function H(A){var g=M(A);if("number"==g||"boolean"==g||null==A)return"".concat(A);if("string"==g)return'"'.concat(A,'"');if("symbol"==g){var I=A.description;return null==I?"Symbol":"Symbol(".concat(I,")")}if("function"==g){var B=A.name;return"string"==typeof B&&B.length>0?"Function(".concat(B,")"):"Function"}if(Array.isArray(A)){var Q=A.length,C="[";Q>0&&(C+=H(A[0]));for(var E=1;E1))return toString.call(A);if("Object"==(D=w[1]))try{return"Object("+JSON.stringify(A)+")"}catch(A){return"Object"}return A instanceof Error?"".concat(A.name,": ").concat(A.message,"\\n").concat(A.stack):D}function S(A,g,I){G.wasm_bindgen__convert__closures__invoke1_mut(A,g,h(I))}function O(A,g){G._dyn_core__ops__function__FnMut__A____Output___R_as_wasm_bindgen__closure__WasmClosure___describe__destroy(A,g)}var p=null;function T(A,g){for(var I=g(4*A.length,4)>>>0,B=(null!==p&&0!==p.byteLength||(p=new Uint32Array(G.memory.buffer)),p),Q=0;Q>>=0;var I=Object.create(A.prototype);return I.__wbg_ptr=g,I}},{key:"new",value:function(A,g){var I=T(g,G.__wbindgen_malloc),B=R;return y(G.ppom_new(h(A),I,B))}},{key:"version",value:function(){return y(G.ppom_version())}}],(I=[{key:"__destroy_into_raw",value:function(){var A=this.__wbg_ptr;return this.__wbg_ptr=0,A}},{key:"free",value:function(){var A=this.__destroy_into_raw();G.__wbg_ppom_free(A)}},{key:"validateJsonRpc",value:function(A){return y(G.ppom_validateJsonRpc(this.__wbg_ptr,h(A)))}}])&&i(g.prototype,I),B&&i(g,B),Object.defineProperty(g,"prototype",{writable:!1}),A}();function d(A,g){return W.apply(this,arguments)}function W(){return(W=w(E().mark((function A(g,I){var B,Q;return E().wrap((function(A){for(;;)switch(A.prev=A.next){case 0:if(!("function"==typeof Response&&g instanceof Response)){A.next=23;break}if("function"!=typeof WebAssembly.instantiateStreaming){A.next=15;break}return A.prev=2,A.next=5,WebAssembly.instantiateStreaming(g,I);case 5:case 20:return A.abrupt("return",A.sent);case 8:if(A.prev=8,A.t0=A.catch(2),"application/wasm"==g.headers.get("Content-Type")){A.next=14;break}console.warn("\`WebAssembly.instantiateStreaming\` failed because your server does not serve wasm with \`application/wasm\` MIME type. Falling back to \`WebAssembly.instantiate\` which is slower. Original error:\\n",A.t0),A.next=15;break;case 14:throw A.t0;case 15:return A.next=17,g.arrayBuffer();case 17:return B=A.sent,A.next=20,WebAssembly.instantiate(B,I);case 23:return A.next=25,WebAssembly.instantiate(g,I);case 25:if(!((Q=A.sent)instanceof WebAssembly.Instance)){A.next=30;break}return A.abrupt("return",{instance:Q,module:g});case 30:return A.abrupt("return",Q);case 31:case"end":return A.stop()}}),A,null,[[2,8]])})))).apply(this,arguments)}function f(){var A={wbg:{}};return A.wbg.__wbg_buffer_085ec1f694018c4f=function(A){return h(K(A).buffer)},A.wbg.__wbg_call_01734de55d61e11d=function(){return x((function(A,g,I){return h(K(A).call(K(g),K(I)))}),arguments)},A.wbg.__wbg_call_4c92f6aec1e1d6e6=function(){return x((function(A,g,I,B){return h(K(A).call(K(g),K(I),K(B)))}),arguments)},A.wbg.__wbg_from_d7c216d4616bb368=function(A){return h(Array.from(K(A)))},A.wbg.__wbg_get_44be0491f933a435=function(A,g){return h(K(A)[g>>>0])},A.wbg.__wbg_length_72e2208bbc0efc61=function(A){return K(A).length},A.wbg.__wbg_length_d813e535247d427e=function(A){return K(A).length},A.wbg.__wbg_length_fff51ee6522a1a18=function(A){return K(A).length},A.wbg.__wbg_new_43f1b47c28813cbd=function(A,g){try{var I={a:A,b:g},B=new Promise((function(A,g){var B=I.a;I.a=0;try{return function(A,g,I,B){G.wasm_bindgen__convert__closures__invoke2_mut(A,g,h(I),h(B))}(B,I.b,A,g)}finally{I.a=B}}));return h(B)}finally{I.a=I.b=0}},A.wbg.__wbg_new_8125e318e6245eed=function(A){return h(new Uint8Array(K(A)))},A.wbg.__wbg_parse_670c19d4e984792e=function(){return x((function(A,g){return h(JSON.parse(F(A,g)))}),arguments)},A.wbg.__wbg_ppom_new=function(A){return h(t.__wrap(A))},A.wbg.__wbg_resolve_53698b95aaf7fcf8=function(A){return h(Promise.resolve(K(A)))},A.wbg.__wbg_set_5cf90238115182c3=function(A,g,I){K(A).set(K(g),I>>>0)},A.wbg.__wbg_stringify_e25465938f3f611f=function(){return x((function(A){return h(JSON.stringify(K(A)))}),arguments)},A.wbg.__wbg_then_b2267541e2a73865=function(A,g,I){return h(K(A).then(K(g),K(I)))},A.wbg.__wbg_then_f7e06ee3c11698eb=function(A,g){return h(K(A).then(K(g)))},A.wbg.__wbindgen_cb_drop=function(A){var g=y(A).original;if(1==g.cnt--)return g.a=0,!0;return!1},A.wbg.__wbindgen_closure_wrapper_wasm_bindgen__closure__Closure_T___wrap__breaks_if_inlined=function(A,g,I){var B=function(A,g,I,B){var Q={a:A,b:g,cnt:1},C=function(){Q.cnt++;var A=Q.a;Q.a=0;try{for(var g=arguments.length,C=new Array(g),E=0;E=0;--C){var E=this.tryEntries[C],D=E.completion;if("root"===E.tryLoc)return Q("end");if(E.tryLoc<=this.prev){var w=B.call(E,"catchLoc"),i=B.call(E,"finallyLoc");if(w&&i){if(this.prev=0;--I){var Q=this.tryEntries[I];if(Q.tryLoc<=this.prev&&B.call(Q,"finallyLoc")&&this.prev=0;--g){var I=this.tryEntries[g];if(I.finallyLoc===A)return this.complete(I.completion,I.afterLoc),S(I),F}},catch:function(A){for(var g=this.tryEntries.length-1;g>=0;--g){var I=this.tryEntries[g];if(I.tryLoc===A){var B=I.completion;if("throw"===B.type){var Q=B.arg;S(I)}return Q}}throw Error("illegal catch attempt")},delegateYield:function(g,I,B){return this.delegate={iterator:p(g),resultName:I,nextLoc:B},"next"===this.method&&(this.arg=A),F}},g}function m(A,g){return function(A){if(Array.isArray(A))return A}(A)||function(A,g){var I=null==A?null:"undefined"!=typeof Symbol&&A[Symbol.iterator]||A["@@iterator"];if(null!=I){var B,Q,C,E,D=[],w=!0,i=!1;try{if(C=(I=I.call(A)).next,0===g){if(Object(I)!==I)return;w=!1}else for(;!(w=(B=C.call(I)).done)&&(D.push(B.value),D.length!==g);w=!0);}catch(A){i=!0,Q=A}finally{try{if(!w&&null!=I.return&&(E=I.return(),Object(E)!==E))return}finally{if(i)throw Q}}return D}}(A,g)||function(A,g){if(!A)return;if("string"==typeof A)return V(A,g);var I=Object.prototype.toString.call(A).slice(8,-1);"Object"===I&&A.constructor&&(I=A.constructor.name);if("Map"===I||"Set"===I)return Array.from(A);if("Arguments"===I||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(I))return V(A,g)}(A,g)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function V(A,g){(null==g||g>A.length)&&(g=A.length);for(var I=0,B=new Array(g);I", } } /> From f5cf399f21733e8fad50ac6b2e1c432f28c67544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 25 Jun 2024 23:23:42 +0100 Subject: [PATCH 39/41] RNWebView: (inpage provider) Replace script tag with straight code execution (#10053) Update `inpage-bridge` build process and change provider injection method Context: CSP directives might block inline script execution, thus preventing our web3 provider from being injected with a script tag creation. Replacing it with a direct function call avoids being blocked. Co-authored-by: jiexi --- app/components/Views/BrowserTab/index.js | 30 +-------- scripts/build-inpage-bridge.sh | 6 +- scripts/inpage-bridge/content-script/build.js | 14 ----- .../inpage-bridge/inpage/webpack.config.js | 63 ------------------- .../{inpage => src}/MobilePortStream.js | 0 .../ReactNativePostMessageStream.js | 0 .../{content-script => src}/index.js | 32 ++-------- .../{inpage/index.js => src/provider.js} | 47 +++++++------- scripts/inpage-bridge/webpack.config.js | 46 +++++++++++++- 9 files changed, 78 insertions(+), 160 deletions(-) delete mode 100644 scripts/inpage-bridge/content-script/build.js delete mode 100644 scripts/inpage-bridge/inpage/webpack.config.js rename scripts/inpage-bridge/{inpage => src}/MobilePortStream.js (100%) rename scripts/inpage-bridge/{inpage => src}/ReactNativePostMessageStream.js (100%) rename scripts/inpage-bridge/{content-script => src}/index.js (78%) rename scripts/inpage-bridge/{inpage/index.js => src/provider.js} (83%) diff --git a/app/components/Views/BrowserTab/index.js b/app/components/Views/BrowserTab/index.js index 370d80bcca1..28dea8dca94 100644 --- a/app/components/Views/BrowserTab/index.js +++ b/app/components/Views/BrowserTab/index.js @@ -1491,34 +1491,6 @@ export const BrowserTab = (props) => { ); - /* - * handleEarlyWeb3ProviderInit workaround. Android only - * - * It avoids the error 'Uncaught TypeError: Cannot read properties of null (reading 'nodeName')' - * by reloading the page if documentElement is not yet defined. - * - * This happens because web3 provider checks for valid HTML document prior initialization with - * document.documentElement.nodeName === 'html' - * - * We must inject the web3 provider at the early stages on the page loading so that - * dapps recognize metamask mobile provider correctly. - * - * This is caused by Android webview lifecycle method `onPageStarted` - * that might execute too early in the document loading phase. - * - * iOS devices aren't affected. - * - */ - const handleEarlyWeb3ProviderInit = `if (!document.documentElement) { - window.location.reload(); - } else { - ${entryScriptWeb3} - }`; - - const handleInjectedJavaScript = Device.isAndroid() - ? handleEarlyWeb3ProviderInit - : entryScriptWeb3; - /** * Main render */ @@ -1547,7 +1519,7 @@ export const BrowserTab = (props) => { )} source={{ uri: initialUrl }} - injectedJavaScriptBeforeContentLoaded={handleInjectedJavaScript} + injectedJavaScriptBeforeContentLoaded={entryScriptWeb3} style={styles.webview} onLoadStart={onLoadStart} onLoad={onLoad} diff --git a/scripts/build-inpage-bridge.sh b/scripts/build-inpage-bridge.sh index 7823e49dd80..52753a1589a 100755 --- a/scripts/build-inpage-bridge.sh +++ b/scripts/build-inpage-bridge.sh @@ -3,11 +3,7 @@ set -euo pipefail rm -f app/core/InpageBridgeWeb3.js mkdir -p scripts/inpage-bridge/dist && rm -rf scripts/inpage-bridge/dist/* -cd scripts/inpage-bridge/inpage -../../../node_modules/.bin/webpack --config webpack.config.js -cd .. -node content-script/build.js -cat dist/inpage-bundle.js content-script/index.js > dist/index-raw.js +cd scripts/inpage-bridge/ ../../node_modules/.bin/webpack --config webpack.config.js cd ../.. cp scripts/inpage-bridge/dist/index.js app/core/InpageBridgeWeb3.js diff --git a/scripts/inpage-bridge/content-script/build.js b/scripts/inpage-bridge/content-script/build.js deleted file mode 100644 index cd0ca95605c..00000000000 --- a/scripts/inpage-bridge/content-script/build.js +++ /dev/null @@ -1,14 +0,0 @@ -const fs = require('fs'); -const path = require('path'); - -const distPath = path.join(__dirname, '..', '/', 'dist'); - -const inpageContent = fs - .readFileSync(path.join(distPath, 'inpage-content.js')) - .toString(); - -// wrap the inpage content in a variable declaration -const code = `const inpageBundle = ${JSON.stringify(inpageContent)}`; - -fs.writeFileSync(path.join(distPath, 'inpage-bundle.js'), code, 'ascii'); -console.log('content-script.js generated succesfully'); diff --git a/scripts/inpage-bridge/inpage/webpack.config.js b/scripts/inpage-bridge/inpage/webpack.config.js deleted file mode 100644 index f1d28be96f1..00000000000 --- a/scripts/inpage-bridge/inpage/webpack.config.js +++ /dev/null @@ -1,63 +0,0 @@ -const webpack = require('webpack'); -const path = require('path'); -const { readFileSync } = require('fs'); - -const SVG_LOGO_PATH = - '../../../app/images/fox.svg'; -function getBuildIcon() { - const svg = readFileSync(SVG_LOGO_PATH, 'utf8'); - return `data:image/svg+xml,${encodeURIComponent(svg)}`; -} - -const config = { - entry: './index.js', - - output: { - path: path.resolve(__dirname, '..', 'dist'), - filename: 'inpage-content.js', - }, - - mode: 'production', - module: { - rules: [ - { - test: /\.(js|jsx|mjs)$/u, - use: { - loader: 'babel-loader', - options: { - presets: ['@babel/preset-env'], - }, - }, - }, - ], - }, - resolve: { - fallback: { - buffer: require.resolve('buffer'), - stream: require.resolve('stream-browserify'), - _stream_transform: require.resolve('readable-stream/transform'), - _stream_readable: require.resolve('readable-stream/readable'), - _stream_writable: require.resolve('readable-stream/writable'), - _stream_duplex: require.resolve('readable-stream/duplex'), - _stream_passthrough: require.resolve('readable-stream/passthrough'), - }, - }, - plugins: [ - new webpack.ProvidePlugin({ - Buffer: ['buffer', 'Buffer'], - process: 'process/browser', - }), - new webpack.DefinePlugin({ - 'process.env.METAMASK_BUILD_NAME': JSON.stringify('MetaMask'), - 'process.env.METAMASK_BUILD_ICON': JSON.stringify(getBuildIcon()), - 'process.env.METAMASK_BUILD_APP_ID': JSON.stringify('io.metamask.mobile'), - }), - ], -}; - -module.exports = (_env, argv) => { - if (argv.mode === 'development') { - config.mode = 'development'; - } - return config; -}; diff --git a/scripts/inpage-bridge/inpage/MobilePortStream.js b/scripts/inpage-bridge/src/MobilePortStream.js similarity index 100% rename from scripts/inpage-bridge/inpage/MobilePortStream.js rename to scripts/inpage-bridge/src/MobilePortStream.js diff --git a/scripts/inpage-bridge/inpage/ReactNativePostMessageStream.js b/scripts/inpage-bridge/src/ReactNativePostMessageStream.js similarity index 100% rename from scripts/inpage-bridge/inpage/ReactNativePostMessageStream.js rename to scripts/inpage-bridge/src/ReactNativePostMessageStream.js diff --git a/scripts/inpage-bridge/content-script/index.js b/scripts/inpage-bridge/src/index.js similarity index 78% rename from scripts/inpage-bridge/content-script/index.js rename to scripts/inpage-bridge/src/index.js index 16052682c1f..0544f17cdb7 100644 --- a/scripts/inpage-bridge/content-script/index.js +++ b/scripts/inpage-bridge/src/index.js @@ -1,7 +1,8 @@ -/* global inpageBundle */ + +import initializeInpageProvider from './provider'; if (shouldInject()) { - injectScript(inpageBundle); + injectScript(); start(); } @@ -21,18 +22,9 @@ async function start() { * * @param {string} content - Code to be executed in the current document */ -function injectScript(content) { +function injectScript() { try { - const container = document.head || document.documentElement; - - // synchronously execute script in page context - const scriptTag = document.createElement('script'); - scriptTag.setAttribute('async', false); - scriptTag.textContent = content; - container.insertBefore(scriptTag, container.children[0]); - - // script executed; remove script element from DOM - container.removeChild(scriptTag); + inpageProvider(); } catch (err) { console.error('MetaMask script injection failed', err); } @@ -47,7 +39,6 @@ function shouldInject() { return ( doctypeCheck() && suffixCheck() && - documentElementCheck() && !blockedDomainCheck() ); } @@ -86,19 +77,6 @@ function suffixCheck() { return true; } -/** - * Checks the documentElement of the current document - * - * @returns {boolean} {@code true} if the documentElement is an html node or if none exists - */ -function documentElementCheck() { - const documentElement = document.documentElement.nodeName; - if (documentElement) { - return documentElement.toLowerCase() === 'html'; - } - return true; -} - /** * Checks if the current domain is blocked * diff --git a/scripts/inpage-bridge/inpage/index.js b/scripts/inpage-bridge/src/provider.js similarity index 83% rename from scripts/inpage-bridge/inpage/index.js rename to scripts/inpage-bridge/src/provider.js index b76b2ae006a..f3cdca54008 100644 --- a/scripts/inpage-bridge/inpage/index.js +++ b/scripts/inpage-bridge/src/provider.js @@ -15,28 +15,31 @@ const metamaskStream = new ReactNativePostMessageStream({ target: CONTENT_SCRIPT, }); -// Initialize provider object (window.ethereum) -initializeProvider({ - connectionStream: metamaskStream, - shouldSendMetadata: false, - providerInfo: { - uuid: uuid(), - name: process.env.METAMASK_BUILD_NAME, - icon: process.env.METAMASK_BUILD_ICON, - rdns: process.env.METAMASK_BUILD_APP_ID, - }, -}); +const init = () => { + // Initialize provider object (window.ethereum) + initializeProvider({ + connectionStream: metamaskStream, + shouldSendMetadata: false, + providerInfo: { + uuid: uuid(), + name: process.env.METAMASK_BUILD_NAME, + icon: process.env.METAMASK_BUILD_ICON, + rdns: process.env.METAMASK_BUILD_APP_ID, + }, + }); -// Set content script post-setup function -Object.defineProperty(window, '_metamaskSetupProvider', { - value: () => { - setupProviderStreams(); - delete window._metamaskSetupProvider; - }, - configurable: true, - enumerable: false, - writable: false, -}); + // Set content script post-setup function + Object.defineProperty(window, '_metamaskSetupProvider', { + value: () => { + setupProviderStreams(); + delete window._metamaskSetupProvider; + }, + configurable: true, + enumerable: false, + writable: false, + }); + +} // Functions @@ -130,3 +133,5 @@ function notifyProviderOfStreamFailure() { window.location.origin, ); } + +export default init; diff --git a/scripts/inpage-bridge/webpack.config.js b/scripts/inpage-bridge/webpack.config.js index 8c0dff54856..b8fa14e20d1 100644 --- a/scripts/inpage-bridge/webpack.config.js +++ b/scripts/inpage-bridge/webpack.config.js @@ -1,7 +1,16 @@ +const webpack = require('webpack'); const path = require('path'); +const { readFileSync } = require('fs'); + +const SVG_LOGO_PATH = + '../../app/images/fox.svg'; +function getBuildIcon() { + const svg = readFileSync(SVG_LOGO_PATH, 'utf8'); + return `data:image/svg+xml,${encodeURIComponent(svg)}`; +} const config = { - entry: './dist/index-raw.js', + entry: './src/index.js', output: { path: path.resolve(__dirname, 'dist'), @@ -9,6 +18,41 @@ const config = { }, mode: 'production', + module: { + rules: [ + { + test: /\.(js|jsx|mjs)$/u, + use: { + loader: 'babel-loader', + options: { + presets: ['@babel/preset-env'], + }, + }, + }, + ], + }, + resolve: { + fallback: { + buffer: require.resolve('buffer'), + stream: require.resolve('stream-browserify'), + _stream_transform: require.resolve('readable-stream/transform'), + _stream_readable: require.resolve('readable-stream/readable'), + _stream_writable: require.resolve('readable-stream/writable'), + _stream_duplex: require.resolve('readable-stream/duplex'), + _stream_passthrough: require.resolve('readable-stream/passthrough'), + }, + }, + plugins: [ + new webpack.ProvidePlugin({ + Buffer: ['buffer', 'Buffer'], + process: 'process/browser', + }), + new webpack.DefinePlugin({ + 'process.env.METAMASK_BUILD_NAME': JSON.stringify('MetaMask'), + 'process.env.METAMASK_BUILD_ICON': JSON.stringify(getBuildIcon()), + 'process.env.METAMASK_BUILD_APP_ID': JSON.stringify('io.metamask.mobile'), + }), + ], }; module.exports = (_env, argv) => { From 060c1e7600f64aaddf418387cebd59446a9d6095 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Tue, 25 Jun 2024 23:32:32 +0100 Subject: [PATCH 40/41] remove unneeded trycatch block --- scripts/inpage-bridge/src/index.js | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/scripts/inpage-bridge/src/index.js b/scripts/inpage-bridge/src/index.js index 0544f17cdb7..2a4787822fc 100644 --- a/scripts/inpage-bridge/src/index.js +++ b/scripts/inpage-bridge/src/index.js @@ -1,8 +1,8 @@ -import initializeInpageProvider from './provider'; +import injectInpageProvider from './provider'; if (shouldInject()) { - injectScript(); + injectInpageProvider(); start(); } @@ -17,19 +17,6 @@ async function start() { window._metamaskSetupProvider(); } -/** - * Injects a script tag into the current document - * - * @param {string} content - Code to be executed in the current document - */ -function injectScript() { - try { - inpageProvider(); - } catch (err) { - console.error('MetaMask script injection failed', err); - } -} - /** * Determines if the provider should be injected. * From ff2515b5f5bc81e9ee4747eac67f9745e213a705 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Loureiro?= <1649425+jpcloureiro@users.noreply.github.com> Date: Thu, 27 Jun 2024 18:34:54 +0100 Subject: [PATCH 41/41] tests: (Jest) ignore inpage bridge file InpageBridgeWeb3.js has changed and now contains only runnable code, which is now considered as untested code by Jest. Before, most of the code was wrapped in single quotes. --- jest.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/jest.config.js b/jest.config.js index d4568dc392d..2fa170ed3bd 100644 --- a/jest.config.js +++ b/jest.config.js @@ -28,6 +28,7 @@ const config = { '/app/util/testUtils/', '/app/lib/ppom/ppom.html.js', '/app/lib/ppom/blockaid-version.js', + '/app/core/InpageBridgeWeb3.js', ], coverageReporters: ['text-summary', 'lcov'], coverageDirectory: '/tests/coverage',