mirror of
https://github.com/apache/cordova-android.git
synced 2025-01-19 07:02:51 +08:00
feat(allow-list)!: integrate and refactor core plugin (#1138)
* refactor!: naming to allow list * feat(allow-list): integrate core plugin * refactor(allow-list): cleanup * refactor: drop deprecated launch-external case for CustomConfigParser::handleStartTag * fix: apply review comments
This commit is contained in:
parent
01569ce71a
commit
015db819ae
@ -21,7 +21,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<!--
|
<!--
|
||||||
Customize this policy to fit your own app's needs. For more guidance, see:
|
Customize this policy to fit your own app's needs. For more guidance, see:
|
||||||
https://github.com/apache/cordova-plugin-whitelist/blob/master/README.md#content-security-policy
|
https://cordova.apache.org/docs/en/latest/
|
||||||
Some notes:
|
Some notes:
|
||||||
* gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
|
* gap: is required only on iOS (when using UIWebView) and is needed for JS->native communication
|
||||||
* https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
|
* https://ssl.gstatic.com is required only on Android and is needed for TalkBack to function properly
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
<!-- <content src="http://mysite.com/myapp.html" /> for external pages -->
|
<!-- <content src="http://mysite.com/myapp.html" /> for external pages -->
|
||||||
<content src="index.html" />
|
<content src="index.html" />
|
||||||
|
|
||||||
<!-- Whitelist docs: https://github.com/apache/cordova-plugin-whitelist -->
|
<!-- Allow List docs: https://cordova.apache.org/docs/en/latest/ -->
|
||||||
<access origin="*" />
|
<access origin="*" />
|
||||||
<!-- Grant certain URLs the ability to launch external applications. This
|
<!-- Grant certain URLs the ability to launch external applications. This
|
||||||
behaviour is set to match that of Cordova versions before 3.6.0, and
|
behaviour is set to match that of Cordova versions before 3.6.0, and
|
||||||
|
@ -28,7 +28,7 @@ import org.apache.cordova.LOG;
|
|||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
|
||||||
public class Whitelist {
|
public class AllowList {
|
||||||
private static class URLPattern {
|
private static class URLPattern {
|
||||||
public Pattern scheme;
|
public Pattern scheme;
|
||||||
public Pattern host;
|
public Pattern host;
|
||||||
@ -92,12 +92,12 @@ public class Whitelist {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<URLPattern> whiteList;
|
private ArrayList<URLPattern> allowList;
|
||||||
|
|
||||||
public static final String TAG = "Whitelist";
|
public static final String TAG = "CordovaAllowList";
|
||||||
|
|
||||||
public Whitelist() {
|
public AllowList() {
|
||||||
this.whiteList = new ArrayList<URLPattern>();
|
this.allowList = new ArrayList<URLPattern>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Match patterns (from http://developer.chrome.com/extensions/match_patterns.html)
|
/* Match patterns (from http://developer.chrome.com/extensions/match_patterns.html)
|
||||||
@ -111,13 +111,13 @@ public class Whitelist {
|
|||||||
* the scheme to be omitted for backwards compatibility. (Also host is not required
|
* the scheme to be omitted for backwards compatibility. (Also host is not required
|
||||||
* to begin with a "*" or "*.".)
|
* to begin with a "*" or "*.".)
|
||||||
*/
|
*/
|
||||||
public void addWhiteListEntry(String origin, boolean subdomains) {
|
public void addAllowListEntry(String origin, boolean subdomains) {
|
||||||
if (whiteList != null) {
|
if (allowList != null) {
|
||||||
try {
|
try {
|
||||||
// Unlimited access to network resources
|
// Unlimited access to network resources
|
||||||
if (origin.compareTo("*") == 0) {
|
if (origin.compareTo("*") == 0) {
|
||||||
LOG.d(TAG, "Unlimited access to network resources");
|
LOG.d(TAG, "Unlimited access to network resources");
|
||||||
whiteList = null;
|
allowList = null;
|
||||||
}
|
}
|
||||||
else { // specific access
|
else { // specific access
|
||||||
Pattern parts = Pattern.compile("^((\\*|[A-Za-z-]+):(//)?)?(\\*|((\\*\\.)?[^*/:]+))?(:(\\d+))?(/.*)?");
|
Pattern parts = Pattern.compile("^((\\*|[A-Za-z-]+):(//)?)?(\\*|((\\*\\.)?[^*/:]+))?(:(\\d+))?(/.*)?");
|
||||||
@ -131,10 +131,10 @@ public class Whitelist {
|
|||||||
String path = m.group(9);
|
String path = m.group(9);
|
||||||
if (scheme == null) {
|
if (scheme == null) {
|
||||||
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
// XXX making it stupid friendly for people who forget to include protocol/SSL
|
||||||
whiteList.add(new URLPattern("http", host, port, path));
|
allowList.add(new URLPattern("http", host, port, path));
|
||||||
whiteList.add(new URLPattern("https", host, port, path));
|
allowList.add(new URLPattern("https", host, port, path));
|
||||||
} else {
|
} else {
|
||||||
whiteList.add(new URLPattern(scheme, host, port, path));
|
allowList.add(new URLPattern(scheme, host, port, path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,15 +149,15 @@ public class Whitelist {
|
|||||||
* Determine if URL is in approved list of URLs to load.
|
* Determine if URL is in approved list of URLs to load.
|
||||||
*
|
*
|
||||||
* @param uri
|
* @param uri
|
||||||
* @return true if wide open or whitelisted
|
* @return true if wide open or allow listed
|
||||||
*/
|
*/
|
||||||
public boolean isUrlWhiteListed(String uri) {
|
public boolean isUrlAllowListed(String uri) {
|
||||||
// If there is no whitelist, then it's wide open
|
// If there is no allowList, then it's wide open
|
||||||
if (whiteList == null) return true;
|
if (allowList == null) return true;
|
||||||
|
|
||||||
Uri parsedUri = Uri.parse(uri);
|
Uri parsedUri = Uri.parse(uri);
|
||||||
// Look for match in white list
|
// Look for match in allow list
|
||||||
Iterator<URLPattern> pit = whiteList.iterator();
|
Iterator<URLPattern> pit = allowList.iterator();
|
||||||
while (pit.hasNext()) {
|
while (pit.hasNext()) {
|
||||||
URLPattern p = pit.next();
|
URLPattern p = pit.next();
|
||||||
if (p.matches(parsedUri)) {
|
if (p.matches(parsedUri)) {
|
157
framework/src/org/apache/cordova/AllowListPlugin.java
Normal file
157
framework/src/org/apache/cordova/AllowListPlugin.java
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.apache.cordova;
|
||||||
|
|
||||||
|
import org.apache.cordova.CordovaPlugin;
|
||||||
|
import org.apache.cordova.ConfigXmlParser;
|
||||||
|
import org.apache.cordova.LOG;
|
||||||
|
import org.apache.cordova.AllowList;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
public class AllowListPlugin extends CordovaPlugin {
|
||||||
|
public static final String PLUGIN_NAME = "CordovaAllowListPlugin";
|
||||||
|
protected static final String LOG_TAG = "CordovaAllowListPlugin";
|
||||||
|
|
||||||
|
private AllowList allowedNavigations;
|
||||||
|
private AllowList allowedIntents;
|
||||||
|
private AllowList allowedRequests;
|
||||||
|
|
||||||
|
// Used when instantiated via reflection by PluginManager
|
||||||
|
public AllowListPlugin() { }
|
||||||
|
|
||||||
|
// These can be used by embedders to allow Java-configuration of an allow list.
|
||||||
|
public AllowListPlugin(Context context) {
|
||||||
|
this(new AllowList(), new AllowList(), null);
|
||||||
|
new CustomConfigXmlParser().parse(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AllowListPlugin(XmlPullParser xmlParser) {
|
||||||
|
this(new AllowList(), new AllowList(), null);
|
||||||
|
new CustomConfigXmlParser().parse(xmlParser);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AllowListPlugin(AllowList allowedNavigations, AllowList allowedIntents, AllowList allowedRequests) {
|
||||||
|
if (allowedRequests == null) {
|
||||||
|
allowedRequests = new AllowList();
|
||||||
|
allowedRequests.addAllowListEntry("file:///*", false);
|
||||||
|
allowedRequests.addAllowListEntry("data:*", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.allowedNavigations = allowedNavigations;
|
||||||
|
this.allowedIntents = allowedIntents;
|
||||||
|
this.allowedRequests = allowedRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void pluginInitialize() {
|
||||||
|
if (this.allowedNavigations == null) {
|
||||||
|
this.allowedNavigations = new AllowList();
|
||||||
|
this.allowedIntents = new AllowList();
|
||||||
|
this.allowedRequests = new AllowList();
|
||||||
|
|
||||||
|
new CustomConfigXmlParser().parse(webView.getContext());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CustomConfigXmlParser extends ConfigXmlParser {
|
||||||
|
@Override
|
||||||
|
public void handleStartTag(XmlPullParser xml) {
|
||||||
|
String strNode = xml.getName();
|
||||||
|
if (strNode.equals("content")) {
|
||||||
|
String startPage = xml.getAttributeValue(null, "src");
|
||||||
|
allowedNavigations.addAllowListEntry(startPage, false);
|
||||||
|
} else if (strNode.equals("allow-navigation")) {
|
||||||
|
String origin = xml.getAttributeValue(null, "href");
|
||||||
|
if ("*".equals(origin)) {
|
||||||
|
allowedNavigations.addAllowListEntry("http://*/*", false);
|
||||||
|
allowedNavigations.addAllowListEntry("https://*/*", false);
|
||||||
|
allowedNavigations.addAllowListEntry("data:*", false);
|
||||||
|
} else {
|
||||||
|
allowedNavigations.addAllowListEntry(origin, false);
|
||||||
|
}
|
||||||
|
} else if (strNode.equals("allow-intent")) {
|
||||||
|
String origin = xml.getAttributeValue(null, "href");
|
||||||
|
allowedIntents.addAllowListEntry(origin, false);
|
||||||
|
} else if (strNode.equals("access")) {
|
||||||
|
String origin = xml.getAttributeValue(null, "origin");
|
||||||
|
|
||||||
|
if (origin != null) {
|
||||||
|
if ("*".equals(origin)) {
|
||||||
|
allowedRequests.addAllowListEntry("http://*/*", false);
|
||||||
|
allowedRequests.addAllowListEntry("https://*/*", false);
|
||||||
|
} else {
|
||||||
|
String subdomains = xml.getAttributeValue(null, "subdomains");
|
||||||
|
allowedRequests.addAllowListEntry(origin, (subdomains != null) && (subdomains.compareToIgnoreCase("true") == 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handleEndTag(XmlPullParser xml) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean shouldAllowNavigation(String url) {
|
||||||
|
return this.allowedNavigations.isUrlAllowListed(url)
|
||||||
|
? true
|
||||||
|
: null; // default policy
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean shouldAllowRequest(String url) {
|
||||||
|
return (this.shouldAllowNavigation(url) || this.allowedRequests.isUrlAllowListed(url))
|
||||||
|
? true
|
||||||
|
: null; // default policy
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean shouldOpenExternalUrl(String url) {
|
||||||
|
return (this.allowedIntents.isUrlAllowListed(url))
|
||||||
|
? true
|
||||||
|
: null; // default policy
|
||||||
|
}
|
||||||
|
|
||||||
|
public AllowList getAllowedNavigations() {
|
||||||
|
return this.allowedNavigations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowedNavigations(AllowList allowedNavigations) {
|
||||||
|
this.allowedNavigations = allowedNavigations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AllowList getAllowedIntents() {
|
||||||
|
return this.allowedIntents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowedIntents(AllowList allowedIntents) {
|
||||||
|
this.allowedIntents = allowedIntents;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AllowList getAllowedRequests() {
|
||||||
|
return this.allowedRequests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAllowedRequests(AllowList allowedRequests) {
|
||||||
|
this.allowedRequests = allowedRequests;
|
||||||
|
}
|
||||||
|
}
|
@ -23,7 +23,7 @@ import java.util.List;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
|
|
||||||
@Deprecated // Use Whitelist, CordovaPrefences, etc. directly.
|
@Deprecated // Use AllowList, CordovaPrefences, etc. directly.
|
||||||
public class Config {
|
public class Config {
|
||||||
private static final String TAG = "Config";
|
private static final String TAG = "Config";
|
||||||
|
|
||||||
|
@ -68,6 +68,15 @@ public class ConfigXmlParser {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pluginEntries.add(
|
||||||
|
new PluginEntry(
|
||||||
|
AllowListPlugin.PLUGIN_NAME,
|
||||||
|
"org.apache.cordova.AllowListPlugin",
|
||||||
|
true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
parse(action.getResources().getXml(id));
|
parse(action.getResources().getXml(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ public interface CordovaWebView {
|
|||||||
/**
|
/**
|
||||||
* Load the specified URL in the Cordova webview or a new browser instance.
|
* Load the specified URL in the Cordova webview or a new browser instance.
|
||||||
*
|
*
|
||||||
* NOTE: If openExternal is false, only whitelisted URLs can be loaded.
|
* NOTE: If openExternal is false, only allow listed URLs can be loaded.
|
||||||
*
|
*
|
||||||
* @param url The url to load.
|
* @param url The url to load.
|
||||||
* @param openExternal Load url in browser instead of Cordova webview.
|
* @param openExternal Load url in browser instead of Cordova webview.
|
||||||
|
@ -218,19 +218,19 @@ public class CordovaWebViewImpl implements CordovaWebView {
|
|||||||
|
|
||||||
// If loading into our webview
|
// If loading into our webview
|
||||||
if (!openExternal) {
|
if (!openExternal) {
|
||||||
// Make sure url is in whitelist
|
// Make sure url is in allow list
|
||||||
if (pluginManager.shouldAllowNavigation(url)) {
|
if (pluginManager.shouldAllowNavigation(url)) {
|
||||||
// TODO: What about params?
|
// TODO: What about params?
|
||||||
// Load new URL
|
// Load new URL
|
||||||
loadUrlIntoView(url, true);
|
loadUrlIntoView(url, true);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
LOG.w(TAG, "showWebPage: Refusing to load URL into webview since it is not in the <allow-navigation> whitelist. URL=" + url);
|
LOG.w(TAG, "showWebPage: Refusing to load URL into webview since it is not in the <allow-navigation> allow list. URL=" + url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!pluginManager.shouldOpenExternalUrl(url)) {
|
if (!pluginManager.shouldOpenExternalUrl(url)) {
|
||||||
LOG.w(TAG, "showWebPage: Refusing to send intent for URL since it is not in the <allow-intent> whitelist. URL=" + url);
|
LOG.w(TAG, "showWebPage: Refusing to send intent for URL since it is not in the <allow-intent> allow list. URL=" + url);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
<script type="text/javascript" charset="utf-8" src="../main.js"></script>
|
<script type="text/javascript" charset="utf-8" src="../main.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="init();" id="stage" class="theme">
|
<body onload="init();" id="stage" class="theme">
|
||||||
<h1>Whitelist Page 1</h1>
|
<h1>Allow List Page 1</h1>
|
||||||
<div id="info">
|
<div id="info">
|
||||||
<h4>Cordova: <span id="cordova"> </span></h4>
|
<h4>Cordova: <span id="cordova"> </span></h4>
|
||||||
<h4>Deviceready: <span id="deviceready"> </span></h4>
|
<h4>Deviceready: <span id="deviceready"> </span></h4>
|
@ -27,7 +27,7 @@
|
|||||||
<script type="text/javascript" charset="utf-8" src="../main.js"></script>
|
<script type="text/javascript" charset="utf-8" src="../main.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body onload="init();" id="stage" class="theme">
|
<body onload="init();" id="stage" class="theme">
|
||||||
<h1>Whitelist Page 2</h1>
|
<h1>Allow List Page 2</h1>
|
||||||
<div id="info">
|
<div id="info">
|
||||||
<h4>Cordova: <span id="cordova"> </span></h4>
|
<h4>Cordova: <span id="cordova"> </span></h4>
|
||||||
<h4>Deviceready: <span id="deviceready"> </span></h4>
|
<h4>Deviceready: <span id="deviceready"> </span></h4>
|
@ -371,10 +371,10 @@ public class SystemWebViewClient extends WebViewClient {
|
|||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
|
public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
|
||||||
try {
|
try {
|
||||||
// Check the against the whitelist and lock out access to the WebView directory
|
// Check the against the allow list and lock out access to the WebView directory
|
||||||
// Changing this will cause problems for your application
|
// Changing this will cause problems for your application
|
||||||
if (!parentEngine.pluginManager.shouldAllowRequest(url)) {
|
if (!parentEngine.pluginManager.shouldAllowRequest(url)) {
|
||||||
LOG.w(TAG, "URL blocked by whitelist: " + url);
|
LOG.w(TAG, "URL blocked by allow list: " + url);
|
||||||
// Results in a 404.
|
// Results in a 404.
|
||||||
return new WebResourceResponse("text/plain", "UTF-8", null);
|
return new WebResourceResponse("text/plain", "UTF-8", null);
|
||||||
}
|
}
|
||||||
|
45
test/androidx/app/src/main/assets/www/allowlist/index.html
Executable file
45
test/androidx/app/src/main/assets/www/allowlist/index.html
Executable file
@ -0,0 +1,45 @@
|
|||||||
|
<!--
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=320, user-scalable=no" />
|
||||||
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||||
|
<title>Cordova Tests</title>
|
||||||
|
<link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title">
|
||||||
|
<script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8" src="../main.js"></script>
|
||||||
|
</head>
|
||||||
|
<body onload="init();" id="stage" class="theme">
|
||||||
|
<h1>Allow List Page 1</h1>
|
||||||
|
<div id="info">
|
||||||
|
<h4>Cordova: <span id="cordova"> </span></h4>
|
||||||
|
<h4>Deviceready: <span id="deviceready"> </span></h4>
|
||||||
|
</div>
|
||||||
|
<div id="info">
|
||||||
|
Loading Page 2 should be successful.<br>
|
||||||
|
Loading Page 3 should be in web browser.<br>
|
||||||
|
Loading Page 2 with target=_blank should be in web browser? <br>
|
||||||
|
(THIS DOESN'T HAPPEN.) https://issues.apache.org/jira/browse/CB-362
|
||||||
|
</div>
|
||||||
|
<a href="index2.html" class="btn large">Page 2</a>
|
||||||
|
<a href="http://www.google.com" class="btn large">Page 3</a>
|
||||||
|
<a href="index2.html" class="btn large" target="_blank">Page 2 with target=_blank</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
39
test/androidx/app/src/main/assets/www/allowlist/index2.html
Executable file
39
test/androidx/app/src/main/assets/www/allowlist/index2.html
Executable file
@ -0,0 +1,39 @@
|
|||||||
|
<!--
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE HTML>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=320, user-scalable=no" />
|
||||||
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||||
|
<title>Cordova Tests</title>
|
||||||
|
<link rel="stylesheet" href="../master.css" type="text/css" media="screen" title="no title">
|
||||||
|
<script type="text/javascript" charset="utf-8" src="../cordova.js"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8" src="../main.js"></script>
|
||||||
|
</head>
|
||||||
|
<body onload="init();" id="stage" class="theme">
|
||||||
|
<h1>Allow List Page 2</h1>
|
||||||
|
<div id="info">
|
||||||
|
<h4>Cordova: <span id="cordova"> </span></h4>
|
||||||
|
<h4>Deviceready: <span id="deviceready"> </span></h4>
|
||||||
|
</div>
|
||||||
|
<div id="info">
|
||||||
|
Press "backbutton"
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -51,6 +51,6 @@
|
|||||||
<button class="btn large" onclick="startActivity('htmlnotfound/index.html');">HTML not found</button>
|
<button class="btn large" onclick="startActivity('htmlnotfound/index.html');">HTML not found</button>
|
||||||
<button class="btn large" onclick="startActivity('iframe/index.html');">IFrame</button>
|
<button class="btn large" onclick="startActivity('iframe/index.html');">IFrame</button>
|
||||||
<button class="btn large" onclick="startActivity('lifecycle/index.html');">Lifecycle</button>
|
<button class="btn large" onclick="startActivity('lifecycle/index.html');">Lifecycle</button>
|
||||||
<button class="btn large" onclick="startActivity('whitelist/index.html');">Whitelist</button>
|
<button class="btn large" onclick="startActivity('allowlist/index.html');">Allow List</button>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user