Skip to content

Commit

Permalink
Merge branch 'develop' into new.room-permissions-actions
Browse files Browse the repository at this point in the history
  • Loading branch information
diegolmello authored Nov 30, 2020
2 parents f0dddf2 + 155fc04 commit f284d17
Show file tree
Hide file tree
Showing 23 changed files with 497 additions and 480 deletions.
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ android {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode VERSIONCODE as Integer
versionName "4.12.1"
versionName "4.13.0"
vectorDrawables.useSupportLibrary = true
if (isPlay) {
manifestPlaceholders = [BugsnagAPIKey: BugsnagAPIKey as String]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.modules.network.NetworkingModule;
import com.facebook.react.modules.network.CustomClientBuilder;
import okhttp3.OkHttpClient;
public class ReactNativeFlipper {
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
Expand All @@ -33,7 +34,7 @@ public static void initializeFlipper(Context context, ReactInstanceManager react
client.addPlugin(CrashReporterPlugin.getInstance());
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
NetworkingModule.setCustomClientBuilder(
new NetworkingModule.CustomClientBuilder() {
new CustomClientBuilder() {
@Override
public void apply(OkHttpClient.Builder builder) {
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
Expand Down
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
android:icon="@mipmap/ic_launcher"
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config"
android:requestLegacyExternalStorage="true"
android:allowBackup="false"
tools:replace="android:allowBackup"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ protected List<ReactPackage> getPackages() {
packages.add(new KeyboardInputPackage(MainApplication.this));
packages.add(new WatermelonDBPackage());
packages.add(new RNCViewPagerPackage());
packages.add(new SSLPinningPackage());
List<ReactPackage> unimodules = Arrays.<ReactPackage>asList(
new ModuleRegistryAdapter(mModuleRegistryProvider)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
package chat.rocket.reactnative;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.modules.network.NetworkingModule;
import com.facebook.react.modules.network.CustomClientBuilder;
import com.facebook.react.modules.network.ReactCookieJarContainer;
import com.facebook.react.modules.websocket.WebSocketModule;
import com.facebook.react.modules.fresco.ReactOkHttpNetworkFetcher;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.Promise;

import java.net.Socket;
import java.security.Principal;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.X509ExtendedKeyManager;
import java.security.PrivateKey;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import okhttp3.OkHttpClient;
import java.lang.InterruptedException;
import android.app.Activity;
import javax.net.ssl.KeyManager;
import android.security.KeyChain;
import android.security.KeyChainAliasCallback;
import java.util.concurrent.TimeUnit;

import com.RNFetchBlob.RNFetchBlob;

import com.reactnativecommunity.webview.RNCWebViewManager;

import com.dylanvann.fastimage.FastImageOkHttpUrlLoader;

import expo.modules.av.player.datasource.SharedCookiesDataSourceFactory;

public class SSLPinningModule extends ReactContextBaseJavaModule implements KeyChainAliasCallback {

private Promise promise;
private static String alias;
private static ReactApplicationContext reactContext;

public SSLPinningModule(ReactApplicationContext reactContext) {
super(reactContext);
this.reactContext = reactContext;
}

public class CustomClient implements CustomClientBuilder {
@Override
public void apply(OkHttpClient.Builder builder) {
if (alias != null) {
SSLSocketFactory sslSocketFactory = getSSLFactory(alias);
if (sslSocketFactory != null) {
builder.sslSocketFactory(sslSocketFactory);
}
}
}
}

protected OkHttpClient getOkHttpClient() {
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(0, TimeUnit.MILLISECONDS)
.readTimeout(0, TimeUnit.MILLISECONDS)
.writeTimeout(0, TimeUnit.MILLISECONDS)
.cookieJar(new ReactCookieJarContainer());

if (alias != null) {
SSLSocketFactory sslSocketFactory = getSSLFactory(alias);
if (sslSocketFactory != null) {
builder.sslSocketFactory(sslSocketFactory);
}
}

return builder.build();
}

@Override
public String getName() {
return "SSLPinning";
}

@Override
public void alias(String alias) {
this.alias = alias;

this.promise.resolve(alias);
}

@ReactMethod
public void setCertificate(String data, Promise promise) {
this.alias = data;

// HTTP Fetch react-native layer
NetworkingModule.setCustomClientBuilder(new CustomClient());
// Websocket react-native layer
WebSocketModule.setCustomClientBuilder(new CustomClient());
// Image networking react-native layer
ReactOkHttpNetworkFetcher.setOkHttpClient(getOkHttpClient());
// RNFetchBlob networking layer
RNFetchBlob.applyCustomOkHttpClient(getOkHttpClient());
// RNCWebView onReceivedClientCertRequest
RNCWebViewManager.setCertificateAlias(data);
// FastImage Glide network layer
FastImageOkHttpUrlLoader.setOkHttpClient(getOkHttpClient());
// Expo AV network layer
SharedCookiesDataSourceFactory.setOkHttpClient(getOkHttpClient());

promise.resolve(null);
}

@ReactMethod
public void pickCertificate(Promise promise) {
Activity activity = getCurrentActivity();

this.promise = promise;

KeyChain.choosePrivateKeyAlias(activity,
this, // Callback
null, // Any key types.
null, // Any issuers.
null, // Any host
-1, // Any port
"RocketChat");
}

public static SSLSocketFactory getSSLFactory(final String alias) {
try {
final PrivateKey privKey = KeyChain.getPrivateKey(reactContext, alias);
final X509Certificate[] certChain = KeyChain.getCertificateChain(reactContext, alias);

final X509ExtendedKeyManager keyManager = new X509ExtendedKeyManager() {
@Override
public String chooseClientAlias(String[] strings, Principal[] principals, Socket socket) {
return alias;
}

@Override
public String chooseServerAlias(String s, Principal[] principals, Socket socket) {
return alias;
}

@Override
public X509Certificate[] getCertificateChain(String s) {
return certChain;
}

@Override
public String[] getClientAliases(String s, Principal[] principals) {
return new String[]{alias};
}

@Override
public String[] getServerAliases(String s, Principal[] principals) {
return new String[]{alias};
}

@Override
public PrivateKey getPrivateKey(String s) {
return privKey;
}
};

final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}

@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}

@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return certChain;
}
}
};

final SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(new KeyManager[]{keyManager}, trustAllCerts, new java.security.SecureRandom());
SSLContext.setDefault(sslContext);

final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

return sslSocketFactory;
} catch (Exception e) {
return null;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package chat.rocket.reactnative;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import com.facebook.react.bridge.JavaScriptModule;

public class SSLPinningPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
return Arrays.<NativeModule>asList(new SSLPinningModule(reactContext));
}

@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
}
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ buildscript {
minSdkVersion = 23
compileSdkVersion = 29
targetSdkVersion = 29
glideVersion = "4.9.0"
glideVersion = "4.11.0"
kotlin_version = "1.3.50"
supportLibVersion = "28.0.0"
libre_build = !(isPlay.toBoolean())
Expand Down
3 changes: 1 addition & 2 deletions app/actions/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,10 @@ export function selectServerFailure() {
};
}

export function serverRequest(server, certificate = null, username = null, fromServerHistory = false) {
export function serverRequest(server, username = null, fromServerHistory = false) {
return {
type: SERVER.REQUEST,
server,
certificate,
username,
fromServerHistory
};
Expand Down
10 changes: 10 additions & 0 deletions app/lib/rocketchat.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import database from './database';
import log from '../utils/log';
import { isIOS, getBundleId } from '../utils/deviceInfo';
import fetch from '../utils/fetch';
import SSLPinning from '../utils/sslPinning';

import { encryptionInit } from '../actions/encryption';
import { setUser, setLoginServices, loginRequest } from '../actions/login';
Expand Down Expand Up @@ -63,6 +64,7 @@ import { sanitizeLikeString } from './database/utils';
const TOKEN_KEY = 'reactnativemeteor_usertoken';
const CURRENT_SERVER = 'currentServer';
const SORT_PREFS_KEY = 'RC_SORT_PREFS_KEY';
const CERTIFICATE_KEY = 'RC_CERTIFICATE_KEY';
export const THEME_PREFERENCES_KEY = 'RC_THEME_PREFERENCES_KEY';
export const CRASH_REPORT_KEY = 'RC_CRASH_REPORT_KEY';
export const ANALYTICS_EVENTS_KEY = 'RC_ANALYTICS_EVENTS_KEY';
Expand All @@ -74,6 +76,7 @@ const STATUSES = ['offline', 'online', 'away', 'busy'];
const RocketChat = {
TOKEN_KEY,
CURRENT_SERVER,
CERTIFICATE_KEY,
callJitsi,
async subscribeRooms() {
if (!this.roomsSub) {
Expand Down Expand Up @@ -312,6 +315,13 @@ const RocketChat = {
async shareExtensionInit(server) {
database.setShareDB(server);

try {
const certificate = await UserPreferences.getStringAsync(`${ RocketChat.CERTIFICATE_KEY }-${ server }`);
await SSLPinning.setCertificate(certificate, server);
} catch {
// Do nothing
}

if (this.shareSDK) {
this.shareSDK.disconnect();
this.shareSDK = null;
Expand Down
16 changes: 9 additions & 7 deletions app/sagas/selectServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import { setUser } from '../actions/login';
import RocketChat from '../lib/rocketchat';
import database from '../lib/database';
import log, { logServerVersion } from '../utils/log';
import { extractHostname } from '../utils/server';
import I18n from '../i18n';
import { BASIC_AUTH_KEY, setBasicAuth } from '../utils/fetch';
import { appStart, ROOT_INSIDE, ROOT_OUTSIDE } from '../actions/app';
import UserPreferences from '../lib/userPreferences';
import { encryptionStop } from '../actions/encryption';
import SSLPinning from '../utils/sslPinning';

import { inquiryReset } from '../ee/omnichannel/actions/inquiry';

Expand Down Expand Up @@ -68,6 +68,10 @@ const getServerInfo = function* getServerInfo({ server, raiseError = true }) {

const handleSelectServer = function* handleSelectServer({ server, version, fetchVersion }) {
try {
// SSL Pinning - Read certificate alias and set it to be used by network requests
const certificate = yield UserPreferences.getStringAsync(`${ RocketChat.CERTIFICATE_KEY }-${ server }`);
yield SSLPinning.setCertificate(certificate, server);

yield put(inquiryReset());
yield put(encryptionStop());
const serversDB = database.servers;
Expand Down Expand Up @@ -138,13 +142,11 @@ const handleSelectServer = function* handleSelectServer({ server, version, fetch
}
};

const handleServerRequest = function* handleServerRequest({
server, certificate, username, fromServerHistory
}) {
const handleServerRequest = function* handleServerRequest({ server, username, fromServerHistory }) {
try {
if (certificate) {
yield UserPreferences.setMapAsync(extractHostname(server), certificate);
}
// SSL Pinning - Read certificate alias and set it to be used by network requests
const certificate = yield UserPreferences.getStringAsync(`${ RocketChat.CERTIFICATE_KEY }-${ server }`);
yield SSLPinning.setCertificate(certificate, server);

const serverInfo = yield getServerInfo({ server });
const serversDB = database.servers;
Expand Down
Binary file modified app/static/images/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit f284d17

Please sign in to comment.