Merge branch 'master' into 4.0.x (External whitelist changes)

This commit is contained in:
Ian Clelland 2014-09-11 10:08:45 -04:00
commit 31b1a821ca
10 changed files with 103 additions and 38 deletions

View File

@ -30,7 +30,20 @@
Apache Cordova Team
</author>
<access origin="*"/>
<!-- Allow access to arbitrary URLs in the Cordova WebView. This is a
development mode setting, and should be changed for production. -->
<access origin="http://*/*"/>
<access origin="https://*/*"/>
<!-- Grant certain URLs the ability to launch external applications. This
behaviour is set to match that of Cordova versions before 3.6.0, and
should be reviewed before launching an application in production. It
may be changed in the future. -->
<access origin="tel:*" launch-external="yes"/>
<access origin="geo:*" launch-external="yes"/>
<access origin="mailto:*" launch-external="yes"/>
<access origin="sms:*" launch-external="yes"/>
<access origin="market:*" launch-external="yes"/>
<!-- <content src="http://mysite.com/myapp.html" /> for external pages -->
<content src="index.html" />

View File

@ -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<PluginEntry> 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,7 +747,12 @@ 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

View File

@ -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<PluginEntry> getPluginEntries() {

View File

@ -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<PluginEntry> pluginEntries = new ArrayList<PluginEntry>(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")) {

View File

@ -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<PluginEntry> 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() {

View File

@ -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;
}
}

View File

@ -13,7 +13,8 @@ public interface CordovaWebView {
public static final String CORDOVA_VERSION = "4.0.0-dev";
void init(CordovaInterface cordova, List<PluginEntry> 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);

View File

@ -98,10 +98,6 @@ public class Whitelist {
public Whitelist() {
this.whiteList = new ArrayList<URLPattern>();
// Add implicitly allowed URLs
addWhiteListEntry("file:///*", false);
addWhiteListEntry("content:///*", false);
addWhiteListEntry("data:*", false);
}
/* Match patterns (from http://developer.chrome.com/extensions/match_patterns.html)

View File

@ -26,6 +26,10 @@
Apache Cordova Team
</author>
<access origin="*.apache.org" />
<access origin="http://*.google.com/*" />
<access origin="https://*.google.com/*" />
<access origin="https://*.googleapis.com/*" />
<access origin="https://*.gstatic.com/*" />
<content src="index.html" />
<preference name="loglevel" value="DEBUG" />
<preference name="useBrowserHistory" value="true" />

View File

@ -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");