I'm trying to catch console logs of an iframe which I don't have access to its source and its implementation.
<iframe src="an http address" name="my-iframe" allowFullScreen/>
When the iframe logs data I see them in my console. But the problem is,
this piece of code
// define a new console
var console = (function(oldCons){
return {
log: function(text){
oldCons.log(text);
if(text === "hi"){
alert("text")
}
},
info: function (text) {
oldCons.info(text);
if(text === "hi"){
alert("text")
}
},
warn: function (text) {
oldCons.warn(text);
if(text === "hi"){
alert("text")
}
},
error: function (text) {
oldCons.error(text);
if(text === "hi"){
alert("text")
}
}
};
}(window.console));
//Then redefine the old console
window.console = console;
Which I got from this post is not working for the iframe logs. It only works on my app console logs.
If the src is a different domain, and you can't run code directly on the other domain (for example, by being able to modify or insert a .js into it), then there's nothing you can do. This is for security reasons: browsers don't want to leak any information between domains unless the sender of the information deliberately allows it.
If you can alter code on the other domain, you could monkeypatch the console and have it pass the log information to the parent window with postMessage so that the parent can do something with it.
If you happen to be trying to examine messages for your personal use only (rather than for use by random people on the internet), you can modify your browser to run your custom JavaScript on the other domain with a userscript, by using a userscript manager like Tampermonkey.
I am trying to access the HTML Geolocation API available in Android WebView (using SDK version 24).
The main problem is that the call to navigator.geolocation.getCurrentPosition() in JavaScript never returns (neither with an error, nor with position data), while on application side I check for permissions and properly pass them to WebView using android.webkit.GeolocationPermissions.Callback class.
UPDATE: Just to clarify here, by "never returns" I mean that none of the two supplied callbacks navigator.geolocation.getCurrentPosition(success, error) are ever called.
In a sample app I built to test this (with just one small activity hosting WebView) I declare the permissions in manifest and request them properly on App start. I see the prompt and can grant or deny permission to location information.
Manifest:
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
Code in the main form:
public boolean checkFineLocationPermission() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION) && !mIsPermissionDialogShown) {
showPermissionDialog(R.string.dialog_permission_location);
} else {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
PERMISSION_ACCESS_FINE_LOCATION);
}
return false;
} else {
return true;
}
}
I can check for permissions during runtime using Context.checkSelfPermission() and I see that the respective permissions are granted to my app.
Then I try to open a web page in a WebView control.
I enable all required options in the settings:
mWebSettings.setJavaScriptEnabled(true);
mWebSettings.setAppCacheEnabled(true);
mWebSettings.setDatabaseEnabled(true);
mWebSettings.setDomStorageEnabled(true);
mWebSettings.setGeolocationEnabled(true);
mWebSettings.setJavaScriptCanOpenWindowsAutomatically(true);
mWebSettings.setSupportZoom(true);
I use the following WebChromeClient overload for handling geolocation requests from JavaScript:
protected class EmbeddedChromeClient extends android.webkit.WebChromeClient {
#Override
public void onGeolocationPermissionsShowPrompt(String origin,
android.webkit.GeolocationPermissions.Callback callback) {
// do we need to request permissions ?
if (ContextCompat.checkSelfPermission(EmbeddedBrowserActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// this should never happen, it means user revoked permissions
// need to warn and quit?
callback.invoke(origin, false, false);
}
else {
callback.invoke(origin, true, true);
}
}
}
To test this I use the following code (taken from Mozilla API help page, shortened here):
function geoFindMe() {
function success(position) {}
function error() {}
navigator.geolocation.getCurrentPosition(success, error);
}
What I see is that the call tonavigator.geolocation.getCurrentPosition(success, error) in JavaScript never returns. I see that onGeolocationPermissionsShowPrompt() method in Java gets properly called and as I check for permissions there I always get the result 0, i.e. PackageManager.PERMISSION_GRANTED, so callback.invoke(origin, true, true) is executed on every call. If I try several times, I see several calls to my Java code. Still, nothing happens on the JavaScript side here after I call invoke().
I added the code to check for granted permissions using the invocation of getOrigins(ValueCallback<Set<String>> callback) in GeolocationPermissions class, as described here in the documentation. I see in the callback that my origins are allowed to request locations (they are listed in the set).
Any ideas what might be wrong here?
Try with options to set timeout (source):
var options = {
enableHighAccuracy: true,
timeout: 10000,
maximumAge: 0
};
navigator.geolocation.getCurrentPosition(success, error, options);
If it fails then try to override getCurrentPosition (source):
(function() {
if (navigator.geolocation) {
function PositionError(code, message) {
this.code = code;
this.message = message;
}
PositionError.PERMISSION_DENIED = 1;
PositionError.POSITION_UNAVAILABLE = 2;
PositionError.TIMEOUT = 3;
PositionError.prototype = new Error();
navigator.geolocation._getCurrentPosition = navigator.geolocation.getCurrentPosition;
navigator.geolocation.getCurrentPosition = function(success, failure, options) {
var successHandler = function(position) {
if ((position.coords.latitude == 0 && position.coords.longitude == 0) ||
(position.coords.latitude == 37.38600158691406 && position.coords.longitude == -122.08200073242188))
return failureHandler(new PositionError(PositionError.POSITION_UNAVAILABLE, 'Position unavailable'));
failureHandler = function() {};
success(position);
}
var failureHandler = function(error) {
failureHandler = function() {};
failure(error);
}
navigator.geolocation._getCurrentPosition(successHandler, failureHandler, options);
window.setTimeout(function() { failureHandler(new PositionError(PositionError.TIMEOUT, 'Timed out')) }, 10000);
}
}
})();
As a third option annotate with #JavascriptInterface (source) in EmbeddedChromeClient
Also add at the proper place in your code:
mWebSettings.setJavaScriptEnabled(true);
//...
mWebSettings.setSupportZoom(true);
webView.addJavascriptInterface(new EmbeddedChromeClient(webView), "injectedObject");
webView.loadData("html here", "text/html", null);
The last option is just to use tags in html, load the html from disk storage, replace tags in the calling function, load the html/string in the webView. I have used this approach before in Android when positioning frustrated me too much. Then you don't have to worry about https either.
Looks like there are 2 different issues in your case:
getCurrentPosition never fails
getCurrentPosition never succeed
First point could be just because method has infinite timeout
The default value is Infinity, meaning that getCurrentPosition() won't return until the position is available.
Second point could be tricky, there is a param maximumAge which means
The PositionOptions.maximumAge property is a positive long value indicating the maximum age in milliseconds of a possible cached position that is acceptable to return. If set to 0, it means that the device cannot use a cached position and must attempt to retrieve the real current position. If set to Infinity the device must return a cached position regardless of its age.
0 by default means that device won't use cached position and will try to fetch the real one and it could be an issue for long response.
Also you could check this reporst which could mean that this API doesn't work really good on Android:
https://github.com/ionic-team/ionic-native/issues/1958
https://issues.apache.org/jira/browse/CB-13241
*Cordova leaves geolocation stuff for browser.
Change your request for permission like this,
ActivityCompat.requestPermissions(this, new String[]{
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION
},0);
This seems to work.
Actually, navigator is a child of browser global object, the window. you should first access to window then call the navigator. In some modern browsers, In addition to the window, some child object is presented like a global object, for example: location, navigator and etc.
The WebView has no global object window. So you can add it manually, for this action please read this medium article.
Maybe your code will be like below:
my_web_view.evaluateJavascript("javascript: " + "updateFromAndroid(\"" + edit_text_to_web.text + "\")", null);
And then add JavaScript interface, like the window object, to this evaluator:
my_web_view.addJavascriptInterface(JavaScriptInterface(), JAVASCRIPT_OBJ); //JAVASCRIPT_OBJ: like window, like navigator, like location and etc.
For applications targeting Android N and later SDKs (API level > Build.VERSION_CODES.M), the method onGeolocationPermissionsShowPrompt (String origin, GeolocationPermissions.Callback callback) is only called for requests originating from secure origins such as HTTPS. On non-secure origins, geolocation requests are automatically denied.
You could narrow down your problem by yourself if you had tried putting a breakpoint or a log inside the method.
You have two options:
Target a lower level API, which is obviously much easier but not really appreciated.
Set up SSL in your website.
In case some of you are still experiencing this issue, I was able to get the navigator.geolocation.getCurrentPosition() to work for me by setting some values for the options parameter, as follows:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(
async (p) => {
await this.workMyCurrentPosition(p);
},
(e) => this.navigatorError(e),
{ timeout: 7000, enableHighAccuracy: true, maximumAge: 0 }
);
}
Hope it works for you!
There is an extensive post on this subject:
navigator.geolocation.getCurrentPosition sometimes works sometimes doesn't
Apparently the solution is to check on navigator.geolocation then make the call:
if(navigator.geolocation) { // dummy call
navigator.geolocation.getCurrentPosition(success, error)
}
I experienced this problem on Android 8. The error callback was called with error.code==1 "PERMISSION_DENIED".
https://developers.google.com/web/updates/2016/04/geolocation-on-secure-contexts-only
Geolocation API Removed from Unsecured Origins in Chrome 50
Meaning, the URL of your app must begin with https:// for the call to work.
I am creating a secure chrome extension that is supposed to safely connect to an external https url that i do not own and that doesnt utilize certificate pinning itself. Using HPKP, i want to pin the certificate in the browser extension to verify the host is legit.
I did some research where its claimed that this is not possible apart from calling chrome via command line. It was hard finding a lot of informations about HKPK for chrome (extensions)
Using webRequest & webRequestBlocking permissions i tried to intercept the response header. The theory is that if i can add the HPKP header into the response header, i can simulate the browser filtering future traffic from this header. I do this with the code below.
chrome.webRequest.onHeadersReceived.addListener(function(details) {
//86400 = 1 day to prevent lockout on missing update
var addHeader = [
{name:"Public-Key-Pins", value:'max-age=30; pin-sha256="+sCGKoPvhK0bw4OcPAnWL7QYsM5wMe/mn1t8VYqY9mM="; pin-sha256="bumevWtKeyHRNs7ZXbyqVVVcbifEL8iDjAzPyQ60tBE="'},
{name:"Strict-Transport-Security", value:"max-age=86400"}
];
for(var i=0;i<details.responseHeaders;i++) {
var existHeader = details.responseHeaders[i];
for(var o=0;o<addHeader.length;o++) {
var writeHeader = addHeader[o];
if(existHeader.name.toLowerCase() == writeHeader.name.toLowerCase()) {
details.responseHeaders[i].value = writeHeader.value;
addHeader[o].written = true;
}
}
}
for(var i=0;i<addHeader.length;i++) {
var writeHeader = addHeader[i];
if(!writeHeader.hasOwnProperty("written")) details.responseHeaders.push({name:writeHeader.name, value:writeHeader.value});
}
return {responseHeaders: details.responseHeaders};
}, {urls: ["<all_urls>"]}, ["blocking","responseHeaders"]);
chrome.webRequest.onResponseStarted.addListener(function(details) {
console.log(details);
}, {urls: ["<all_urls>"]}, ["responseHeaders"]);
The SHA256 hashes are random certificates found online, and when i call a website i expect the browser to block the request as long as its an https url (as RFC ignores http ones). Sadly, nothing happens at all, but the console returns that the data did get indeed attached.
My question is: Did i do something wrong at another place, or is there any other way to have my browser extension verify its talking to the correct host?
If you try to load with Chrome: http://sdqdsqdqsdsqdsqd.com/
You'll obtain:
ERR_NAME_NOT_RESOLVED
I would like, with a bookmarklet, to be able to get the current domain name and redirect it to a whois page in order to check if the domain is available.
I tried in the console:
window.location.href
but it outputs:
"data:text/html,chromewebdata"
Is there any way to retrieve the failed URL?
The solutions given by others didn't work (maybe because I was getting a different error or have a newer version: Chrome 55):
document.querySelector('strong[jscontent="hostName"]').textContent
but the same can be achieved via:
document.querySelector('#reload-button').url
A potentially more future-proof version (from Thomas's comment)
loadTimeData.data_.summary.failedUrl
So a cross-version solution incorporating all workarounds:
var url = (location.href === 'data:text/html,chromewebdata'
&& loadTimeData.data_.summary.failedUrl
|| document.querySelector('#reload-button').url
) || location.href;
var hostname = (location.href === 'data:text/html,chromewebdata'
&& loadTimeData.data_.summary.hostName
|| document.querySelector('strong[jscontent="hostName"]').textContent
) || location.hostname;
On the Chrome error page, location.href doesn't point to the domain you tried to visit, since it's an internally-hosted page.
However, the domain name you tried to visit is available if you expand the "Show Details" link.
You can run this code in console (or a bookmarklet) to parse out the domain name:
document.querySelector('strong[jscontent="hostName"]').textContent
A modified version of nderscore's since you'll need to have an if statement for the return of the correct one.
function getUrl () {
if(window.location.hostname == "") {
return document.querySelector('strong[jscontent="hostName"]').textContent
} else{
return window.location.href;
}
}
While looking in source code of html page using Developer Tools (right-click on a web page, and select Inspect Element), I've found that full original failed URL is in a variable called
loadTimeData.data_.summary.failedUrl
In my case I have to update some 'incorrect part' of auto generated URL to 'correct part'. So I've created bookmarlet like this:
javascript: location.assign(loadTimeData.data_.summary.failedUrl.replace('IncorrectPart','CorrectPart'));
I am trying to write a PAC file which can read a Windows Environment Variable that is set by GPO (e.g. ENABLE_PROXY = FALSE/TRUE)
Based on whether this Variable is true or not will either return a correct proxy server (uk-proxy-01:80) or a localhost (localhost:80)
I have read references online that say a PAC file is just javascript code. My google searching hasn't returned anything that works.
All I essentially want is:
if ( ENABLE_PROXY == "TRUE" ){
return "PROXY uk-proxy-01:80";
else }
return "PROXY 127.0.0.1:80";
{
You will need to read the environmental variable:
var result = WScript.CreateObject("WScript.Shell").Environment("SYSTEM")("ENABLE_PROXY");
if (result === "TRUE") {
...