Skip to content

Commit

Permalink
[TIMOB-25755] Android: Allow WebView to support certificate requests (#…
Browse files Browse the repository at this point in the history
…9882)

* [TIMOB-25755] Allow WebView to support certificate requests

* [TIMOB-25755] Fix imports

* [TIMOB-25755] Fix UI module dependency
  • Loading branch information
garymathews authored and sgtcoolguy committed May 23, 2018
1 parent 07fd7dc commit 481f561
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 6 deletions.
2 changes: 1 addition & 1 deletion android/dependency.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
{
"android":["jaxen-1.1.1.jar","ti-commons-codec-1.3.jar","kroll-common.jar","titanium.jar","filesystem.jar","android-support-multidex.jar"],
"xml":["jaxen-1.1.1.jar"],
"ui":["nineoldandroids-appc-2.4.0.jar"],
"ui":["nineoldandroids-appc-2.4.0.jar", "WebViewClient.jar"],
"appcompat":["android-support-v4.jar", "android-support-v7-appcompat.jar", "android-support-animated-vector-drawable.jar", "android-support-annotations.jar", "android-support-core-ui.jar", "android-support-core-utils.jar", "android-support-fragment.jar", "android-support-media-compat.jar", "android-support-vector-drawable.jar", "android-support-transition.jar", "android-support-v7-recyclerview.jar", "android-arch-lifecycle-viewmodel.jar", "android-arch-lifecycle-livedata-core.jar", "android-arch-lifecycle-common.jar", "android-arch-core-runtime.jar", "android-arch-core-common.jar", "android-arch-lifecycle-runtime.jar", "exifinterface.jar"],
"cardview":["android-support-v7-cardview.jar"],
"compat":["android-support-compat.jar"],
Expand Down
Binary file added android/modules/ui/lib/WebViewClient.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -307,8 +307,12 @@ public TiUIWebView(TiViewProxy proxy)
}
}

TiWebView webView =
isHTCSenseDevice() ? new TiWebView(proxy.getActivity()) : new NonHTCWebView(proxy.getActivity());
TiWebView webView = null;
try {
webView = isHTCSenseDevice() ? new TiWebView(proxy.getActivity()) : new NonHTCWebView(proxy.getActivity());
} catch (Exception e) {
// silence unnecessary internal logs...
}
webView.setVerticalScrollbarOverlay(true);

WebSettings settings = webView.getSettings();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,38 @@
package ti.modules.titanium.ui.widget.webview;

import org.appcelerator.kroll.KrollDict;
import org.appcelerator.kroll.KrollProxy;
import org.appcelerator.kroll.common.Log;
import org.appcelerator.titanium.TiApplication;
import org.appcelerator.titanium.TiC;
import org.appcelerator.titanium.util.TiConvert;

import ti.modules.titanium.media.TiVideoActivity;
import ti.modules.titanium.ui.WebViewProxy;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.net.Uri;
import android.net.http.SslError;
import android.os.AsyncTask;
import android.os.Build;
import android.security.KeyChain;
import android.security.KeyChainAliasCallback;
import android.webkit.ClientCertRequest;
import android.webkit.ClientCertRequestHandler;
import android.webkit.HttpAuthHandler;
import android.webkit.MimeTypeMap;
import android.webkit.SslErrorHandler;
import android.webkit.URLUtil;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.webkit.WebViewClientClassicExt;

import java.security.PrivateKey;
import java.security.cert.X509Certificate;

public class TiWebViewClient extends WebViewClient
public class TiWebViewClient extends WebViewClientClassicExt
{
private static final String TAG = "TiWVC";

Expand Down Expand Up @@ -195,6 +207,107 @@ public void setBasicAuthentication(String username, String password)
this.password = password;
}

/*
* ClientCertRequest wrapper for compatibility with both ClientCertRequest and ClientCertRequestHandler
*/
private class ClientCertRequestCompat
{
private ClientCertRequest clientCertRequest;
private ClientCertRequestHandler clientCertRequestHandler;

ClientCertRequestCompat(Object request)
{
// API 21+
if (Build.VERSION.SDK_INT >= 21 && request instanceof ClientCertRequest) {
clientCertRequest = (ClientCertRequest) request;

// API 16+
} else if (request instanceof ClientCertRequestHandler) {
clientCertRequestHandler = (ClientCertRequestHandler) request;
}
}

@SuppressLint("NewApi")
public void cancel()
{
if (clientCertRequest != null) {
clientCertRequest.cancel();
} else if (clientCertRequestHandler != null) {
clientCertRequestHandler.cancel();
}
}

@SuppressLint("NewApi")
public void ignore()
{
if (clientCertRequest != null) {
clientCertRequest.ignore();
} else if (clientCertRequestHandler != null) {
clientCertRequestHandler.ignore();
}
}

@SuppressLint("NewApi")
public void proceed(PrivateKey privateKey, X509Certificate[] x509Certificates)
{
if (clientCertRequest != null) {
clientCertRequest.proceed(privateKey, x509Certificates);
} else if (clientCertRequestHandler != null) {
clientCertRequestHandler.proceed(privateKey, x509Certificates);
}
}
}

@TargetApi(16)
private void handleClientCertRequest(final Object requestObj, final String host, final int port)
{
final Activity activity = TiApplication.getAppRootOrCurrentActivity();
final ClientCertRequestCompat request = new ClientCertRequestCompat(requestObj);

KeyChain.choosePrivateKeyAlias(activity, new KeyChainAliasCallback() {
@Override
public void alias(final String alias)
{
final AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... args)
{
try {
PrivateKey privateKey = KeyChain.getPrivateKey(activity, alias);
X509Certificate[] certificateChain = KeyChain.getCertificateChain(activity, alias);
request.proceed(privateKey, certificateChain);
} catch (Exception e) {
request.ignore();
}
return null;
}
}.execute();
}
}, null, null, host, port, null);
}

@TargetApi(21)
@Override
public void onReceivedClientCertRequest(WebView view, ClientCertRequest request)
{
handleClientCertRequest(request, request.getHost(), request.getPort());
}

/*
* this is a "hidden" callback implemented on API 16 - 18 for handling certificate requests
* note: Android 4.4 prevents this from being called, stating "Client certificates not supported in WebView"
*/
@TargetApi(16)
@Override
public void onReceivedClientCertRequest(WebView view, ClientCertRequestHandler handler, String host_and_port)
{
String[] hostPort = host_and_port.split(":");
String host = hostPort[0];
int port = Integer.parseInt(hostPort[1]);

handleClientCertRequest(handler, host, port);
}

@Override
public void onReceivedSslError(WebView view, SslErrorHandler handler, SslError error)
{
Expand Down

0 comments on commit 481f561

Please sign in to comment.