Merge request changes

- Moved certificate-related utilities to separate class

- Added settings method to return an entire SSLSettings object; refactored
  methods using separate parameters to take single SSLSettings parameter

- Advanced Settings section on login page now hides / shows along with
  other buttons to prevent it from showing up in front of the loading
  spinner

- Fixed star imports

- Refactored applySslSettings as per code from merge request

- Fixed formatting
This commit is contained in:
Galen Abell
2018-11-08 17:43:12 -05:00
parent 2d14ef1b6f
commit 8e2d90ef50
10 changed files with 274 additions and 209 deletions

View File

@@ -1,6 +1,5 @@
package com.github.gotify;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -15,22 +14,12 @@ import com.github.gotify.log.Log;
import com.google.android.material.snackbar.Snackbar;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import okhttp3.OkHttpClient;
import okio.Buffer;
import org.threeten.bp.OffsetDateTime;
import javax.net.ssl.*;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.io.InputStream;
import java.util.Collection;
import java.io.InputStreamReader;
import okio.Buffer;
import org.threeten.bp.OffsetDateTime;
public class Utils {
public static void showSnackBar(Activity activity, String message) {
@@ -66,17 +55,6 @@ public class Utils {
return new ApiClient().getJSON();
}
public interface DrawableReceiver {
void loaded(Drawable drawable);
}
public static InputStream stringToInputStream(String str) {
if (str == null) return null;
return new Buffer()
.writeUtf8(str)
.inputStream();
}
public static String readFileFromStream(@NonNull InputStream inputStream) {
StringBuilder sb = new StringBuilder();
String currentLine;
@@ -92,87 +70,12 @@ public class Utils {
return sb.toString();
}
/////////////////////////
///// SSL Utilities /////
/////////////////////////
public static Certificate parseCertificate(String cert) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
return certificateFactory.generateCertificate(Utils.stringToInputStream(cert));
} catch (Exception e) {
throw new IllegalArgumentException("certificate is invalid");
}
public interface DrawableReceiver {
void loaded(Drawable drawable);
}
public static class SSLSettings {
boolean validateSSL;
String cert;
public SSLSettings(boolean validateSSL, String cert) {
this.validateSSL = validateSSL;
this.cert = cert;
}
}
// TrustManager that trusts all SSL Certs
private static final TrustManager trustAll = new X509TrustManager() {
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@SuppressLint("TrustAllX509TrustManager")
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
@Override
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
};
public static void applySslSettings(OkHttpClient.Builder builder, SSLSettings settings) {
// Modified from ApiClient.applySslSettings in the client package.
try {
TrustManager[] trustManagers = null;
HostnameVerifier hostnameVerifier = null;
if (!settings.validateSSL) {
trustManagers = new TrustManager[]{ trustAll };
hostnameVerifier = (hostname, session) -> true;
} else if (settings.cert != null) {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(stringToInputStream(settings.cert));
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
KeyStore caKeyStore = newEmptyKeyStore();
int index = 0;
for (Certificate certificate : certificates) {
String certificateAlias = "ca" + Integer.toString(index++);
caKeyStore.setCertificateEntry(certificateAlias, certificate);
}
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(caKeyStore);
trustManagers = trustManagerFactory.getTrustManagers();
}
if (trustManagers != null && trustManagers.length > 0) {
SSLContext context = SSLContext.getInstance("TLS");
context.init(new KeyManager[]{}, trustManagers, new SecureRandom());
builder.sslSocketFactory(context.getSocketFactory(), (X509TrustManager) trustManagers[0]);
}
if (hostnameVerifier != null) builder.hostnameVerifier(hostnameVerifier);
} catch (Exception e) {
// We shouldn't have issues since the cert is verified on login.
Log.e("Failed to apply SSL settings", e);
}
}
private static KeyStore newEmptyKeyStore() throws GeneralSecurityException {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
return keyStore;
} catch (IOException e) {
throw new AssertionError(e);
}
public static InputStream stringToInputStream(String str) {
if (str == null) return null;
return new Buffer().writeUtf8(str).inputStream();
}
}