Rocket.Chat.ReactNative/patches/react-native+0.71.7.patch

473 lines
19 KiB
Diff

diff --git a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
index 175865d..c1cabef 100644
--- a/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
+++ b/node_modules/react-native/Libraries/Components/TextInput/TextInput.js
@@ -956,6 +956,7 @@ export type Props = $ReadOnly<{|
type ImperativeMethods = $ReadOnly<{|
clear: () => void,
+ setTextAndSelection: () => void,
isFocused: () => boolean,
getNativeRef: () => ?React.ElementRef<HostComponent<mixed>>,
setSelection: (start: number, end: number) => void,
@@ -1214,6 +1215,18 @@ function InternalTextInput(props: Props): React.Node {
}
}
+ function setTextAndSelection(_text, _selection): void {
+ if (inputRef.current != null) {
+ viewCommands.setTextAndSelection(
+ inputRef.current,
+ mostRecentEventCount,
+ _text,
+ _selection?.start ?? -1,
+ _selection?.end ?? -1,
+ );
+ }
+ }
+
// TODO: Fix this returning true on null === null, when no input is focused
function isFocused(): boolean {
return TextInputState.currentlyFocusedInput() === inputRef.current;
@@ -1252,6 +1265,7 @@ function InternalTextInput(props: Props): React.Node {
*/
if (ref) {
ref.clear = clear;
+ ref.setTextAndSelection = setTextAndSelection;
ref.isFocused = isFocused;
ref.getNativeRef = getNativeRef;
ref.setSelection = setSelection;
diff --git a/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm b/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm
index b7b2db1..baf5b3c 100644
--- a/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm
+++ b/node_modules/react-native/Libraries/Network/RCTHTTPRequestHandler.mm
@@ -8,11 +8,13 @@
#import <React/RCTHTTPRequestHandler.h>
#import <mutex>
-
+#import <MMKV/MMKV.h>
#import <React/RCTNetworking.h>
#import <ReactCommon/RCTTurboModule.h>
+#import <SDWebImage/SDWebImageDownloader.h>
#import "RCTNetworkPlugins.h"
+#import "SecureStorage.h"
@interface RCTHTTPRequestHandler () <NSURLSessionDataDelegate, RCTTurboModule>
@@ -64,6 +66,102 @@ - (BOOL)canHandleRequest:(NSURLRequest *)request
return [schemes containsObject:request.URL.scheme.lowercaseString];
}
+-(NSURLCredential *)getUrlCredential:(NSURLAuthenticationChallenge *)challenge path:(NSString *)path password:(NSString *)password
+{
+ NSString *authMethod = [[challenge protectionSpace] authenticationMethod];
+ SecTrustRef serverTrust = challenge.protectionSpace.serverTrust;
+
+ if ([authMethod isEqualToString:NSURLAuthenticationMethodServerTrust] || path == nil || password == nil) {
+ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
+ } else if (path && password) {
+ NSMutableArray *policies = [NSMutableArray array];
+ [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)challenge.protectionSpace.host)];
+ SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
+
+ SecTrustResultType result;
+ SecTrustEvaluate(serverTrust, &result);
+
+ if (![[NSFileManager defaultManager] fileExistsAtPath:path])
+ {
+ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
+ }
+
+ NSData *p12data = [NSData dataWithContentsOfFile:path];
+ NSDictionary* options = @{ (id)kSecImportExportPassphrase:password };
+ CFArrayRef rawItems = NULL;
+ OSStatus status = SecPKCS12Import((__bridge CFDataRef)p12data,
+ (__bridge CFDictionaryRef)options,
+ &rawItems);
+
+ if (status != noErr) {
+ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
+ }
+
+ NSArray* items = (NSArray*)CFBridgingRelease(rawItems);
+ NSDictionary* firstItem = nil;
+ if ((status == errSecSuccess) && ([items count]>0)) {
+ firstItem = items[0];
+ }
+
+ SecIdentityRef identity = (SecIdentityRef)CFBridgingRetain(firstItem[(id)kSecImportItemIdentity]);
+ SecCertificateRef certificate = NULL;
+ if (identity) {
+ SecIdentityCopyCertificate(identity, &certificate);
+ if (certificate) { CFRelease(certificate); }
+ }
+
+ NSMutableArray *certificates = [[NSMutableArray alloc] init];
+ [certificates addObject:CFBridgingRelease(certificate)];
+
+ [SDWebImageDownloader sharedDownloader].config.urlCredential = [NSURLCredential credentialWithIdentity:identity certificates:certificates persistence:NSURLCredentialPersistenceNone];
+
+ return [NSURLCredential credentialWithIdentity:identity certificates:certificates persistence:NSURLCredentialPersistenceNone];
+ }
+
+ return [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
+}
+
+- (NSString *)stringToHex:(NSString *)string
+{
+ char *utf8 = (char *)[string UTF8String];
+ NSMutableString *hex = [NSMutableString string];
+ while (*utf8) [hex appendFormat:@"%02X", *utf8++ & 0x00FF];
+
+ return [[NSString stringWithFormat:@"%@", hex] lowercaseString];
+}
+
+-(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
+
+ NSString *host = challenge.protectionSpace.host;
+
+ // Read the clientSSL info from MMKV
+ __block NSString *clientSSL;
+ SecureStorage *secureStorage = [[SecureStorage alloc] init];
+
+ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31
+ NSString *key = [secureStorage getSecureKey:[self stringToHex:@"com.MMKV.default"]];
+ NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
+
+ if (key == NULL) {
+ return completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, credential);
+ }
+
+ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding];
+ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess];
+ clientSSL = [mmkv getStringForKey:host];
+
+ if (clientSSL) {
+ NSData *data = [clientSSL dataUsingEncoding:NSUTF8StringEncoding];
+ id dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+ NSString *path = [dict objectForKey:@"path"];
+ NSString *password = [dict objectForKey:@"password"];
+ credential = [self getUrlCredential:challenge path:path password:password];
+ }
+
+ completionHandler(NSURLSessionAuthChallengeUseCredential, credential);
+}
+
+
- (NSURLSessionDataTask *)sendRequest:(NSURLRequest *)request withDelegate:(id<RCTURLRequestDelegate>)delegate
{
std::lock_guard<std::mutex> lock(_mutex);
diff --git a/node_modules/react-native/Libraries/WebSocket/RCTSRWebSocket.m b/node_modules/react-native/Libraries/WebSocket/RCTSRWebSocket.m
index 925596f..d23e727 100644
--- a/node_modules/react-native/Libraries/WebSocket/RCTSRWebSocket.m
+++ b/node_modules/react-native/Libraries/WebSocket/RCTSRWebSocket.m
@@ -24,6 +24,9 @@
#import <React/RCTAssert.h>
#import <React/RCTLog.h>
+#import <MMKV/MMKV.h>
+#import "SecureStorage.h"
+
typedef NS_ENUM(NSInteger, RCTSROpCode) {
RCTSROpCodeTextFrame = 0x1,
RCTSROpCodeBinaryFrame = 0x2,
@@ -513,6 +516,38 @@ - (void)didConnect
[self _readHTTPHeader];
}
+- (void)setClientSSL:(NSString *)path password:(NSString *)password options:(NSMutableDictionary *)options;
+{
+ if ([[NSFileManager defaultManager] fileExistsAtPath:path])
+ {
+ NSData *pkcs12data = [[NSData alloc] initWithContentsOfFile:path];
+ NSDictionary* certOptions = @{ (id)kSecImportExportPassphrase:password };
+ CFArrayRef keyref = NULL;
+ OSStatus sanityChesk = SecPKCS12Import((__bridge CFDataRef)pkcs12data,
+ (__bridge CFDictionaryRef)certOptions,
+ &keyref);
+ if (sanityChesk == noErr) {
+ CFDictionaryRef identityDict = CFArrayGetValueAtIndex(keyref, 0);
+ SecIdentityRef identityRef = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
+ SecCertificateRef cert = NULL;
+ OSStatus status = SecIdentityCopyCertificate(identityRef, &cert);
+ if (!status) {
+ NSArray *certificates = [[NSArray alloc] initWithObjects:(__bridge id)identityRef, (__bridge id)cert, nil];
+ [options setObject:certificates forKey:(NSString *)kCFStreamSSLCertificates];
+ }
+ }
+ }
+}
+
+- (NSString *)stringToHex:(NSString *)string
+{
+ char *utf8 = (char *)[string UTF8String];
+ NSMutableString *hex = [NSMutableString string];
+ while (*utf8) [hex appendFormat:@"%02X", *utf8++ & 0x00FF];
+
+ return [[NSString stringWithFormat:@"%@", hex] lowercaseString];
+}
+
- (void)_initializeStreams
{
assert(_url.port.unsignedIntValue <= UINT32_MAX);
@@ -550,6 +585,26 @@ - (void)_initializeStreams
RCTLogInfo(@"SocketRocket: In debug mode. Allowing connection to any root cert");
#endif
+ // Read the clientSSL info from MMKV
+ __block NSString *clientSSL;
+ SecureStorage *secureStorage = [[SecureStorage alloc] init];
+
+ // https://github.com/ammarahm-ed/react-native-mmkv-storage/blob/master/src/loader.js#L31
+ NSString *key = [secureStorage getSecureKey:[self stringToHex:@"com.MMKV.default"]];
+
+ if (key != NULL) {
+ NSData *cryptKey = [key dataUsingEncoding:NSUTF8StringEncoding];
+ MMKV *mmkv = [MMKV mmkvWithID:@"default" cryptKey:cryptKey mode:MMKVMultiProcess];
+ clientSSL = [mmkv getStringForKey:host];
+ if (clientSSL) {
+ NSData *data = [clientSSL dataUsingEncoding:NSUTF8StringEncoding];
+ id dict = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
+ NSString *path = [dict objectForKey:@"path"];
+ NSString *password = [dict objectForKey:@"password"];
+ [self setClientSSL:path password:password options:SSLOptions];
+ }
+ }
+
[_outputStream setProperty:SSLOptions forKey:(__bridge id)kCFStreamPropertySSLSettings];
}
@@ -634,6 +689,7 @@ - (void)closeWithCode:(NSInteger)code reason:(NSString *)reason
}
}
+ [self.delegate webSocket:self didCloseWithCode:code reason:reason wasClean:YES];
[self _sendFrameWithOpcode:RCTSROpCodeConnectionClose data:payload];
});
}
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/ReactOkHttpNetworkFetcher.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/ReactOkHttpNetworkFetcher.java
index 18a7ce9..9644a5b 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/ReactOkHttpNetworkFetcher.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/fresco/ReactOkHttpNetworkFetcher.java
@@ -22,11 +22,25 @@ import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;
-class ReactOkHttpNetworkFetcher extends OkHttpNetworkFetcher {
+import android.os.Looper;
+import com.facebook.imagepipeline.common.BytesRange;
+import com.facebook.imagepipeline.image.EncodedImage;
+import com.facebook.imagepipeline.producers.BaseNetworkFetcher;
+import com.facebook.imagepipeline.producers.BaseProducerContextCallbacks;
+import com.facebook.imagepipeline.producers.Consumer;
+import com.facebook.imagepipeline.producers.FetchState;
+import com.facebook.imagepipeline.producers.ProducerContext;
+import java.io.IOException;
+import javax.annotation.Nullable;
+import okhttp3.Call;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+public class ReactOkHttpNetworkFetcher extends OkHttpNetworkFetcher {
private static final String TAG = "ReactOkHttpNetworkFetcher";
- private final OkHttpClient mOkHttpClient;
+ private static OkHttpClient mOkHttpClient;
private final Executor mCancellationExecutor;
/** @param okHttpClient client to use */
@@ -36,6 +50,10 @@ class ReactOkHttpNetworkFetcher extends OkHttpNetworkFetcher {
mCancellationExecutor = okHttpClient.dispatcher().executorService();
}
+ public static void setOkHttpClient(OkHttpClient okHttpClient) {
+ mOkHttpClient = okHttpClient;
+ }
+
private Map<String, String> getHeaders(ReadableMap readableMap) {
if (readableMap == null) {
return null;
@@ -75,4 +93,88 @@ class ReactOkHttpNetworkFetcher extends OkHttpNetworkFetcher {
fetchWithRequest(fetchState, callback, request);
}
+
+ @Override
+ protected void fetchWithRequest(
+ final OkHttpNetworkFetchState fetchState,
+ final NetworkFetcher.Callback callback,
+ final Request request) {
+ final Call call = mOkHttpClient.newCall(request);
+
+ fetchState
+ .getContext()
+ .addCallbacks(
+ new BaseProducerContextCallbacks() {
+ @Override
+ public void onCancellationRequested() {
+ if (Looper.myLooper() != Looper.getMainLooper()) {
+ call.cancel();
+ } else {
+ mCancellationExecutor.execute(
+ new Runnable() {
+ @Override
+ public void run() {
+ call.cancel();
+ }
+ });
+ }
+ }
+ });
+
+ call.enqueue(
+ new okhttp3.Callback() {
+ @Override
+ public void onResponse(Call call, Response response) throws IOException {
+ fetchState.responseTime = SystemClock.elapsedRealtime();
+ final ResponseBody body = response.body();
+ try {
+ if (!response.isSuccessful()) {
+ handleException(
+ call, new IOException("Unexpected HTTP code " + response), callback);
+ return;
+ }
+
+ BytesRange responseRange =
+ BytesRange.fromContentRangeHeader(response.header("Content-Range"));
+ if (responseRange != null
+ && !(responseRange.from == 0
+ && responseRange.to == BytesRange.TO_END_OF_CONTENT)) {
+ // Only treat as a partial image if the range is not all of the content
+ fetchState.setResponseBytesRange(responseRange);
+ fetchState.setOnNewResultStatusFlags(Consumer.IS_PARTIAL_RESULT);
+ }
+
+ long contentLength = body.contentLength();
+ if (contentLength < 0) {
+ contentLength = 0;
+ }
+ callback.onResponse(body.byteStream(), (int) contentLength);
+ } catch (Exception e) {
+ handleException(call, e, callback);
+ } finally {
+ body.close();
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, IOException e) {
+ handleException(call, e, callback);
+ }
+ });
+ }
+
+ /**
+ * Handles exceptions.
+ *
+ * <p>OkHttp notifies callers of cancellations via an IOException. If IOException is caught after
+ * request cancellation, then the exception is interpreted as successful cancellation and
+ * onCancellation is called. Otherwise onFailure is called.
+ */
+ private void handleException(final Call call, final Exception e, final Callback callback) {
+ if (call.isCanceled()) {
+ callback.onCancellation();
+ } else {
+ callback.onFailure(e);
+ }
+ }
}
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/CustomClientBuilder.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/CustomClientBuilder.java
new file mode 100644
index 0000000..db81d65
--- /dev/null
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/CustomClientBuilder.java
@@ -0,0 +1,14 @@
+/*
+ * Copyright (c) Facebook, Inc. and its affiliates.
+ *
+ * This source code is licensed under the MIT license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+package com.facebook.react.modules.network;
+
+import okhttp3.OkHttpClient;
+
+public interface CustomClientBuilder {
+ public void apply(OkHttpClient.Builder builder);
+}
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
index f80b1c6..49b649e 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/network/NetworkingModule.java
@@ -170,10 +170,6 @@ public final class NetworkingModule extends NativeNetworkingAndroidSpec {
customClientBuilder = ccb;
}
- public static interface CustomClientBuilder {
- public void apply(OkHttpClient.Builder builder);
- }
-
private static void applyCustomBuilder(OkHttpClient.Builder builder) {
if (customClientBuilder != null) {
customClientBuilder.apply(builder);
diff --git a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
index 50e6f9d..280e604 100644
--- a/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
+++ b/node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/websocket/WebSocketModule.java
@@ -21,6 +21,8 @@ import com.facebook.react.common.ReactConstants;
import com.facebook.react.module.annotations.ReactModule;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.modules.network.ForwardingCookieHandler;
+import com.facebook.react.modules.network.OkHttpClientProvider;
+import com.facebook.react.modules.network.CustomClientBuilder;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
@@ -53,11 +55,23 @@ public final class WebSocketModule extends NativeWebSocketModuleSpec {
private ForwardingCookieHandler mCookieHandler;
+ private static @Nullable CustomClientBuilder customClientBuilder = null;
+
public WebSocketModule(ReactApplicationContext context) {
super(context);
mCookieHandler = new ForwardingCookieHandler(context);
}
+ public static void setCustomClientBuilder(CustomClientBuilder ccb) {
+ customClientBuilder = ccb;
+ }
+
+ private static void applyCustomBuilder(OkHttpClient.Builder builder) {
+ if (customClientBuilder != null) {
+ customClientBuilder.apply(builder);
+ }
+ }
+
@Override
public void invalidate() {
for (WebSocket socket : mWebSocketConnections.values()) {
@@ -96,12 +110,15 @@ public final class WebSocketModule extends NativeWebSocketModuleSpec {
@Nullable final ReadableMap options,
final double socketID) {
final int id = (int) socketID;
- OkHttpClient client =
+ OkHttpClient.Builder clientBuilder =
new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
- .readTimeout(0, TimeUnit.MINUTES) // Disable timeouts for read
- .build();
+ .readTimeout(0, TimeUnit.MINUTES); // Disable timeouts for read
+
+ applyCustomBuilder(clientBuilder);
+
+ OkHttpClient client = clientBuilder.build();
Request.Builder builder = new Request.Builder().tag(id).url(url);