titanium-sdk
titanium-sdk copied to clipboard
feat: android Ti.UI.WebView support allowFileAccess
This is needed so that local files can be loaded into a WebView.
In SDK 9.X.X this was allowed by default, in 10.X.X this is not the case. The Android documentation recommends that this is set to false by default so I have added this as a new Ti.UI.WebView property setAllowFileAccess() as per previous PR feedback
Fixes #13188
Fails | |
---|---|
:no_entry_sign: | Test reports missing for MacOS. This indicates that a build failed or the test app crashed |
:no_entry_sign: |
:microscope: There are library changes, but no changes to the unit tests. That's OK as long as you're refactoring existing code, but will require an admin to merge this PR. Please see README.md#unit-tests for docs on unit testing. |
Warnings | |
---|---|
:warning: | Tests have failed, see below for more information. |
:warning: | There is no linked JIRA ticket in the PR body. Please include the URL of the relevant JIRA ticket. If you need to, you may file a ticket on JIRA |
Messages | |
---|---|
:book: | :fist: The commits in this PR match our conventions! Feel free to Rebase and Merge this PR when ready. |
:book: | :x: 1 tests have failed There are 1 tests failing and 902 skipped out of 17426 total tests. |
:book: |
:confetti_ball: Welcome to the Titanium SDK community, markive! Thank you so much for your PR, you're helping us make Titanium better. :gift: |
Tests:
Classname | Name | Time | Error |
---|---|---|---|
android.emulator.main.Titanium.Geolocation.methods | #forwardGeocoder() works via callback argument (12) | 5.043 | Error: expected false to be true at Assertion.fail (/node_modules/should/cjs/should.js:275:13) at Assertion.value (/node_modules/should/cjs/should.js:356:9) at Geolocation.<anonymous> (/ti.geolocation.test.js:585:32) |
Generated by :no_entry_sign: dangerJS against 1b90b9511bdb0e8a265c20c47e4f5e37e120999b
I feel like there was a reason for it to be removed. Kindly tagging @jquick-axway who most likely knows more here.
This "feature" allows the website to use "file://" URLs to access local files. Apple and Google considers this to be a security issue. And it violates the "same origin" policy for URLs and exposes a cross-app/site scripting vulnerability. If the Android device is rooted, then it might expose the entire Android file system to the web view too. https://developer.android.com/reference/android/webkit/WebSettings#setAllowFileAccess(boolean)
I'm pretty sure Google Play's security scanner will flag the app with a warning if it sees this API in the code. I'd be worried about all apps getting wrongly flagged. https://stackoverflow.com/questions/50791306/google-play-warning-your-app-contains-a-file-based-xss-issue-javascript-enable https://stackoverflow.com/questions/53095398/google-play-warning-your-app-contains-a-cross-app-scripting-vulnerability
On iOS, you have to use the assetsDirectory
property and assign it the local directory or single file you want to expose to the WebView
.
https://titaniumsdk.com/api/titanium/ui/webview.html#assetsdirectory
Maybe something similar can be implemented via the WebViewAssetLoader
? This class' shouldInterceptRequest()
method can intercept any URL (such as a file://
URL) and return the file content the website is looking for... but only if the file "should" be exposed. Probably more work than what you guys want to implement.
https://developer.android.com/reference/android/webkit/WebResourceResponse.html
Thanks @jquick-axway for your detailed explanation!
@hansemannn Only setAllowFileAccessFromFileURLs()
and setAllowUniversalAccessFromFileURLs()
are deprecated in API level 30, but setAllowFileAccess()
is still available.
In this PR it is set to false
by default as recommended, so why not give the option to explicitly changing it (regardless of the fact that an implementation via WebViewAssetLoader
is indeed needed) ?
A note could be added to the Titanium API reference like in the Android developer reference.
In this way one can explicitly allow file://
access in e.g. an inhouse app outside Google Play.
There is an example for WebViewAssetLoader
in https://developer.android.com/reference/androidx/webkit/WebViewAssetLoader
But it looks like we can use this PR too: https://github.com/tidev/titanium_mobile/issues/13188#issuecomment-1177675842 and it's not being flagged by Google.
Can we merge it?
We need @markive as a listed contributor to merge this
@Xlinx64 @caspahouzer, sorry i'm not very Github experienced.. I think we are all good to merge, I've updated branch to merge latest changes.. Anything else I'm needed to do?
@markive you have to sign the contributor cla as described. After you've been added to the contributors list we can merge your changes.
@caspahouzer ok I've reached out to Josh, thanks!
@caspahouzer please note I have signed the CLA, so as soon as I appear on the contributor list this can be merged. Thanks!
@caspahouzer @m1ga I am now on the contributor list so I think all is in place, thanks! https://github.com/tidev/organization-docs/blob/main/AUTHORIZED_CONTRIBUTORS.md
Will this be part of the next release? What is keeping us back to approve and merge this?
Is there anything else I need to do? This is my first submission..
@markive can you add it to the docs too. Have a look at https://github.com/tidev/titanium_mobile/blob/master/apidoc/Titanium/UI/WebView.yml#L727-L735 for an example.
Also tried to test it but I wasn't successful. I've tried:
const win = Ti.UI.createWindow({});
const webview = Ti.UI.createWebView({
allowFileAccess: true,
});
win.add(webview);
win.addEventListener("open", function() {
var permissions = [ 'android.permission.READ_EXTERNAL_STORAGE' ];
Ti.Android.requestPermissions(permissions, function(e) {
if (e.success) {
webview.url = "file:////storage/emulated/0/test.html";
}
});
})
win.open();
but still get err_access_denied
@m1ga I've retested it and it does work for me like this:


const win = Ti.UI.createWindow({});
const webview = Ti.UI.createWebView({
allowFileAccess: true,
});
win.add(webview);
win.addEventListener("open", function() {
var assetFile = Ti.Filesystem.getFile(Titanium.Filesystem.resourcesDirectory, '/images/[email protected]');
var destFile = Ti.Filesystem.getFile(Titanium.Filesystem.applicationDataDirectory, '[email protected]')
if (!destFile.exists()) {
assetFile.copy(destFile.nativePath);
}
webview.url = "test.html";
})
win.open();`
`<!doctype html>
<html>
<head>
<title>View Plan</title>
<meta name="viewport" content="width=device-width, maximum-scale=4, minimum-scale=0.1, user-scalable=yes">
<meta name="format-detection" content="telephone=no"/>
<style type="text/css">
/* Prevent the default selection behaviour */
html, body {
-webkit-user-select: none;
-webkit-touch-callout: none;
}
html, body, #plan-image {
margin: 0; padding: 0;
}
#plan-image {
position: relative;
height: 1000px;
width: 1000px;
z-index: 1;
}
.defect, .newDefect, .location, .drilldown, .mp {
position: absolute;
cursor: pointer;
z-index: 2;
background-repeat: no-repeat;
background-color: transparent;
-webkit-background-size: 100% 100%;
background-size: 100% 100%;
}
.defect {
width: 50px;
height: 50px;
background-image: url(file:///android_asset/Resources/images/[email protected]);
}
.blueDefect {
padding-left:10px;
width: 50px;
height: 50px;
background-image: url(file:///data/user/0/uk.co.marktestdelete/app_appdata/[email protected]);
}
</style>
</head>
<body>
<div id="plan-image">
<div class="defect" > </div>
<div class="blueDefect" style="margin-left:10px"> </div>
<h1>hello!</h1>
</div>
</body>
</html>`
First test is with allowFileAccess: false
, second is true.
Thanks for the example @markive :+1: That helped and it's working fine. Testing it with Liveview wasn't a good idea since that cached the images in the webview even when you switch it off.
@m1ga & @markive
Thanks for helps. It's working fine.
~~PR can be closed in my opinion.~~ Why it is still not merged into tidev:master and was not released with Ti 12.0.0 ?
@m1ga what is still needed? Tests and checks have passed, @markive is listed as a authorized contributor.
@hbugdoll I don't merge PRs, I'm only a contributor too. I have more than one PR waiting :wink: So we'll need to be patient (or you a custom SDK with this PR merged in)
@hbugdoll I don't merge PRs, I'm only a contributor too.
@m1ga Thank you for the clarification.
To check if there is any automatic security scan that would flag an app I've uploaded an app with 12.1.0 (master) + this PR merge in. I didn't enable the flag so it's a "normal" app build like other users would do it too. No issues during app upload check and after the review. App is live, no warnings :+1:
Yes I have also been using this in production across 2 different apps for over 1yr, so that is many many full reviews and approvals with no issue.
We released an app using setAllowFileAccess(true)
in Google Play without any issues last year.