From 8b55a16986de1329956b838eed93bb23bf038cf3 Mon Sep 17 00:00:00 2001 From: Ian Clelland Date: Tue, 12 Aug 2014 11:02:55 -0400 Subject: [PATCH 1/6] CB-7291: Add external-launch-whitelist and use it for filtering intent launches --- framework/src/org/apache/cordova/Config.java | 24 ++++++++++++++++--- .../org/apache/cordova/ConfigXmlParser.java | 18 ++++++++++---- .../org/apache/cordova/CordovaActivity.java | 12 ++++++---- .../org/apache/cordova/CordovaUriHelper.java | 24 +++++++++---------- .../org/apache/cordova/CordovaWebView.java | 24 ++++++++++++------- 5 files changed, 69 insertions(+), 33 deletions(-) diff --git a/framework/src/org/apache/cordova/Config.java b/framework/src/org/apache/cordova/Config.java index 5cae9a27..f13292c3 100644 --- a/framework/src/org/apache/cordova/Config.java +++ b/framework/src/org/apache/cordova/Config.java @@ -58,7 +58,7 @@ public class Config { Log.e(TAG, "Config was not initialised. Did you forget to Config.init(this)?"); return; } - parser.getWhitelist().addWhiteListEntry(origin, subdomains); + parser.getInternalWhitelist().addWhiteListEntry(origin, subdomains); } /** @@ -72,7 +72,21 @@ public class Config { Log.e(TAG, "Config was not initialised. Did you forget to Config.init(this)?"); return false; } - return parser.getWhitelist().isUrlWhiteListed(url); + return parser.getInternalWhitelist().isUrlWhiteListed(url); + } + + /** + * Determine if URL is in approved list of URLs to launch external applications. + * + * @param url + * @return true if whitelisted + */ + public static boolean isUrlExternallyWhiteListed(String url) { + if (parser == null) { + Log.e(TAG, "Config was not initialised. Did you forget to Config.init(this)?"); + return false; + } + return parser.getExternalWhitelist().isUrlWhiteListed(url); } public static String getStartUrl() { @@ -87,7 +101,11 @@ public class Config { } public static Whitelist getWhitelist() { - return parser.getWhitelist(); + return parser.getInternalWhitelist(); + } + + public static Whitelist getExternalWhitelist() { + return parser.getExternalWhitelist(); } public static List getPluginEntries() { diff --git a/framework/src/org/apache/cordova/ConfigXmlParser.java b/framework/src/org/apache/cordova/ConfigXmlParser.java index a5958efa..9179f982 100644 --- a/framework/src/org/apache/cordova/ConfigXmlParser.java +++ b/framework/src/org/apache/cordova/ConfigXmlParser.java @@ -37,11 +37,16 @@ public class ConfigXmlParser { private String launchUrl = "file:///android_asset/www/index.html"; private CordovaPreferences prefs = new CordovaPreferences(); - private Whitelist whitelist = new Whitelist(); + private Whitelist internalWhitelist = new Whitelist(); + private Whitelist externalWhitelist = new Whitelist(); private ArrayList pluginEntries = new ArrayList(20); - public Whitelist getWhitelist() { - return whitelist; + public Whitelist getInternalWhitelist() { + return internalWhitelist; + } + + public Whitelist getExternalWhitelist() { + return externalWhitelist; } public CordovaPreferences getPreferences() { @@ -104,8 +109,13 @@ public class ConfigXmlParser { else if (strNode.equals("access")) { String origin = xml.getAttributeValue(null, "origin"); String subdomains = xml.getAttributeValue(null, "subdomains"); + boolean external = (xml.getAttributeValue(null, "launch-external") != null); if (origin != null) { - whitelist.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0)); + if (external) { + externalWhitelist.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0)); + } else { + internalWhitelist.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0)); + } } } else if (strNode.equals("preference")) { diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java index 2fdb9a7b..190309ec 100755 --- a/framework/src/org/apache/cordova/CordovaActivity.java +++ b/framework/src/org/apache/cordova/CordovaActivity.java @@ -130,7 +130,8 @@ public class CordovaActivity extends Activity implements CordovaInterface { // Read from config.xml: protected CordovaPreferences preferences; - protected Whitelist whitelist; + protected Whitelist internalWhitelist; + protected Whitelist externalWhitelist; protected String launchUrl; protected ArrayList pluginEntries; @@ -216,7 +217,8 @@ public class CordovaActivity extends Activity implements CordovaInterface { preferences = parser.getPreferences(); preferences.setPreferencesBundle(getIntent().getExtras()); preferences.copyIntoIntentExtras(this); - whitelist = parser.getWhitelist(); + internalWhitelist = parser.getInternalWhitelist(); + externalWhitelist = parser.getExternalWhitelist(); launchUrl = parser.getLaunchUrl(); pluginEntries = parser.getPluginEntries(); Config.parser = parser; @@ -324,7 +326,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { if (appView.pluginManager == null) { appView.init(this, webViewClient != null ? webViewClient : makeWebViewClient(appView), webChromeClient != null ? webChromeClient : makeChromeClient(appView), - pluginEntries, whitelist, preferences); + pluginEntries, internalWhitelist, externalWhitelist, preferences); } // TODO: Have the views set this themselves. @@ -789,7 +791,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { // If errorUrl specified, then load it final String errorUrl = preferences.getString("errorUrl", null); - if ((errorUrl != null) && (errorUrl.startsWith("file://") || whitelist.isUrlWhiteListed(errorUrl)) && (!failingUrl.equals(errorUrl))) { + if ((errorUrl != null) && (errorUrl.startsWith("file://") || internalWhitelist.isUrlWhiteListed(errorUrl)) && (!failingUrl.equals(errorUrl))) { // Load URL on UI thread me.runOnUiThread(new Runnable() { @@ -849,7 +851,7 @@ public class CordovaActivity extends Activity implements CordovaInterface { */ @Deprecated // Use whitelist object directly. public boolean isUrlWhiteListed(String url) { - return whitelist.isUrlWhiteListed(url); + return internalWhitelist.isUrlWhiteListed(url); } /* diff --git a/framework/src/org/apache/cordova/CordovaUriHelper.java b/framework/src/org/apache/cordova/CordovaUriHelper.java index bb785920..ada28515 100644 --- a/framework/src/org/apache/cordova/CordovaUriHelper.java +++ b/framework/src/org/apache/cordova/CordovaUriHelper.java @@ -48,18 +48,11 @@ class CordovaUriHelper { */ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) boolean shouldOverrideUrlLoading(WebView view, String url) { - // The WebView should support http and https when going on the Internet - if(url.startsWith("http:") || url.startsWith("https:")) - { - // We only need to whitelist sites on the Internet! - if(appView.getWhitelist().isUrlWhiteListed(url)) - { - return false; - } - } // Give plugins the chance to handle the url - else if (this.appView.pluginManager.onOverrideUrlLoading(url)) { - + if (this.appView.pluginManager.onOverrideUrlLoading(url)) { + // Do nothing other than what the plugins wanted. + // If any returned true, then the request was handled. + return true; } else if(url.startsWith("file://") | url.startsWith("data:")) { @@ -67,7 +60,11 @@ class CordovaUriHelper { //DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING! return url.contains("app_webview"); } - else + else if (appView.getWhitelist().isUrlWhiteListed(url)) { + // Allow internal navigation + return false; + } + else if (appView.getExternalWhitelist().isUrlWhiteListed(url)) { try { Intent intent = new Intent(Intent.ACTION_VIEW); @@ -78,11 +75,12 @@ class CordovaUriHelper { intent.setSelector(null); } this.cordova.getActivity().startActivity(intent); + return true; } catch (android.content.ActivityNotFoundException e) { LOG.e(TAG, "Error loading url " + url, e); } } - //Default behaviour should be to load the default intent, let's see what happens! + // Intercept the request and do nothing with it -- block it return true; } } diff --git a/framework/src/org/apache/cordova/CordovaWebView.java b/framework/src/org/apache/cordova/CordovaWebView.java index 72aa1716..403a7aec 100755 --- a/framework/src/org/apache/cordova/CordovaWebView.java +++ b/framework/src/org/apache/cordova/CordovaWebView.java @@ -88,7 +88,9 @@ public class CordovaWebView extends WebView { private WebChromeClient.CustomViewCallback mCustomViewCallback; private CordovaResourceApi resourceApi; - private Whitelist whitelist; + private Whitelist internalWhitelist; + private Whitelist externalWhitelist; + // The URL passed to loadUrl(), not necessarily the URL of the current page. String loadedUrl; private CordovaPreferences preferences; @@ -135,14 +137,16 @@ public class CordovaWebView extends WebView { // Use two-phase init so that the control will work with XML layouts. public void init(CordovaInterface cordova, CordovaWebViewClient webViewClient, CordovaChromeClient webChromeClient, - List pluginEntries, Whitelist whitelist, CordovaPreferences preferences) { + List pluginEntries, Whitelist internalWhitelist, Whitelist externalWhitelist, + CordovaPreferences preferences) { if (this.cordova != null) { throw new IllegalStateException(); } this.cordova = cordova; this.viewClient = webViewClient; this.chromeClient = webChromeClient; - this.whitelist = whitelist; + this.internalWhitelist = internalWhitelist; + this.externalWhitelist = externalWhitelist; this.preferences = preferences; super.setWebChromeClient(webChromeClient); super.setWebViewClient(webViewClient); @@ -165,7 +169,7 @@ public class CordovaWebView extends WebView { if (!Config.isInitialized()) { Config.init(cdv.getActivity()); } - init(cdv, makeWebViewClient(cdv), makeWebChromeClient(cdv), Config.getPluginEntries(), Config.getWhitelist(), Config.getPreferences()); + init(cdv, makeWebViewClient(cdv), makeWebChromeClient(cdv), Config.getPluginEntries(), Config.getWhitelist(), Config.getExternalWhitelist(), Config.getPreferences()); } } @@ -319,9 +323,13 @@ public class CordovaWebView extends WebView { public Whitelist getWhitelist() { - return this.whitelist; + return this.internalWhitelist; } - + + public Whitelist getExternalWhitelist() { + return this.externalWhitelist; + } + /** * Load the url into the webview. * @@ -427,7 +435,7 @@ public class CordovaWebView extends WebView { if (LOG.isLoggable(LOG.DEBUG) && !url.startsWith("javascript:")) { LOG.d(TAG, ">>> loadUrlNow()"); } - if (url.startsWith("file://") || url.startsWith("javascript:") || whitelist.isUrlWhiteListed(url)) { + if (url.startsWith("file://") || url.startsWith("javascript:") || internalWhitelist.isUrlWhiteListed(url)) { super.loadUrl(url); } } @@ -560,7 +568,7 @@ public class CordovaWebView extends WebView { if (!openExternal) { // Make sure url is in whitelist - if (url.startsWith("file://") || whitelist.isUrlWhiteListed(url)) { + if (url.startsWith("file://") || internalWhitelist.isUrlWhiteListed(url)) { // TODO: What about params? // Load new URL this.loadUrl(url); From 4e3331ba6699d323420c7762efef633c7ca20324 Mon Sep 17 00:00:00 2001 From: Ian Clelland Date: Thu, 21 Aug 2014 15:59:05 -0400 Subject: [PATCH 2/6] CB-7291: Add defaults to external whitelist --- framework/res/xml/config.xml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/framework/res/xml/config.xml b/framework/res/xml/config.xml index 50459b92..6f4a264b 100644 --- a/framework/res/xml/config.xml +++ b/framework/res/xml/config.xml @@ -30,7 +30,20 @@ Apache Cordova Team - + + + + + + + + + + From 3b3bd9b6c917fe3ca9fdc967e9812b56ce7ca47a Mon Sep 17 00:00:00 2001 From: Ian Clelland Date: Thu, 21 Aug 2014 16:10:32 -0400 Subject: [PATCH 3/6] CB-7291: Only add file, content and data URLs to internal whitelist --- framework/src/org/apache/cordova/ConfigXmlParser.java | 5 +++++ framework/src/org/apache/cordova/Whitelist.java | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/framework/src/org/apache/cordova/ConfigXmlParser.java b/framework/src/org/apache/cordova/ConfigXmlParser.java index 9179f982..2a667a9a 100644 --- a/framework/src/org/apache/cordova/ConfigXmlParser.java +++ b/framework/src/org/apache/cordova/ConfigXmlParser.java @@ -82,6 +82,11 @@ public class ConfigXmlParser { boolean insideFeature = false; ArrayList urlMap = null; + // Add implicitly allowed URLs + internalWhitelist.addWhiteListEntry("file:///*", false); + internalWhitelist.addWhiteListEntry("content:///*", false); + internalWhitelist.addWhiteListEntry("data:*", false); + while (eventType != XmlResourceParser.END_DOCUMENT) { if (eventType == XmlResourceParser.START_TAG) { String strNode = xml.getName(); diff --git a/framework/src/org/apache/cordova/Whitelist.java b/framework/src/org/apache/cordova/Whitelist.java index 5101ec35..d0f823c3 100644 --- a/framework/src/org/apache/cordova/Whitelist.java +++ b/framework/src/org/apache/cordova/Whitelist.java @@ -98,10 +98,6 @@ public class Whitelist { public Whitelist() { this.whiteList = new ArrayList(); - // Add implicitly allowed URLs - addWhiteListEntry("file:///*", false); - addWhiteListEntry("content:///*", false); - addWhiteListEntry("data:*", false); } /* Match patterns (from http://developer.chrome.com/extensions/match_patterns.html) From 6e222c3938db43fc00f3d6f8fbb138af075c689b Mon Sep 17 00:00:00 2001 From: Ian Clelland Date: Tue, 26 Aug 2014 14:58:00 -0400 Subject: [PATCH 4/6] CB-7291: Restrict meaning of "*" in internal whitelist to just http and https --- framework/src/org/apache/cordova/ConfigXmlParser.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/framework/src/org/apache/cordova/ConfigXmlParser.java b/framework/src/org/apache/cordova/ConfigXmlParser.java index 2a667a9a..1ada1af2 100644 --- a/framework/src/org/apache/cordova/ConfigXmlParser.java +++ b/framework/src/org/apache/cordova/ConfigXmlParser.java @@ -119,7 +119,15 @@ public class ConfigXmlParser { if (external) { externalWhitelist.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0)); } else { - internalWhitelist.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0)); + if ("*".equals(origin)) { + // Special-case * origin to mean http and https when used for internal + // whitelist. This prevents external urls like sms: and geo: from being + // handled internally. + internalWhitelist.addWhiteListEntry("http://*/*", false); + internalWhitelist.addWhiteListEntry("https://*/*", false); + } else { + internalWhitelist.addWhiteListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0)); + } } } } From 94c096dd5b2a042534de72a53ee9bf166118eb83 Mon Sep 17 00:00:00 2001 From: Marcel Kinard Date: Tue, 26 Aug 2014 16:38:04 -0400 Subject: [PATCH 5/6] CB-7291 propogate change in method signature to the native tests --- .../org/apache/cordova/test/CordovaWebViewTestActivity.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java b/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java index 1c1789ef..d4270475 100644 --- a/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java +++ b/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java @@ -52,7 +52,7 @@ public class CordovaWebViewTestActivity extends Activity implements CordovaInter cordovaWebView = (CordovaWebView) findViewById(R.id.cordovaWebView); cordovaWebView.init(this, new CordovaWebViewClient(this, cordovaWebView), new CordovaChromeClient(this, cordovaWebView), - Config.getPluginEntries(), Config.getWhitelist(), Config.getPreferences()); + Config.getPluginEntries(), Config.getWhitelist(), Config.getExternalWhitelist(), Config.getPreferences()); cordovaWebView.loadUrl("file:///android_asset/www/index.html"); @@ -105,4 +105,4 @@ public class CordovaWebViewTestActivity extends Activity implements CordovaInter cordovaWebView.handleDestroy(); } } -} \ No newline at end of file +} From 16e3ebd87bbfa075defb5c4f2b1dd2e8a1eeb5b0 Mon Sep 17 00:00:00 2001 From: Marcel Kinard Date: Tue, 26 Aug 2014 17:20:58 -0400 Subject: [PATCH 6/6] CB-7410 add whitelist entries to get iframe/GoogleMaps working --- test/res/xml/config.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/res/xml/config.xml b/test/res/xml/config.xml index 7572732b..148bad5a 100644 --- a/test/res/xml/config.xml +++ b/test/res/xml/config.xml @@ -26,6 +26,10 @@ Apache Cordova Team + + + +