mirror of
https://github.com/apache/cordova-android.git
synced 2025-02-20 23:56:20 +08:00
Merge branch 'unplug-whitelist'
This commit is contained in:
commit
7e0bfbbad2
@ -88,10 +88,9 @@ public class AndroidWebView extends WebView implements CordovaWebView {
|
||||
private WebChromeClient.CustomViewCallback mCustomViewCallback;
|
||||
|
||||
private CordovaResourceApi resourceApi;
|
||||
private Whitelist internalWhitelist;
|
||||
private Whitelist externalWhitelist;
|
||||
private CordovaPreferences preferences;
|
||||
private CoreAndroid appPlugin;
|
||||
private CordovaUriHelper helper;
|
||||
// The URL passed to loadUrl(), not necessarily the URL of the current page.
|
||||
String loadedUrl;
|
||||
|
||||
@ -114,15 +113,13 @@ public class AndroidWebView extends WebView implements CordovaWebView {
|
||||
// Use two-phase init so that the control will work with XML layouts.
|
||||
@Override
|
||||
public void init(final CordovaInterface cordova, List<PluginEntry> pluginEntries,
|
||||
Whitelist internalWhitelist, Whitelist externalWhitelist,
|
||||
CordovaPreferences preferences) {
|
||||
if (this.cordova != null) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
this.cordova = cordova;
|
||||
this.internalWhitelist = internalWhitelist;
|
||||
this.externalWhitelist = externalWhitelist;
|
||||
this.preferences = preferences;
|
||||
this.helper = new CordovaUriHelper(cordova, this);
|
||||
|
||||
pluginManager = new PluginManager(this, this.cordova, pluginEntries);
|
||||
cookieManager = new AndroidCookieManager(this);
|
||||
@ -141,7 +138,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
|
||||
cordova.getActivity().runOnUiThread(r);
|
||||
}
|
||||
}));
|
||||
bridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue, this.cordova.getActivity().getPackageName());
|
||||
bridge = new CordovaBridge(pluginManager, nativeToJsMessageQueue, this.cordova.getActivity().getPackageName(), helper);
|
||||
initWebViewSettings();
|
||||
pluginManager.addService(CoreAndroid.PLUGIN_NAME, CoreAndroid.class.getCanonicalName());
|
||||
pluginManager.init();
|
||||
@ -386,7 +383,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:") || url.startsWith("about:") || internalWhitelist.isUrlWhiteListed(url)) {
|
||||
if (url.startsWith("javascript:") || helper.shouldAllowNavigation(url)) {
|
||||
super.loadUrl(url);
|
||||
}
|
||||
}
|
||||
@ -461,7 +458,7 @@ public class AndroidWebView extends WebView implements CordovaWebView {
|
||||
if (!openExternal) {
|
||||
|
||||
// Make sure url is in whitelist
|
||||
if (url.startsWith("file://") || internalWhitelist.isUrlWhiteListed(url)) {
|
||||
if (helper.shouldAllowNavigation(url)) {
|
||||
// TODO: What about params?
|
||||
// Load new URL
|
||||
loadUrlIntoView(url, true);
|
||||
@ -800,16 +797,6 @@ public class AndroidWebView extends WebView implements CordovaWebView {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Whitelist getWhitelist() {
|
||||
return this.internalWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Whitelist getExternalWhitelist() {
|
||||
return this.externalWhitelist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CordovaPreferences getPreferences() {
|
||||
return preferences;
|
||||
|
@ -46,48 +46,6 @@ public class Config {
|
||||
parser = new ConfigXmlParser();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add entry to approved list of URLs (whitelist)
|
||||
*
|
||||
* @param origin URL regular expression to allow
|
||||
* @param subdomains T=include all subdomains under origin
|
||||
*/
|
||||
public static void addWhiteListEntry(String origin, boolean subdomains) {
|
||||
if (parser == null) {
|
||||
Log.e(TAG, "Config was not initialised. Did you forget to Config.init(this)?");
|
||||
return;
|
||||
}
|
||||
parser.getInternalWhitelist().addWhiteListEntry(origin, subdomains);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if URL is in approved list of URLs to load.
|
||||
*
|
||||
* @param url
|
||||
* @return true if whitelisted
|
||||
*/
|
||||
public static boolean isUrlWhiteListed(String url) {
|
||||
if (parser == null) {
|
||||
Log.e(TAG, "Config was not initialised. Did you forget to Config.init(this)?");
|
||||
return false;
|
||||
}
|
||||
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() {
|
||||
if (parser == null) {
|
||||
@ -100,14 +58,6 @@ public class Config {
|
||||
return parser.getPreferences().getString("errorurl", null);
|
||||
}
|
||||
|
||||
public static Whitelist getWhitelist() {
|
||||
return parser.getInternalWhitelist();
|
||||
}
|
||||
|
||||
public static Whitelist getExternalWhitelist() {
|
||||
return parser.getExternalWhitelist();
|
||||
}
|
||||
|
||||
public static List<PluginEntry> getPluginEntries() {
|
||||
return parser.getPluginEntries();
|
||||
}
|
||||
|
@ -36,18 +36,8 @@ public class ConfigXmlParser {
|
||||
|
||||
private String launchUrl = "file:///android_asset/www/index.html";
|
||||
private CordovaPreferences prefs = new CordovaPreferences();
|
||||
private Whitelist internalWhitelist = new Whitelist();
|
||||
private Whitelist externalWhitelist = new Whitelist();
|
||||
private ArrayList<PluginEntry> pluginEntries = new ArrayList<PluginEntry>(20);
|
||||
|
||||
public Whitelist getInternalWhitelist() {
|
||||
return internalWhitelist;
|
||||
}
|
||||
|
||||
public Whitelist getExternalWhitelist() {
|
||||
return externalWhitelist;
|
||||
}
|
||||
|
||||
public CordovaPreferences getPreferences() {
|
||||
return prefs;
|
||||
}
|
||||
@ -59,7 +49,7 @@ public class ConfigXmlParser {
|
||||
public String getLaunchUrl() {
|
||||
return launchUrl;
|
||||
}
|
||||
|
||||
|
||||
public void parse(Activity action) {
|
||||
// First checking the class namespace for config.xml
|
||||
int id = action.getResources().getIdentifier("config", "xml", action.getClass().getPackage().getName());
|
||||
@ -74,78 +64,20 @@ public class ConfigXmlParser {
|
||||
parse(action.getResources().getXml(id));
|
||||
}
|
||||
|
||||
boolean insideFeature = false;
|
||||
String service = "", pluginClass = "", paramType = "";
|
||||
boolean onload = false;
|
||||
|
||||
public void parse(XmlResourceParser xml) {
|
||||
int eventType = -1;
|
||||
String service = "", pluginClass = "", paramType = "";
|
||||
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();
|
||||
if (strNode.equals("feature")) {
|
||||
//Check for supported feature sets aka. plugins (Accelerometer, Geolocation, etc)
|
||||
//Set the bit for reading params
|
||||
insideFeature = true;
|
||||
service = xml.getAttributeValue(null, "name");
|
||||
}
|
||||
else if (insideFeature && strNode.equals("param")) {
|
||||
paramType = xml.getAttributeValue(null, "name");
|
||||
if (paramType.equals("service")) // check if it is using the older service param
|
||||
service = xml.getAttributeValue(null, "value");
|
||||
else if (paramType.equals("package") || paramType.equals("android-package"))
|
||||
pluginClass = xml.getAttributeValue(null,"value");
|
||||
else if (paramType.equals("onload"))
|
||||
onload = "true".equals(xml.getAttributeValue(null, "value"));
|
||||
}
|
||||
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) {
|
||||
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")) {
|
||||
String name = xml.getAttributeValue(null, "name").toLowerCase(Locale.ENGLISH);
|
||||
String value = xml.getAttributeValue(null, "value");
|
||||
prefs.set(name, value);
|
||||
}
|
||||
else if (strNode.equals("content")) {
|
||||
String src = xml.getAttributeValue(null, "src");
|
||||
if (src != null) {
|
||||
setStartUrl(src);
|
||||
}
|
||||
}
|
||||
handleStartTag(xml);
|
||||
}
|
||||
else if (eventType == XmlResourceParser.END_TAG)
|
||||
{
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("feature")) {
|
||||
pluginEntries.add(new PluginEntry(service, pluginClass, onload));
|
||||
|
||||
service = "";
|
||||
pluginClass = "";
|
||||
insideFeature = false;
|
||||
onload = false;
|
||||
}
|
||||
handleEndTag(xml);
|
||||
}
|
||||
try {
|
||||
eventType = xml.next();
|
||||
@ -157,6 +89,48 @@ public class ConfigXmlParser {
|
||||
}
|
||||
}
|
||||
|
||||
public void handleStartTag(XmlResourceParser xml) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("feature")) {
|
||||
//Check for supported feature sets aka. plugins (Accelerometer, Geolocation, etc)
|
||||
//Set the bit for reading params
|
||||
insideFeature = true;
|
||||
service = xml.getAttributeValue(null, "name");
|
||||
}
|
||||
else if (insideFeature && strNode.equals("param")) {
|
||||
paramType = xml.getAttributeValue(null, "name");
|
||||
if (paramType.equals("service")) // check if it is using the older service param
|
||||
service = xml.getAttributeValue(null, "value");
|
||||
else if (paramType.equals("package") || paramType.equals("android-package"))
|
||||
pluginClass = xml.getAttributeValue(null,"value");
|
||||
else if (paramType.equals("onload"))
|
||||
onload = "true".equals(xml.getAttributeValue(null, "value"));
|
||||
}
|
||||
else if (strNode.equals("preference")) {
|
||||
String name = xml.getAttributeValue(null, "name").toLowerCase(Locale.ENGLISH);
|
||||
String value = xml.getAttributeValue(null, "value");
|
||||
prefs.set(name, value);
|
||||
}
|
||||
else if (strNode.equals("content")) {
|
||||
String src = xml.getAttributeValue(null, "src");
|
||||
if (src != null) {
|
||||
setStartUrl(src);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handleEndTag(XmlResourceParser xml) {
|
||||
String strNode = xml.getName();
|
||||
if (strNode.equals("feature")) {
|
||||
pluginEntries.add(new PluginEntry(service, pluginClass, onload));
|
||||
|
||||
service = "";
|
||||
pluginClass = "";
|
||||
insideFeature = false;
|
||||
onload = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void setStartUrl(String src) {
|
||||
Pattern schemeRegex = Pattern.compile("^[a-z-]+://");
|
||||
Matcher matcher = schemeRegex.matcher(src);
|
||||
|
@ -94,8 +94,6 @@ public class CordovaActivity extends Activity {
|
||||
|
||||
// Read from config.xml:
|
||||
protected CordovaPreferences preferences;
|
||||
protected Whitelist internalWhitelist;
|
||||
protected Whitelist externalWhitelist;
|
||||
protected String launchUrl;
|
||||
protected ArrayList<PluginEntry> pluginEntries;
|
||||
protected CordovaInterfaceImpl cordovaInterface;
|
||||
@ -142,7 +140,7 @@ public class CordovaActivity extends Activity {
|
||||
appView = makeWebView();
|
||||
createViews();
|
||||
//TODO: Add null check against CordovaInterfaceImpl, since this can be fragile
|
||||
appView.init(cordovaInterface, pluginEntries, internalWhitelist, externalWhitelist, preferences);
|
||||
appView.init(cordovaInterface, pluginEntries, preferences);
|
||||
cordovaInterface.setPluginManager(appView.getPluginManager());
|
||||
|
||||
// Wire the hardware volume controls to control media if desired.
|
||||
@ -159,8 +157,6 @@ public class CordovaActivity extends Activity {
|
||||
preferences = parser.getPreferences();
|
||||
preferences.setPreferencesBundle(getIntent().getExtras());
|
||||
preferences.copyIntoIntentExtras(this);
|
||||
internalWhitelist = parser.getInternalWhitelist();
|
||||
externalWhitelist = parser.getExternalWhitelist();
|
||||
launchUrl = parser.getLaunchUrl();
|
||||
pluginEntries = parser.getPluginEntries();
|
||||
Config.parser = parser;
|
||||
@ -354,7 +350,8 @@ public class CordovaActivity extends Activity {
|
||||
|
||||
// If errorUrl specified, then load it
|
||||
final String errorUrl = preferences.getString("errorUrl", null);
|
||||
if ((errorUrl != null) && (errorUrl.startsWith("file://") || internalWhitelist.isUrlWhiteListed(errorUrl)) && (!failingUrl.equals(errorUrl))) {
|
||||
CordovaUriHelper helper = new CordovaUriHelper(this.cordovaInterface, appView);
|
||||
if ((errorUrl != null) && (!failingUrl.equals(errorUrl)) && (appView != null)) {
|
||||
// Load URL on UI thread
|
||||
me.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
|
@ -38,11 +38,13 @@ public class CordovaBridge {
|
||||
private volatile int expectedBridgeSecret = -1; // written by UI thread, read by JS thread.
|
||||
private String loadedUrl;
|
||||
private String appContentUrlPrefix;
|
||||
protected CordovaUriHelper helper;
|
||||
|
||||
public CordovaBridge(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue, String packageName) {
|
||||
public CordovaBridge(PluginManager pluginManager, NativeToJsMessageQueue jsMessageQueue, String packageName, CordovaUriHelper helper) {
|
||||
this.pluginManager = pluginManager;
|
||||
this.jsMessageQueue = jsMessageQueue;
|
||||
this.appContentUrlPrefix = "content://" + packageName + ".";
|
||||
this.helper = helper;
|
||||
}
|
||||
|
||||
public String jsExec(int bridgeSecret, String service, String action, String callbackId, String arguments) throws JSONException, IllegalAccessException {
|
||||
@ -167,11 +169,11 @@ public class CordovaBridge {
|
||||
}
|
||||
else if (defaultValue != null && defaultValue.startsWith("gap_init:")) {
|
||||
// Protect against random iframes being able to talk through the bridge.
|
||||
// Trust only file URLs and the start URL's domain.
|
||||
// The extra origin.startsWith("http") is to protect against iframes with data: having "" as origin.
|
||||
// Trust only file URLs and pages which the app would have been allowed
|
||||
// to navigate to anyway.
|
||||
if (origin.startsWith("file:") ||
|
||||
origin.startsWith(this.appContentUrlPrefix) ||
|
||||
(origin.startsWith("http") && loadedUrl.startsWith(origin))) {
|
||||
helper.shouldAllowNavigation(origin)) {
|
||||
// Enable the bridge
|
||||
int bridgeMode = Integer.parseInt(defaultValue.substring(9));
|
||||
jsMessageQueue.setBridgeMode(bridgeMode);
|
||||
|
@ -162,19 +162,67 @@ public class CordovaPlugin {
|
||||
* Called when an activity you launched exits, giving you the requestCode you started it with,
|
||||
* the resultCode it returned, and any additional data from it.
|
||||
*
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
|
||||
* @param requestCode The request code originally supplied to startActivityForResult(),
|
||||
* allowing you to identify who this result came from.
|
||||
* @param resultCode The integer result code returned by the child activity through its setResult().
|
||||
* @param intent An Intent, which can return result data to the caller (various data can be
|
||||
* attached to Intent "extras").
|
||||
*/
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for blocking the loading of external resources.
|
||||
*
|
||||
* This will be called when the WebView's shouldInterceptRequest wants to
|
||||
* know whether to open a connection to an external resource. Return false
|
||||
* to block the request: if any plugin returns false, Cordova will block
|
||||
* the request. If all plugins return null, the default policy will be
|
||||
* enforced. If at least one plugin returns true, and no plugins return
|
||||
* false, then the request will proceed.
|
||||
*
|
||||
* Note that this only affects resource requests which are routed through
|
||||
* WebViewClient.shouldInterceptRequest, such as XMLHttpRequest requests and
|
||||
* img tag loads. WebSockets and media requests (such as <video> and <audio>
|
||||
* tags) are not affected by this method. Use CSP headers to control access
|
||||
* to such resources.
|
||||
*/
|
||||
public Boolean shouldAllowRequest(String url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for blocking navigation by the Cordova WebView.
|
||||
*
|
||||
* This will be called when the WebView's needs to know whether to navigate
|
||||
* to a new page. Return false to block the navigation: if any plugin
|
||||
* returns false, Cordova will block the navigation. If all plugins return
|
||||
* null, the default policy will be enforced. It at least one plugin returns
|
||||
* true, and no plugins return false, then the navigation will proceed.
|
||||
*/
|
||||
public Boolean shouldAllowNavigation(String url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for blocking the launching of Intents by the Cordova application.
|
||||
*
|
||||
* This will be called when the WebView will not navigate to a page, but
|
||||
* could launch an intent to handle the URL. Return false to block this: if
|
||||
* any plugin returns false, Cordova will block the navigation. If all
|
||||
* plugins return null, the default policy will be enforced. If at least one
|
||||
* plugin returns true, and no plugins return false, then the URL will be
|
||||
* opened.
|
||||
*/
|
||||
public Boolean shouldOpenExternalUrl(String url) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* By specifying a <url-filter> in config.xml you can map a URL (using startsWith atm) to this method.
|
||||
*
|
||||
* @param url The URL that is trying to be loaded in the Cordova webview.
|
||||
* @return Return true to prevent the URL from loading. Default is false.
|
||||
* @param url The URL that is trying to be loaded in the Cordova webview.
|
||||
* @return Return true to prevent the URL from loading. Default is false.
|
||||
*/
|
||||
public boolean onOverrideUrlLoading(String url) {
|
||||
return false;
|
||||
|
@ -23,6 +23,7 @@ import android.annotation.TargetApi;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.webkit.WebView;
|
||||
|
||||
public class CordovaUriHelper {
|
||||
@ -37,11 +38,77 @@ public class CordovaUriHelper {
|
||||
appView = webView;
|
||||
cordova = cdv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the webview should be allowed to navigate to a given URL.
|
||||
*
|
||||
* This method implements the default whitelist policy when no plugins override
|
||||
* shouldAllowNavigation
|
||||
*/
|
||||
public boolean shouldAllowNavigation(String url) {
|
||||
Boolean pluginManagerAllowsNavigation = this.appView.getPluginManager().shouldAllowNavigation(url);
|
||||
if (pluginManagerAllowsNavigation == null) {
|
||||
// Default policy:
|
||||
// Internal urls on file:// or data:// that do not contain "/app_webview/" are allowed for navigation
|
||||
if(url.startsWith("file://") || url.startsWith("data:"))
|
||||
{
|
||||
//This directory on WebKit/Blink based webviews contains SQLite databases!
|
||||
//DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!
|
||||
return !url.contains("/app_webview/");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return pluginManagerAllowsNavigation;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the webview should be allowed to launch an intent for a given URL.
|
||||
*
|
||||
* This method implements the default whitelist policy when no plugins override
|
||||
* shouldOpenExternalUrl
|
||||
*/
|
||||
public boolean shouldOpenExternalUrl(String url) {
|
||||
Boolean pluginManagerAllowsExternalUrl = this.appView.getPluginManager().shouldOpenExternalUrl(url);
|
||||
if (pluginManagerAllowsExternalUrl == null) {
|
||||
// Default policy:
|
||||
// External URLs are not allowed
|
||||
return false;
|
||||
}
|
||||
return pluginManagerAllowsExternalUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the webview should be allowed to request a resource from a given URL.
|
||||
*
|
||||
* This method implements the default whitelist policy when no plugins override
|
||||
* shouldAllowRequest
|
||||
*/
|
||||
public boolean shouldAllowRequest(String url) {
|
||||
|
||||
Boolean pluginManagerAllowsRequest = this.appView.getPluginManager().shouldAllowRequest(url);
|
||||
if (pluginManagerAllowsRequest == null) {
|
||||
// Default policy:
|
||||
// Internal urls on file:// or data:// that do not contain "/app_webview/" are allowed for navigation
|
||||
if(url.startsWith("file://") || url.startsWith("data:"))
|
||||
{
|
||||
//This directory on WebKit/Blink based webviews contains SQLite databases!
|
||||
//DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!
|
||||
return !url.contains("/app_webview/");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return pluginManagerAllowsRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the host application a chance to take over the control when a new url
|
||||
* is about to be loaded in the current WebView.
|
||||
*
|
||||
* This method implements the default whitelist policy when no plugins override
|
||||
* the whitelist methods:
|
||||
* Internal urls on file:// or data:// that do not contain "app_webview" are allowed for navigation
|
||||
* External urls are not allowed.
|
||||
*
|
||||
* @param view The WebView that is initiating the callback.
|
||||
* @param url The url to be loaded.
|
||||
* @return true to override, false for default behavior
|
||||
@ -49,23 +116,15 @@ public class CordovaUriHelper {
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
|
||||
public boolean shouldOverrideUrlLoading(String url) {
|
||||
// Give plugins the chance to handle the 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:"))
|
||||
{
|
||||
//This directory on WebKit/Blink based webviews contains SQLite databases!
|
||||
//DON'T CHANGE THIS UNLESS YOU KNOW WHAT YOU'RE DOING!
|
||||
return url.contains("app_webview");
|
||||
}
|
||||
else if (appView.getWhitelist().isUrlWhiteListed(url)) {
|
||||
if (shouldAllowNavigation(url)) {
|
||||
// Allow internal navigation
|
||||
return false;
|
||||
}
|
||||
else if (appView.getExternalWhitelist().isUrlWhiteListed(url))
|
||||
{
|
||||
if (shouldOpenExternalUrl(url)) {
|
||||
// Do nothing other than what the plugins wanted.
|
||||
// If any returned false, then the request was either blocked
|
||||
// completely, or handled out-of-band by the plugin. If they all
|
||||
// returned true, then we should open the URL here.
|
||||
try {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(url));
|
||||
@ -77,10 +136,11 @@ public class CordovaUriHelper {
|
||||
this.cordova.getActivity().startActivity(intent);
|
||||
return true;
|
||||
} catch (android.content.ActivityNotFoundException e) {
|
||||
LOG.e(TAG, "Error loading url " + url, e);
|
||||
Log.e(TAG, "Error loading url " + url, e);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Intercept the request and do nothing with it -- block it
|
||||
// Block by default
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,6 @@ public interface CordovaWebView {
|
||||
public static final String CORDOVA_VERSION = "4.0.0-dev";
|
||||
|
||||
void init(CordovaInterface cordova, List<PluginEntry> pluginEntries,
|
||||
Whitelist internalWhitelist, Whitelist externalWhitelist,
|
||||
CordovaPreferences preferences);
|
||||
|
||||
View getView();
|
||||
@ -81,8 +80,6 @@ public interface CordovaWebView {
|
||||
|
||||
PluginManager getPluginManager();
|
||||
|
||||
Whitelist getWhitelist();
|
||||
Whitelist getExternalWhitelist();
|
||||
CordovaPreferences getPreferences();
|
||||
ICordovaCookieManager getCookieManager();
|
||||
|
||||
|
@ -45,7 +45,7 @@ public class IceCreamCordovaWebViewClient extends AndroidWebViewClient {
|
||||
try {
|
||||
// Check the against the whitelist and lock out access to the WebView directory
|
||||
// Changing this will cause problems for your application
|
||||
if (isUrlHarmful(url)) {
|
||||
if (!helper.shouldAllowRequest(url)) {
|
||||
LOG.w(TAG, "URL blocked by whitelist: " + url);
|
||||
// Results in a 404.
|
||||
return new WebResourceResponse("text/plain", "UTF-8", null);
|
||||
@ -71,11 +71,6 @@ public class IceCreamCordovaWebViewClient extends AndroidWebViewClient {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isUrlHarmful(String url) {
|
||||
return ((url.startsWith("http:") || url.startsWith("https:")) && !appView.getWhitelist().isUrlWhiteListed(url))
|
||||
|| url.contains("app_webview");
|
||||
}
|
||||
|
||||
private static boolean needsKitKatContentUrlFix(Uri uri) {
|
||||
return android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT && "content".equals(uri.getScheme());
|
||||
}
|
||||
|
@ -297,6 +297,110 @@ public class PluginManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the webview is going to request an external resource.
|
||||
*
|
||||
* This delegates to the installed plugins, which must all return true for
|
||||
* this method to return true.
|
||||
*
|
||||
* @param url The URL that is being requested.
|
||||
* @return Tri-State:
|
||||
* null: All plugins returned null (the default). This
|
||||
* indicates that the default policy should be
|
||||
* followed.
|
||||
* true: All plugins returned true (allow the resource
|
||||
* to load)
|
||||
* false: At least one plugin returned false (block the
|
||||
* resource)
|
||||
*/
|
||||
public Boolean shouldAllowRequest(String url) {
|
||||
Boolean anyResponded = null;
|
||||
for (PluginEntry entry : this.entryMap.values()) {
|
||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
||||
if (plugin != null) {
|
||||
Boolean result = plugin.shouldAllowRequest(url);
|
||||
if (result != null) {
|
||||
anyResponded = true;
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// This will be true if all plugins allow the request, or null if no plugins override the method
|
||||
return anyResponded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the webview is going to change the URL of the loaded content.
|
||||
*
|
||||
* This delegates to the installed plugins, which must all return true for
|
||||
* this method to return true. A true result will allow the new page to load;
|
||||
* a false result will prevent the page from loading.
|
||||
*
|
||||
* @param url The URL that is being requested.
|
||||
* @return Tri-State:
|
||||
* null: All plugins returned null (the default). This
|
||||
* indicates that the default policy should be
|
||||
* followed.
|
||||
* true: All plugins returned true (allow the navigation)
|
||||
* false: At least one plugin returned false (block the
|
||||
* navigation)
|
||||
*/
|
||||
public Boolean shouldAllowNavigation(String url) {
|
||||
Boolean anyResponded = null;
|
||||
for (PluginEntry entry : this.entryMap.values()) {
|
||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
||||
if (plugin != null) {
|
||||
Boolean result = plugin.shouldAllowNavigation(url);
|
||||
if (result != null) {
|
||||
anyResponded = true;
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// This will be true if all plugins allow the request, or null if no plugins override the method
|
||||
return anyResponded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the webview is going not going to navigate, but may launch
|
||||
* an Intent for an URL.
|
||||
*
|
||||
* This delegates to the installed plugins, which must all return true for
|
||||
* this method to return true. A true result will allow the URL to launch;
|
||||
* a false result will prevent the URL from loading.
|
||||
*
|
||||
* @param url The URL that is being requested.
|
||||
* @return Tri-State:
|
||||
* null: All plugins returned null (the default). This
|
||||
* indicates that the default policy should be
|
||||
* followed.
|
||||
* true: All plugins returned true (allow the URL to
|
||||
* launch an intent)
|
||||
* false: At least one plugin returned false (block the
|
||||
* intent)
|
||||
*/
|
||||
public Boolean shouldOpenExternalUrl(String url) {
|
||||
Boolean anyResponded = null;
|
||||
for (PluginEntry entry : this.entryMap.values()) {
|
||||
CordovaPlugin plugin = pluginMap.get(entry.service);
|
||||
if (plugin != null) {
|
||||
Boolean result = plugin.shouldOpenExternalUrl(url);
|
||||
if (result != null) {
|
||||
anyResponded = true;
|
||||
if (!result) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// This will be true if all plugins allow the request, or null if no plugins override the method
|
||||
return anyResponded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the URL of the webview changes.
|
||||
*
|
||||
|
@ -63,8 +63,7 @@ public class CordovaWebViewTestActivity extends Activity {
|
||||
|
||||
AndroidWebView webView = (AndroidWebView) findViewById(R.id.cordovaWebView);
|
||||
cordovaWebView = webView;
|
||||
cordovaWebView.init(cordovaInterface, Config.getPluginEntries(), Config.getWhitelist(),
|
||||
Config.getExternalWhitelist(), Config.getPreferences());
|
||||
cordovaWebView.init(cordovaInterface, Config.getPluginEntries(), Config.getPreferences());
|
||||
|
||||
cordovaWebView.loadUrl(START_URL);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user