mirror of
https://github.com/syncthing/syncthing-android.git
synced 2024-12-03 17:51:17 +00:00
Enable TLS for the WebGUI
This commit is contained in:
parent
c7cdfa1ff2
commit
8f2fe9955a
3 changed files with 91 additions and 2 deletions
|
@ -1,3 +1,8 @@
|
||||||
# Fix appcompat-v7 v21.0.0 causing crash on Samsung devices with Android v4.2.2 (https://code.google.com/p/android/issues/detail?id=78377)
|
# Fix appcompat-v7 v21.0.0 causing crash on Samsung devices with Android v4.2.2 (https://code.google.com/p/android/issues/detail?id=78377)
|
||||||
-keep class !android.support.v7.internal.view.menu.MenuBuilder, !android.support.v7.internal.view.menu.SubMenuBuilder, android.support.v7.** { *; }
|
-keep class !android.support.v7.internal.view.menu.MenuBuilder, !android.support.v7.internal.view.menu.SubMenuBuilder, android.support.v7.** { *; }
|
||||||
-keep interface android.support.v7.** { *; }
|
-keep interface android.support.v7.** { *; }
|
||||||
|
|
||||||
|
# Enable reflective access to mX509Certificate
|
||||||
|
-keepclassmembers class android.net.http.SslCertificate {
|
||||||
|
private final X509Certificate mX509Certificate;
|
||||||
|
}
|
||||||
|
|
|
@ -2,30 +2,82 @@ package com.nutomic.syncthingandroid.activities;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.net.http.SslCertificate;
|
||||||
|
import android.net.http.SslError;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.webkit.SslErrorHandler;
|
||||||
import android.webkit.WebView;
|
import android.webkit.WebView;
|
||||||
import android.webkit.WebViewClient;
|
import android.webkit.WebViewClient;
|
||||||
import android.widget.ProgressBar;
|
import android.widget.ProgressBar;
|
||||||
|
|
||||||
import com.nutomic.syncthingandroid.R;
|
import com.nutomic.syncthingandroid.R;
|
||||||
|
import com.nutomic.syncthingandroid.syncthing.RestApi;
|
||||||
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
import com.nutomic.syncthingandroid.syncthing.SyncthingService;
|
||||||
|
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
import java.security.NoSuchProviderException;
|
||||||
|
import java.security.SignatureException;
|
||||||
|
import java.security.cert.CertificateException;
|
||||||
|
import java.security.cert.CertificateFactory;
|
||||||
|
import java.security.cert.X509Certificate;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds a WebView that shows the web ui of the local syncthing instance.
|
* Holds a WebView that shows the web ui of the local syncthing instance.
|
||||||
*/
|
*/
|
||||||
public class WebGuiActivity extends SyncthingActivity implements SyncthingService.OnWebGuiAvailableListener {
|
public class WebGuiActivity extends SyncthingActivity
|
||||||
|
implements SyncthingService.OnWebGuiAvailableListener {
|
||||||
|
|
||||||
|
private static final String TAG = "WebGuiActivity";
|
||||||
|
|
||||||
private WebView mWebView;
|
private WebView mWebView;
|
||||||
|
|
||||||
private View mLoadingView;
|
private View mLoadingView;
|
||||||
|
|
||||||
|
private X509Certificate mCaCert;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides the loading screen and shows the WebView once it is fully loaded.
|
* Hides the loading screen and shows the WebView once it is fully loaded.
|
||||||
*/
|
*/
|
||||||
private final WebViewClient mWebViewClient = new WebViewClient() {
|
private final WebViewClient mWebViewClient = new WebViewClient() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Catch (self-signed) SSL errors and test if they correspond to Syncthing's certificate.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onReceivedSslError (WebView view, SslErrorHandler handler, SslError error) {
|
||||||
|
try {
|
||||||
|
// Uses reflection to access the private mX509Certificate field of SslCertificate
|
||||||
|
SslCertificate sslCert = error.getCertificate();
|
||||||
|
Field f = sslCert.getClass().getDeclaredField("mX509Certificate");
|
||||||
|
f.setAccessible(true);
|
||||||
|
X509Certificate cert = (X509Certificate)f.get(sslCert);
|
||||||
|
if (cert == null) {
|
||||||
|
Log.w(TAG, "X509Certificate reference invalid");
|
||||||
|
handler.cancel();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cert.verify(mCaCert.getPublicKey());
|
||||||
|
handler.proceed();
|
||||||
|
} catch (NoSuchFieldException|IllegalAccessException|CertificateException|
|
||||||
|
NoSuchAlgorithmException|InvalidKeyException|NoSuchProviderException|
|
||||||
|
SignatureException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
handler.cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPageFinished(WebView view, String url) {
|
public void onPageFinished(WebView view, String url) {
|
||||||
mWebView.setVisibility(View.VISIBLE);
|
mWebView.setVisibility(View.VISIBLE);
|
||||||
|
@ -50,6 +102,8 @@ public class WebGuiActivity extends SyncthingActivity implements SyncthingServic
|
||||||
ProgressBar pb = (ProgressBar) mLoadingView.findViewById(R.id.progress);
|
ProgressBar pb = (ProgressBar) mLoadingView.findViewById(R.id.progress);
|
||||||
pb.setIndeterminate(true);
|
pb.setIndeterminate(true);
|
||||||
|
|
||||||
|
loadCaCert();
|
||||||
|
|
||||||
mWebView = (WebView) findViewById(R.id.webview);
|
mWebView = (WebView) findViewById(R.id.webview);
|
||||||
mWebView.getSettings().setJavaScriptEnabled(true);
|
mWebView.getSettings().setJavaScriptEnabled(true);
|
||||||
mWebView.setWebViewClient(mWebViewClient);
|
mWebView.setWebViewClient(mWebViewClient);
|
||||||
|
@ -63,10 +117,36 @@ public class WebGuiActivity extends SyncthingActivity implements SyncthingServic
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads and shows WebView, hides loading view.
|
* Loads and shows WebView, hides loading view.
|
||||||
|
*
|
||||||
|
* Sets the X-API-Key (HEADER_API_KEY) header for authorization
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void onWebGuiAvailable() {
|
public void onWebGuiAvailable() {
|
||||||
mWebView.loadUrl(getService().getWebGuiUrl());
|
Map<String, String> extraHeaders = new HashMap<>();
|
||||||
|
extraHeaders.put(RestApi.HEADER_API_KEY, getService().getApi().getApiKey());
|
||||||
|
mWebView.loadUrl(getService().getWebGuiUrl(), extraHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the SyncthingService.HTTPS_CERT_FILE Ca Cert key and loads it in memory
|
||||||
|
*/
|
||||||
|
private void loadCaCert() {
|
||||||
|
InputStream inStream = null;
|
||||||
|
try {
|
||||||
|
String httpsCertPath = getFilesDir() + "/" + SyncthingService.HTTPS_CERT_FILE;
|
||||||
|
inStream = new FileInputStream(httpsCertPath);
|
||||||
|
CertificateFactory cf = CertificateFactory.getInstance("X.509");
|
||||||
|
mCaCert = (X509Certificate)
|
||||||
|
cf.generateCertificate(inStream);
|
||||||
|
} catch (FileNotFoundException|CertificateException e) {
|
||||||
|
throw new IllegalArgumentException("Untrusted Certificate");
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (inStream != null)
|
||||||
|
inStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Log.w(TAG, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -953,4 +953,8 @@ public class RestApi implements SyncthingService.OnWebGuiAvailableListener,
|
||||||
return new Device();
|
return new Device();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getApiKey() {
|
||||||
|
return mApiKey;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue