Geolocation API doesn't work on mobile - javascript

I'm writing my web application on React/Redux. And I need to get user location with a help of Geolocation API. On desktop browsers everything works fine, but on mobile phones (checked out on Xiaomi Redmi Note 3 and iPhone 5s) it throws error code 1 - permission denied. And it doesn't requests any permissions to get the location.
Here's a test sample which I ran on my site:
componentDidMount() {
if (window.navigator.geolocation) {
window.navigator.geolocation.getCurrentPosition(position => {
alert(position.coords.latitude + ' ' + position.coords.longitude);
}, err => {
alert('ERROR: ' + err.code);
});
} else {
alert('Geolocation API is not supported!');
}
}
What's the solution of this problem?

Got the same Problem... Solved:
Check your phone permissions for sharing your location.
On iPhone:
Settings -> Location Services -> [your Browser]
https://support.apple.com/en-ca/HT203033
Added:
Chrome requires https for geolocation usage:
https://developers.google.com/web/updates/2016/04/geolocation-on-secure-contexts-only

I've got the solution. I'm using the Web Application Manifest and it needed to set the permission to use Geolocation API.
We just need to set an "required_features" option at manifest.webapp file:
{
"required_features": ["geolocation"]
}
Hope it will be useful for somebody ;)

As of the Year 2021, this still does not work.
This is the link in that error message.In case you're wondering, it talks about "prefer secure origins for powerful new features" and location is consider one of those powerful features.
To generate the above, update the error section as follows:
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(position => {
// other
},
err => {
// include the "code" part
alert(`ERROR(${err.code}): ${err.message}`)
});
};
On desktop during development...It works because if you read from the above link you will note that localhost is considered a secure origin.
In fact, even the chrome link shared in #chrisheyn's answer above, there is a section "Does this affect local development?" and explains why this should work on locahost.
So how about Mobile during development?Notice that react serves the app over your network e.g. http://192.168.0.134:3000 and that is definitely not considered a "secure origin" at all.
This question "Can I detect at runtime if the geolocation was blocked because of not being on a secure context
" mentions that... Errors due to this secure-context issue will return a code of 1 which is a "Permission Denied Error".
What's the solution?
Until the react team updates how your mobile picks the app during development, there is absolutely nothing you can to solve this issue.
To use the HTML5 Geolocation API, you will need to run the app over HTTPS. This means push your app to the cloud/host (in order to test this feature) or if you can some manage to get this network url http://192.168.0.134:3000 to do https The latter option, i believe, is much harder but I'd be interested to know if someone pulls it off.

Related

WebAuthn credentials.get bug after discoverable credentials test

Having got Platform Authenticator and Multi-device Authentication working I am trying to expand my FIDO2 knowledge by reading through WebAuthn issues on GitHub To this end I was testing Discoverable Credentials (i.e. specifying allowCredentials as empty [])
I couldn't get the signing to match so reverted to allowing only the credential id I just CREATEd but now I still keep getting prompted to specify a device when I call GET also the signatures don't match. This is the JS code: -
var allowCredentials = [{
type: "public-key",
id: Uint8Array.from(atob(credentialId), x => x.charCodeAt(0)).buffer
}]
var getAssertionOptions = {
timeout: 60000,
challenge: Uint8Array.from(serverChallenge.Token, c => c.charCodeAt(0)).buffer,
allowCredentials: allowCredentials,
userVerification: "required"
};
return navigator.credentials.get({
publicKey: getAssertionOptions
}).then(rawAssertion => {
var assertion = {
id: base64encode(rawAssertion.rawId),
clientDataJSON: utf8Decoder.decode(rawAssertion.response.clientDataJSON),
userHandle: base64encode(rawAssertion.response.userHandle),
signature: base64encode(rawAssertion.response.signature),
authenticatorData: base64encode(rawAssertion.response.authenticatorData)
};
and this is the C# signature check: -
using (ECDsa dsa = ECDsa.Create(ecparams))
{
if (dsa.VerifyData(data, ECDsaSig, HashAlgorithmName.SHA256))
{
Console.WriteLine("The signature is valid.");
}
else
{
Console.WriteLine("The signature is not valid.");
return FAIL_STATUS;
}
}
Now this code "used to work" using my Samsung phone but then (IIRC) I wasn't being reprompted for a device for verification. UPDATE: Sometimes the first time after CREATE the GET will work by returning a correctly signed load. But now I can't reproduce that :-(
Look this clearly sounds like developer/pilot error on my behalf but I just want to see if it rings any bells? I have cleared all cache, rebooted, can't find any "credentials" in and password history, and am at a loss. I thought there may be some signature timeout but I've extended everything I could
Q1. Was I always prompted to select a device even though I said only allow this Samsung credential
NB: If I use the platform authenticator on my phone then the same thumb-print works. EC encryption.
Chrome: Version 103.0.5060.134 (Official Build) (64-bit)
I'm assuming because you are testing on a Samsung device that you are running Android. Sadly at the moment Android does not support discoverable credentials / resident keys. Your previous flows would work as you are able to invoke the WebAuthn ceremony with credentials populating the allowList.
I tested on a WebAuthn environment of mine and confirmed that I am getting an error that reads "Use of an empty 'allowCredentials' list is not supported on this device" (I'm using Chrome on a Pixel 5 device).
Google has indicated that discoverable credential support is coming to Android soon to help support their passkey implementation.
For now I would recommend that you test your discoverable credential flow on another device with a platform authenticator to see if it works.
As for some of your other errors, I may need more information to help identify the issue.
Hope this helps

Google Auth OAuth 2.0 SvelteKit wierd behavior

I am using Google Auth OAuth 2.0 One Tap Sign and Sveltekit,
and I got some really weird behavior,
I followed this doc https://developers.google.com/identity/gsi/web/guides/overview with javascript
onMount(async () => {
const handleCredentialResponse = async (response) => {
console.log('Encoded JWT ID token: ' + response.credential);
};
google.accounts.id.initialize({
client_id: clientId,
callback: handleCredentialResponse,
});
google.accounts.id.renderButton(
document.getElementById('buttonDiv'),
{ theme: 'outline', size: 'large' } // customization attributes
);
google.accounts.id.prompt();
});
the code from the doc.
Sometimes it works everything goes well,
Sometimes I got
Uncaught (in promise) ReferenceError: google is not defined
And some mobile / mobile browsers I get
[GSI_LOGGER]: The given origin is not allowed for the given client ID.
but works on laptop
Hope someone can understand and help.
Do we have any way to check logs for investigation?
I got your code to successfully run without modification: https://google-signin-kit.vercel.app/ (This app is in "dev" mode so signin may only succeed with my Google account. If you clone my repo and set your Google client id, signin will work for you.)
I would check how my code is different from your code outside onMount(). For example, how did you include the Google javascript? I describe one major change below.
You also need to check your Google app settings. [GSI_LOGGER]: The given origin is not allowed... is fixed by adding the HTTPS app domain to your Google app "Authorized JavaScript origins." Non-HTTPS domains are not allowed. For example, these domains would not work:
https://google-signin-kit-leftium.vercel.app/ (Not added as Authorized JavaScript origin)
http://google-signin-kit.vercel.app/ (Not HTTPS, if Vercel did not automatically redirect to HTTPS)
Of course, raw IP addresses will not work, either.
localhost is a special exception, but not easy (impossible?) to access from mobile.
ReferenceError: google is not defined (sometimes) happens because onMount() runs before the Google script is loaded.
To get a consistent reproduction, USB debug/inspect Android Chrome and set "disable caching" and throttling to "Slow 3G." (I could not reproduce on desktop Chrome).
Fixed by removing defer async when including Google's script: <script src="https://accounts.google.com/gsi/client"></script>
It should also be possible to call a function after the script is loaded, but I got inconsistent results in SvelteKit. For some reason Kit doesn't always call the load function. Possibly a bug?
Ideally, the Google script should be imported, but I couldn't find a version of the Google script that was built for importing. You may be able to construct a library that you can import? Importing would compile the Google script code into your app, tree-shaking the unused portions. Thus saving a network request and bandwidth.
Another workaround is to have your onMount function check for the google variable. If google is still undefined, call your function again after a certain timeout.

How to enable geolocation using Firefox/Chromium on Ubuntu 16.04

I'm building a node app that returns the user's geolocation, but I'm having a hard time testing it because I can't access geolocation on my computer. I tried using my localhost server in both Firefox and Chromium - Firefox asks for my permission but then can't retrieve it, and Chromium doesn't even get that far. When I deploy it to Heroku, I still can't access it on the computer. On my iPhone, Firefox still has no luck but Safari can do it. I don't know if my problem is in Ubuntu itself (can it block things like that?) or if both Firefox and Chromium have the same issue.
I doubt my code will be especially useful, but here it is anyway:
const locationButton = jQuery('#send-location');
locationButton.on('click', function() {
if (!navigator.geolocation) return alert('Geolocation not supported by your browser.');
navigator.geolocation.getCurrentPosition(function (position) {
socket.emit('newLocationMessage', {
latitude: position.coords.latitude,
longitude: position.coords.longitude
}, function (mapLink) {
alert(mapLink);
});
}, function () {
alert('unable to fetch location.')
});
});
The app is also up at http://rocky-brook-97128.herokuapp.com/.
Thanks for any guidance on this!
As of Chrome 50, the Geolocation API will only work on secure contexts such as HTTPS. If your site is hosted on an non-secure origin (such as HTTP) the requests to get the users location will no longer function.
Try it on https.
https://rocky-brook-97128.herokuapp.com/
(1) In a new tab, type or paste about:config in the address bar and press Enter/Return.
(2) In the search box above the list, type or paste geo and pause while the list is filtered
(3) If the geo.wifi.uri preference is bolded and "modified" or "user set", you can right-click > Reset it to the default
If Firefox sends anything to the geolocation service, the address should appear in the Browser Console
You can inspect and manage the permissions for all domains on the about:permissions page

FB.login() fails with "Unsafe JavaScript attempt to initiate navigation for frame" on Android Chrome but not desktop Chrome

I have a Facebook JS SDK login flow here: https://web.triller.co/#/user/login
When the user taps the Facebook button, the following function is executed:
loginFacebook()
{
const fbPromise = new Promise((resolve, reject) => {
FB.login(resp => {
if (resp.authResponse)
{
resolve(resp.authResponse.accessToken);
}
else
{
console.log(resp);
reject(new Error('Facebook login canceled or failed.'));
}
});
});
return fbPromise
.then(accessToken => api.postJson('user/login_facebook', { accessToken }))
.then(this._handleLogin.bind(this));
}
Basically, it calls FB.login(), and expects to receive a valid resp.authResponse. Unfortunately, it doesn't, even after successfully authenticating on the Facebook popup/tab. Instead, we receive { authResponse: undefined, status: undefined } and the following error from the browser:
Unsafe JavaScript attempt to initiate navigation for frame with URL
'https://m.facebook.com/v2.8/dialog/oauth?foo=bar'
from frame with URL 'https://web.triller.co/#/user/login?_k=cmzdb6'.
The frame attempting navigation is neither same-origin with the
target, nor is it the target's parent or opener.
The error occurs immediately after authenticating within the Facebook popup/tab, and it only occurs on Android Chrome. Desktop Chrome (on a Mac) does not show the same error. Safari on iOS does not show the error, either.
Any thoughts on what's going on? Why the difference between Android Chrome and desktop Chrome? Could it have something to do with the hash in the URL?
In desktop this issue can be caused by XFINITY Constant Guard Protection Suite Chrome extension. Disble it and problem will be solved.
In Android, try removing XFINITY or similar security extensions or applications (Norton security antivirus).
https://developer.salesforce.com/forums/?id=906F00000008qKnIAI
I think it fails because of the m.facebook.com/... based on this https://en.wikipedia.org/wiki/Same-origin_policy#Origin_determination_rules (see the case for http://en.example.com/dir/other.html and why it fails). Although it shouldn't based on what I've done with the fb api this is weird, try making a cors request instead as a workaround?
This is a known issue here https://code.google.com/p/android/issues/detail?id=20254.
When the window.open is called without proper arguments, it will not be opened as expected.
It can be overcome by either updating the browser (for client, check the browser version and if old one, force them to update it).
Otherwise (not applicable for you since you can't change the FB function), pass the correct arguments to window.open
Interestingly I only seem to get this when I am using the mobile device simulator in Chrome.
Looking at the source code for the Facebook SDK there is the following line:
url: i.resolve(a.display == "touch" ? "m" : "www") + "/" + d.url,
Now "m" then becomes "m.facebook.com" whereas "www" becomes "www.facebook.com". So it's using a different URL based on whether or not it's touch.
Now they're the same domain anyway, and the connect API is loaded from facebook.net (not .com) so it's not as simple as just being a different domain. However I suspect the issue could be related to this.
In either case when not in mobile device testing mode I don't get the error.

Chrome extensions for silent print?

I have made a silent print web application that prints a PDF file. The key was to add JavaScript to the PDF file that silently print itself.
To do this I open the PDF with acrobat reader in chrome, that allow me to execute the script (with the proper permissions).
But as it was announced this solution won't work after chrome 45 because the npapi issue.
I guess a possible solution could be to use the recently release printProvider of chrome extensions.
Nevertheless I can't imagine how to fire any of the printProvider events.
So the question is: Is ok to think in chrome extensions to make a silent print web application, and how can I fire and handle a print job for an embedded PDF of a HTML Page.
Finally I reached an acceptable solution for this problem, as I couldn't find it out there, but read to many post with the same issue I will leave my solution here.
So first you need to add your printer to the Google Cloud Print and then you will need to add a proyect to the Google Developers Console
Then add this script and any time you need to print something execute the print() function. This method will print the document indicated in the content
The application will ask for your permission once to manage your printers.
function auth() {
gapi.auth.authorize({
'client_id': 'YOUR_GOOGLE_API_CLIENT_ID',
'scope': 'https://www.googleapis.com/auth/cloudprint',
'immediate': true
});
}
function print() {
var xhr = new XMLHttpRequest();
var q = new FormData()
q.append('xsrf', gapi.auth.getToken().access_token);
q.append('printerid', 'YOUR_GOOGLE_CLOUD_PRINTER_ID');
q.append('jobid', '');
q.append('title', 'silentPrintTest');
q.append('contentType', 'url');
q.append('content',"http://www.pdf995.com/samples/pdf.pdf");
q.append('ticket', '{ "version": "1.0", "print": {}}');
xhr.open('POST', 'https://www.google.com/cloudprint/submit');
xhr.setRequestHeader('Authorization', 'Bearer ' + gapi.auth.getToken().access_token);
xhr.onload = function () {
try {
var r = JSON.parse(xhr.responseText);
console.log(r.message)
} catch (e) {
console.log(xhr.responseText)
}
}
xhr.send(q)
}
window.addEventListener('load', auth);
<script src="https://apis.google.com/js/client.js"></script>
Anyway this script throw a 'Access-Control-Allow-Origin' error, even though this appears in the documentation... I couldn't make it work :(
Google APIs support requests and responses using Cross-origin Resource Sharing (CORS). You do not need to load the complete JavaScript client library to use CORS. If you want your application to access a user's personal information, however, it must still work with Google's OAuth 2.0 mechanism. To make this possible, Google provides the standalone auth client — a subset of the JavaScript client.
So to go throw this I had to install this chrome extension CORS. I'm sure that some one will improve this script to avoid this chrome extension.
You can register an Application to a URI Scheme to trigger the local application to print silently. The setting is pretty easy and straightforward. It's a seamless experience. I have posted the solution here with full example:
https://stackoverflow.com/a/37601807/409319
After the removal of npapi, I don't believe this is possible solely programmatically. The only current way I know to get chrome to print silently is using chrome kiosk mode, which is a flag (mode) you have to set when starting chrome.
Take a look at these SO posts:
Silent printing (direct) using KIOSK mode in Google Chrome
Running Chrome with extension in kiosk mode
This used to be possible using browser plugins (e.g. Java + NPAPI, ActiveX) but has been blacklisted by most browsers for several years.
If interested in modern solutions that use similar techniques, the architecture usually requires the following:
WebSocket, HTTP or Custom URI connection back to localhost
API that talks through web transport (JavaScript or custom URI scheme) to an app running locally.
A detail of projects (several of them are open source) that leverage these technologies are available here:
https://stackoverflow.com/a/28783269/3196753
Since the source code of these projects can vary (hundreds of lines to tens-of-thousands of lines), a code snippet would be too large unless a inquiring about a specific project's API.
Side note: Some technologies offer dedicated cloud resources, which add convenience at the expense of potential latency and privacy. At the time of writing this, the most popular "free" cloud solution -- Google Cloud Print -- is slated to be retired in December 2020.

Categories

Resources