diff --git a/framework/res/xml/config.xml b/framework/res/xml/config.xml
index 0f00c3b3..ee68c3b7 100644
--- a/framework/res/xml/config.xml
+++ b/framework/res/xml/config.xml
@@ -30,7 +30,20 @@
Apache Cordova Team
-
+
+
+
+
+
+
+
+
+
+
diff --git a/framework/src/org/apache/cordova/AndroidWebView.java b/framework/src/org/apache/cordova/AndroidWebView.java
index bd733845..8986d583 100755
--- a/framework/src/org/apache/cordova/AndroidWebView.java
+++ b/framework/src/org/apache/cordova/AndroidWebView.java
@@ -86,7 +86,8 @@ public class AndroidWebView extends WebView implements CordovaWebView {
private WebChromeClient.CustomViewCallback mCustomViewCallback;
private CordovaResourceApi resourceApi;
- private Whitelist whitelist;
+ private Whitelist internalWhitelist;
+ private Whitelist externalWhitelist;
private CordovaPreferences preferences;
// The URL passed to loadUrl(), not necessarily the URL of the current page.
String loadedUrl;
@@ -110,12 +111,14 @@ public class AndroidWebView extends WebView implements CordovaWebView {
// Use two-phase init so that the control will work with XML layouts.
@Override
public void init(CordovaInterface cordova, List pluginEntries,
- Whitelist whitelist, CordovaPreferences preferences) {
+ Whitelist internalWhitelist, Whitelist externalWhitelist,
+ CordovaPreferences preferences) {
if (this.cordova != null) {
throw new IllegalStateException();
}
this.cordova = cordova;
- this.whitelist = whitelist;
+ this.internalWhitelist = internalWhitelist;
+ this.externalWhitelist = externalWhitelist;
this.preferences = preferences;
pluginManager = new PluginManager(this, this.cordova, pluginEntries);
@@ -351,7 +354,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
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);
}
}
@@ -426,7 +429,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
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
loadUrlIntoView(url, true);
@@ -744,9 +747,14 @@ public class AndroidWebView extends WebView implements CordovaWebView {
@Override
public Whitelist getWhitelist() {
- return this.whitelist;
+ return this.internalWhitelist;
}
-
+
+ @Override
+ public Whitelist getExternalWhitelist() {
+ return this.externalWhitelist;
+ }
+
@Override
public CordovaPreferences getPreferences() {
return preferences;
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 e5cb1db6..0b1f5290 100644
--- a/framework/src/org/apache/cordova/ConfigXmlParser.java
+++ b/framework/src/org/apache/cordova/ConfigXmlParser.java
@@ -36,11 +36,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() {
@@ -75,6 +80,11 @@ public class ConfigXmlParser {
boolean onload = false;
boolean insideFeature = false;
+ // 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();
@@ -96,8 +106,21 @@ 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 {
+ 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));
+ }
+ }
}
}
else if (strNode.equals("preference")) {
diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java
index fa332e5b..c2971ae0 100755
--- a/framework/src/org/apache/cordova/CordovaActivity.java
+++ b/framework/src/org/apache/cordova/CordovaActivity.java
@@ -121,7 +121,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;
@@ -181,7 +182,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;
@@ -256,7 +258,7 @@ public class CordovaActivity extends Activity implements CordovaInterface {
// If all else fails, return a default WebView
ret = new AndroidWebView(this);
}
- ret.init(this, pluginEntries, whitelist, preferences);
+ ret.init(this, pluginEntries, internalWhitelist, externalWhitelist, preferences);
return ret;
}
@@ -544,7 +546,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() {
public void run() {
diff --git a/framework/src/org/apache/cordova/CordovaUriHelper.java b/framework/src/org/apache/cordova/CordovaUriHelper.java
index f7d22da8..6c1c4fa9 100644
--- a/framework/src/org/apache/cordova/CordovaUriHelper.java
+++ b/framework/src/org/apache/cordova/CordovaUriHelper.java
@@ -48,18 +48,11 @@ public class CordovaUriHelper {
*/
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
public boolean shouldOverrideUrlLoading(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.getPluginManager().onOverrideUrlLoading(url)) {
-
+ if (this.appView.getPluginManager().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 @@ public 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 @@ public 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 213e062c..47abfc0d 100644
--- a/framework/src/org/apache/cordova/CordovaWebView.java
+++ b/framework/src/org/apache/cordova/CordovaWebView.java
@@ -13,7 +13,8 @@ public interface CordovaWebView {
public static final String CORDOVA_VERSION = "4.0.0-dev";
void init(CordovaInterface cordova, List pluginEntries,
- Whitelist whitelist, CordovaPreferences preferences);
+ Whitelist internalWhitelist, Whitelist externalWhitelist,
+ CordovaPreferences preferences);
View getView();
@@ -81,6 +82,7 @@ public interface CordovaWebView {
PluginManager getPluginManager();
Whitelist getWhitelist();
+ Whitelist getExternalWhitelist();
CordovaPreferences getPreferences();
void onFilePickerResult(Uri uri);
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)
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
+
+
+
+
diff --git a/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java b/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
index b143521e..43e0b2bc 100644
--- a/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
+++ b/test/src/org/apache/cordova/test/CordovaWebViewTestActivity.java
@@ -51,7 +51,8 @@ public class CordovaWebViewTestActivity extends Activity implements CordovaInter
Config.init(this);
cordovaWebView = (CordovaWebView) findViewById(R.id.cordovaWebView);
- cordovaWebView.init(this, Config.getPluginEntries(), Config.getWhitelist(), Config.getPreferences());
+ cordovaWebView.init(this, Config.getPluginEntries(), Config.getWhitelist(),
+ Config.getExternalWhitelist(), Config.getPreferences());
cordovaWebView.loadUrl("file:///android_asset/www/index.html");