mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-20 12:09:45 +01:00
Merge pull request #2671 from nextcloud/fix-trust-manager
Split different exception scopes / Use own OkHttp client for coil
This commit is contained in:
commit
4c64503cc4
@ -36,7 +36,7 @@ import com.nextcloud.talk.events.CertificateEvent
|
||||
import com.nextcloud.talk.ui.theme.ViewThemeUtils
|
||||
import com.nextcloud.talk.utils.SecurityUtils
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
||||
import com.nextcloud.talk.utils.ssl.MagicTrustManager
|
||||
import com.nextcloud.talk.utils.ssl.TrustManager
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
@ -81,7 +81,7 @@ open class BaseActivity : AppCompatActivity() {
|
||||
|
||||
fun showCertificateDialog(
|
||||
cert: X509Certificate,
|
||||
magicTrustManager: MagicTrustManager,
|
||||
trustManager: TrustManager,
|
||||
sslErrorHandler: SslErrorHandler?
|
||||
) {
|
||||
val formatter = DateFormat.getDateInstance(DateFormat.LONG)
|
||||
@ -121,7 +121,7 @@ open class BaseActivity : AppCompatActivity() {
|
||||
.setTitle(R.string.nc_certificate_dialog_title)
|
||||
.setMessage(dialogText)
|
||||
.setPositiveButton(R.string.nc_yes) { _, _ ->
|
||||
magicTrustManager.addCertInTrustStore(cert)
|
||||
trustManager.addCertInTrustStore(cert)
|
||||
sslErrorHandler?.proceed()
|
||||
}
|
||||
.setNegativeButton(R.string.nc_no) { _, _ ->
|
||||
|
@ -255,6 +255,8 @@ class NextcloudTalkApplication : MultiDexApplication(), LifecycleObserver {
|
||||
imageLoaderBuilder.logger(DebugLogger())
|
||||
}
|
||||
|
||||
imageLoaderBuilder.okHttpClient(okHttpClient)
|
||||
|
||||
return imageLoaderBuilder.build()
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,7 @@ public class ReadFilesystemOperation {
|
||||
okHttpClientBuilder.followRedirects(false);
|
||||
okHttpClientBuilder.followSslRedirects(false);
|
||||
okHttpClientBuilder.authenticator(
|
||||
new RestModule.MagicAuthenticator(
|
||||
new RestModule.HttpAuthenticator(
|
||||
ApiUtils.getCredentials(
|
||||
currentUser.getUsername(),
|
||||
currentUser.getToken()
|
||||
|
@ -40,7 +40,7 @@ import com.nextcloud.talk.components.filebrowser.models.properties.NCPreview
|
||||
import com.nextcloud.talk.components.filebrowser.models.properties.OCFavorite
|
||||
import com.nextcloud.talk.components.filebrowser.models.properties.OCId
|
||||
import com.nextcloud.talk.components.filebrowser.models.properties.OCSize
|
||||
import com.nextcloud.talk.dagger.modules.RestModule.MagicAuthenticator
|
||||
import com.nextcloud.talk.dagger.modules.RestModule.HttpAuthenticator
|
||||
import com.nextcloud.talk.data.user.model.User
|
||||
import com.nextcloud.talk.remotefilebrowser.model.RemoteFileBrowserItem
|
||||
import com.nextcloud.talk.utils.ApiUtils
|
||||
@ -61,7 +61,7 @@ class ReadFolderListingOperation(okHttpClient: OkHttpClient, currentUser: User,
|
||||
okHttpClientBuilder.followRedirects(false)
|
||||
okHttpClientBuilder.followSslRedirects(false)
|
||||
okHttpClientBuilder.authenticator(
|
||||
MagicAuthenticator(
|
||||
HttpAuthenticator(
|
||||
ApiUtils.getCredentials(
|
||||
currentUser.username,
|
||||
currentUser.token
|
||||
|
@ -64,7 +64,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ORIGINAL_PROTOCOL
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_TOKEN
|
||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USERNAME
|
||||
import com.nextcloud.talk.utils.singletons.ApplicationWideMessageHolder
|
||||
import com.nextcloud.talk.utils.ssl.MagicTrustManager
|
||||
import com.nextcloud.talk.utils.ssl.TrustManager
|
||||
import de.cotech.hw.fido.WebViewFidoBridge
|
||||
import io.reactivex.disposables.Disposable
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
@ -88,7 +88,7 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
||||
lateinit var userManager: UserManager
|
||||
|
||||
@Inject
|
||||
lateinit var magicTrustManager: MagicTrustManager
|
||||
lateinit var trustManager: TrustManager
|
||||
|
||||
@Inject
|
||||
lateinit var eventBus: EventBus
|
||||
@ -288,10 +288,10 @@ class WebViewLoginController(args: Bundle? = null) : BaseController(
|
||||
handler.cancel()
|
||||
} else {
|
||||
try {
|
||||
magicTrustManager.checkServerTrusted(arrayOf(cert), "generic")
|
||||
trustManager.checkServerTrusted(arrayOf(cert), "generic")
|
||||
handler.proceed()
|
||||
} catch (exception: CertificateException) {
|
||||
eventBus.post(CertificateEvent(cert, magicTrustManager, handler))
|
||||
eventBus.post(CertificateEvent(cert, trustManager, handler))
|
||||
}
|
||||
}
|
||||
} catch (exception: Exception) {
|
||||
|
@ -32,9 +32,9 @@ import com.nextcloud.talk.users.UserManager;
|
||||
import com.nextcloud.talk.utils.ApiUtils;
|
||||
import com.nextcloud.talk.utils.LoggingUtils;
|
||||
import com.nextcloud.talk.utils.preferences.AppPreferences;
|
||||
import com.nextcloud.talk.utils.ssl.MagicKeyManager;
|
||||
import com.nextcloud.talk.utils.ssl.MagicTrustManager;
|
||||
import com.nextcloud.talk.utils.ssl.KeyManager;
|
||||
import com.nextcloud.talk.utils.ssl.SSLSocketFactoryCompat;
|
||||
import com.nextcloud.talk.utils.ssl.TrustManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.CookieManager;
|
||||
@ -121,13 +121,13 @@ public class RestModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
MagicTrustManager provideMagicTrustManager() {
|
||||
return new MagicTrustManager();
|
||||
TrustManager provideTrustManager() {
|
||||
return new TrustManager();
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
MagicKeyManager provideKeyManager(AppPreferences appPreferences, UserManager userManager) {
|
||||
KeyManager provideKeyManager(AppPreferences appPreferences, UserManager userManager) {
|
||||
KeyStore keyStore = null;
|
||||
try {
|
||||
keyStore = KeyStore.getInstance("AndroidKeyStore");
|
||||
@ -135,7 +135,7 @@ public class RestModule {
|
||||
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
|
||||
kmf.init(keyStore, null);
|
||||
X509KeyManager origKm = (X509KeyManager) kmf.getKeyManagers()[0];
|
||||
return new MagicKeyManager(origKm, userManager, appPreferences);
|
||||
return new KeyManager(origKm, userManager, appPreferences);
|
||||
} catch (KeyStoreException e) {
|
||||
Log.e(TAG, "KeyStoreException " + e.getLocalizedMessage());
|
||||
} catch (CertificateException e) {
|
||||
@ -153,9 +153,9 @@ public class RestModule {
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
SSLSocketFactoryCompat provideSslSocketFactoryCompat(MagicKeyManager keyManager, MagicTrustManager
|
||||
magicTrustManager) {
|
||||
return new SSLSocketFactoryCompat(keyManager, magicTrustManager);
|
||||
SSLSocketFactoryCompat provideSslSocketFactoryCompat(KeyManager keyManager, TrustManager
|
||||
trustManager) {
|
||||
return new SSLSocketFactoryCompat(keyManager, trustManager);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@ -184,7 +184,7 @@ public class RestModule {
|
||||
@Singleton
|
||||
@Provides
|
||||
OkHttpClient provideHttpClient(Proxy proxy, AppPreferences appPreferences,
|
||||
MagicTrustManager magicTrustManager,
|
||||
TrustManager trustManager,
|
||||
SSLSocketFactoryCompat sslSocketFactoryCompat, Cache cache,
|
||||
CookieManager cookieManager, Dispatcher dispatcher) {
|
||||
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
|
||||
@ -198,9 +198,9 @@ public class RestModule {
|
||||
httpClient.cache(cache);
|
||||
|
||||
// Trust own CA and all self-signed certs
|
||||
httpClient.sslSocketFactory(sslSocketFactoryCompat, magicTrustManager);
|
||||
httpClient.sslSocketFactory(sslSocketFactoryCompat, trustManager);
|
||||
httpClient.retryOnConnectionFailure(true);
|
||||
httpClient.hostnameVerifier(magicTrustManager.getHostnameVerifier(OkHostnameVerifier.INSTANCE));
|
||||
httpClient.hostnameVerifier(trustManager.getHostnameVerifier(OkHostnameVerifier.INSTANCE));
|
||||
|
||||
httpClient.dispatcher(dispatcher);
|
||||
if (!Proxy.NO_PROXY.equals(proxy)) {
|
||||
@ -209,7 +209,7 @@ public class RestModule {
|
||||
if (appPreferences.getProxyCredentials() &&
|
||||
!TextUtils.isEmpty(appPreferences.getProxyUsername()) &&
|
||||
!TextUtils.isEmpty(appPreferences.getProxyPassword())) {
|
||||
httpClient.proxyAuthenticator(new MagicAuthenticator(Credentials.basic(
|
||||
httpClient.proxyAuthenticator(new HttpAuthenticator(Credentials.basic(
|
||||
appPreferences.getProxyUsername(),
|
||||
appPreferences.getProxyPassword()), "Proxy-Authorization"));
|
||||
}
|
||||
@ -253,12 +253,12 @@ public class RestModule {
|
||||
}
|
||||
}
|
||||
|
||||
public static class MagicAuthenticator implements Authenticator {
|
||||
public static class HttpAuthenticator implements Authenticator {
|
||||
|
||||
private String credentials;
|
||||
private String authenticatorType;
|
||||
|
||||
public MagicAuthenticator(@NonNull String credentials, @NonNull String authenticatorType) {
|
||||
public HttpAuthenticator(@NonNull String credentials, @NonNull String authenticatorType) {
|
||||
this.credentials = credentials;
|
||||
this.authenticatorType = authenticatorType;
|
||||
}
|
||||
|
@ -21,21 +21,23 @@
|
||||
package com.nextcloud.talk.events;
|
||||
|
||||
import android.webkit.SslErrorHandler;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.nextcloud.talk.utils.ssl.MagicTrustManager;
|
||||
|
||||
import com.nextcloud.talk.utils.ssl.TrustManager;
|
||||
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class CertificateEvent {
|
||||
private final X509Certificate x509Certificate;
|
||||
private final MagicTrustManager magicTrustManager;
|
||||
private final TrustManager trustManager;
|
||||
@Nullable
|
||||
private final SslErrorHandler sslErrorHandler;
|
||||
|
||||
public CertificateEvent(X509Certificate x509Certificate, MagicTrustManager magicTrustManager,
|
||||
public CertificateEvent(X509Certificate x509Certificate, TrustManager trustManager,
|
||||
@Nullable SslErrorHandler sslErrorHandler) {
|
||||
this.x509Certificate = x509Certificate;
|
||||
this.magicTrustManager = magicTrustManager;
|
||||
this.trustManager = trustManager;
|
||||
this.sslErrorHandler = sslErrorHandler;
|
||||
}
|
||||
|
||||
@ -48,7 +50,7 @@ public class CertificateEvent {
|
||||
return x509Certificate;
|
||||
}
|
||||
|
||||
public MagicTrustManager getMagicTrustManager() {
|
||||
return magicTrustManager;
|
||||
public TrustManager getMagicTrustManager() {
|
||||
return trustManager;
|
||||
}
|
||||
}
|
||||
|
@ -295,7 +295,7 @@ class ChunkedFileUploader(
|
||||
// okHttpClientBuilder.readTimeout(Duration.ofMinutes(30)) // TODO set timeout
|
||||
okHttpClientBuilder.protocols(listOf(Protocol.HTTP_1_1))
|
||||
okHttpClientBuilder.authenticator(
|
||||
RestModule.MagicAuthenticator(
|
||||
RestModule.HttpAuthenticator(
|
||||
ApiUtils.getCredentials(
|
||||
currentUser.username,
|
||||
currentUser.token
|
||||
|
@ -45,15 +45,15 @@ import javax.net.ssl.X509KeyManager;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
public class MagicKeyManager implements X509KeyManager {
|
||||
private static final String TAG = "MagicKeyManager";
|
||||
public class KeyManager implements X509KeyManager {
|
||||
private static final String TAG = "KeyManager";
|
||||
private final X509KeyManager keyManager;
|
||||
|
||||
private UserManager userManager;
|
||||
private AppPreferences appPreferences;
|
||||
private Context context;
|
||||
|
||||
public MagicKeyManager(X509KeyManager keyManager, UserManager userManager, AppPreferences appPreferences) {
|
||||
public KeyManager(X509KeyManager keyManager, UserManager userManager, AppPreferences appPreferences) {
|
||||
this.keyManager = keyManager;
|
||||
this.userManager = userManager;
|
||||
this.appPreferences = appPreferences;
|
@ -38,29 +38,36 @@ import java.security.KeyStoreException;
|
||||
import java.security.cert.CertificateException;
|
||||
import java.security.cert.X509Certificate;
|
||||
|
||||
import javax.net.ssl.HostnameVerifier;
|
||||
import javax.net.ssl.SSLPeerUnverifiedException;
|
||||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
|
||||
public class MagicTrustManager implements X509TrustManager {
|
||||
private static final String TAG = "MagicTrustManager";
|
||||
public class TrustManager implements X509TrustManager {
|
||||
private static final String TAG = "TrustManager";
|
||||
|
||||
private File keystoreFile;
|
||||
private X509TrustManager systemTrustManager = null;
|
||||
private KeyStore trustedKeyStore = null;
|
||||
|
||||
public MagicTrustManager() {
|
||||
keystoreFile = new File(NextcloudTalkApplication.Companion.getSharedApplication().getDir("CertsKeystore",
|
||||
Context.MODE_PRIVATE), "keystore.bks");
|
||||
|
||||
try (FileInputStream fileInputStream = new FileInputStream(keystoreFile)) {
|
||||
public TrustManager() {
|
||||
keystoreFile = new File(NextcloudTalkApplication.Companion.getSharedApplication()
|
||||
.getDir("CertsKeystore", Context.MODE_PRIVATE),
|
||||
"keystore.bks");
|
||||
try {
|
||||
trustedKeyStore = KeyStore.getInstance(KeyStore.getDefaultType());
|
||||
} catch (KeyStoreException e) {
|
||||
Log.e(TAG, "Trusted key store can't be created.", e);
|
||||
}
|
||||
|
||||
if (keystoreFile.exists()) {
|
||||
try (FileInputStream fileInputStream = new FileInputStream(keystoreFile)) {
|
||||
trustedKeyStore.load(fileInputStream, null);
|
||||
} catch (Exception exception) {
|
||||
Log.e(TAG, "Error during opening the trusted key store.", exception);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
trustedKeyStore.load(null, null);
|
||||
} catch (Exception e) {
|
||||
@ -75,7 +82,7 @@ public class MagicTrustManager implements X509TrustManager {
|
||||
|
||||
trustManagerFactory.init((KeyStore) null);
|
||||
|
||||
for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
|
||||
for (javax.net.ssl.TrustManager trustManager : trustManagerFactory.getTrustManagers()) {
|
||||
if (trustManager instanceof X509TrustManager) {
|
||||
systemTrustManager = (X509TrustManager) trustManager;
|
||||
break;
|
||||
@ -88,8 +95,8 @@ public class MagicTrustManager implements X509TrustManager {
|
||||
|
||||
}
|
||||
|
||||
public HostnameVerifier getHostnameVerifier(HostnameVerifier defaultHostNameVerifier) {
|
||||
return new MagicHostnameVerifier(defaultHostNameVerifier);
|
||||
public javax.net.ssl.HostnameVerifier getHostnameVerifier(javax.net.ssl.HostnameVerifier defaultHostNameVerifier) {
|
||||
return new HostnameVerifier(defaultHostNameVerifier);
|
||||
}
|
||||
|
||||
private boolean isCertInTrustStore(X509Certificate[] x509Certificates, String s) {
|
||||
@ -99,15 +106,15 @@ public class MagicTrustManager implements X509TrustManager {
|
||||
systemTrustManager.checkServerTrusted(x509Certificates, s);
|
||||
return true;
|
||||
} catch (CertificateException e) {
|
||||
if (!isCertInMagicTrustStore(x509Certificate)) {
|
||||
if (!isCertInTrustStore(x509Certificate)) {
|
||||
EventBus.getDefault().post(new CertificateEvent(x509Certificate, this,
|
||||
null));
|
||||
long startTime = System.currentTimeMillis();
|
||||
while (!isCertInMagicTrustStore(x509Certificate) && System.currentTimeMillis() <=
|
||||
while (!isCertInTrustStore(x509Certificate) && System.currentTimeMillis() <=
|
||||
startTime + 15000) {
|
||||
//do nothing
|
||||
}
|
||||
return isCertInMagicTrustStore(x509Certificate);
|
||||
return isCertInTrustStore(x509Certificate);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
@ -117,7 +124,7 @@ public class MagicTrustManager implements X509TrustManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCertInMagicTrustStore(X509Certificate x509Certificate) {
|
||||
private boolean isCertInTrustStore(X509Certificate x509Certificate) {
|
||||
if (trustedKeyStore != null) {
|
||||
try {
|
||||
if (trustedKeyStore.getCertificateAlias(x509Certificate) != null) {
|
||||
@ -159,11 +166,11 @@ public class MagicTrustManager implements X509TrustManager {
|
||||
return systemTrustManager.getAcceptedIssuers();
|
||||
}
|
||||
|
||||
private class MagicHostnameVerifier implements HostnameVerifier {
|
||||
private static final String TAG = "MagicHostnameVerifier";
|
||||
private HostnameVerifier defaultHostNameVerifier;
|
||||
private class HostnameVerifier implements javax.net.ssl.HostnameVerifier {
|
||||
private static final String TAG = "HostnameVerifier";
|
||||
private javax.net.ssl.HostnameVerifier defaultHostNameVerifier;
|
||||
|
||||
private MagicHostnameVerifier(HostnameVerifier defaultHostNameVerifier) {
|
||||
private HostnameVerifier(javax.net.ssl.HostnameVerifier defaultHostNameVerifier) {
|
||||
this.defaultHostNameVerifier = defaultHostNameVerifier;
|
||||
}
|
||||
|
@ -452,7 +452,7 @@ class WebSocketInstance internal constructor(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "MagicWebSocketInstance"
|
||||
private const val TAG = "WebSocketInstance"
|
||||
private const val NORMAL_CLOSURE = 1000
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user