How to debug Safari ITP 2.0 requestStorageAccess failure - javascript

I'm currently working on making my code compatible with Safari ITP 2.0. In a method that is triggered on an onClick, I have code similar to the code below:
if (document.hasStorageAccess && document.requestStorageAccess) {
console.log('On Safari 12');
document.hasStorageAccess().then(
function successful(hasAccess) {
console.log('Testing if hasAccess');
if (hasAccess) {
console.log('Access granted already');
} else {
console.log('Requesting access');
document.requestStorageAccess().then(
function successful() {
console.log('Access request was a success');
window.location.reload();
},
function fail() {
console.log('Storage Access API call failed...');
});
}
},
function rejected(reason) {
console.log('hasStorageAccess failed: ', reason);
});
}
However, running this gets me the logging statement "'Storage Access API call failed...'" without a prompt from Safari - what's more frustrating is that it previously worked but is now starting to fail again. Is there any way to debug why the call to requestStorageAccess failed?
I tried enabling the ITP debug mode logs as per the instructions, and I did get some use out of that. It gave me this error once:
2018-09-04 15:15:40.930157-0700 0x110c87 Info 0x0
69100 Safari Technology Preview: (WebKit)
[com.apple.WebKit:ResourceLoadStatisticsDebug] Cannot grant storage
access to example.com since its cookies are blocked in third-party
contexts and it has not received user interaction as first-party.
But when I accessed it in a first party context and reloaded the page, I got no further reasons why the call to requestStorageAccess was failing. If anyone has any ideas, please let me know what you suggest I try to debug the issue.
Thank you!

There are updated debug instructions: https://stackoverflow.com/a/61532464/13443904
But I also wanted to provide some more concrete steps for people struggling with Safari ITP, since it took ages to figure out all the rules.
1) Don't embed requestStorageAccess inside hasStorageAccess. This loses the required user interaction (button click) needed to prompt for requestStorageAccess.
2) hasStorageAccess and requestStorageAccess are promises. Make sure any follow-up actions are nested -inside- the success closures of the promise (ie, if you have a submit button, don't let it submit the form before you've finished asking for requestStorageAccess).
3) You have to set a 1st party cookie and have a user interaction from a top-level window for your subdomain BEFORE you can requestStorageAccess for a 3rd party cookie via user interaction in an iframe for your subdomain. Setting a cookie/interaction in the main domain/parent window does not count.
4) Testing in Safari Technology Preview makes resetting the ITP choices easier - just clear history and quit/reopen and you should go back to scratch. Safari seems to cling to the values forever.

Did you interact (tap/click/form entry) with your website as first party? A mere visit does not suffice. The user has to interact with a webpage with the same eTLD+1 as the domain that is requesting storage access.
Example:
1) service.example is classified with tracking abilities by ITP.
2) The user visits and interacts with a page from service.example or *.service.example.
3) service.example calls the Storage Access API under othersite.example when the user taps in service.example’s iframe.

Related

Angular 6: Trying to make synchronous call (delete) on browser close event (beforeunload/unload event of browser)

Actually, I want to update a flag in Db using a service call(Delete method) once the user close the browser. I am able to detect browser close action using onbeforeunload and onunload events but async call doesn't work for me(sometimes in debugging mode it works fine but on higher env it doesn't work).
Then, I tried to make sync request but then I found that Chrome now disallows synchronous XHR during page dismissal when the page is being navigated away from or closed by the user.
check link : https://www.chromestatus.com/feature/4664843055398912
I have tried new XMLHttpRequest() as sync, fetch api also Navigator.sendBeacon() but unfortunately nothing works for me.
Please suggest something which works because I have visited so many posts but nothing works for me.
Thanks in advance.
I have some solution for this. Hope so any one of them solves your issue.
constructor() {
window.onbeforeunload = ()=>{
//call API here
}
}
In your component constructor write above code
OR
In my opinion the better idea is making the heartbeat api that sends requests every N seconds to notify server that the session is active and the user is online. On the server check every M minutes if there was no heartbeat requests for more than N seconds: if it is so - execute the API request(what you wanted to execute on crash).
OR
'beforeunload' would be trigger when refreshing pages, closing tab, or closing the browser.
#HostListener('window:beforeunload', ['$event'])
beforeUnload(e: Event) {
e.returnValue = false;
}
OR
It is not possible to ensure that every time an user exits a browser page a specific function will be triggered. The reason is that the browser could close the window for many reasons. Yes it could be a user action but this is not the only case. For example The browser could crash.
In my case I will have to find another strategy to track the time the user stays on the page. For example I am planning to send a lot of API calls before the user exits with all the informations I need to understand his stay on the page. I will update the answer when I will reach a good solution. Anyway I will still wait for better answers.
You can use the fetch API.
The syntax would be:
fetch('API', {
method: 'POST', // Other opn are also supported like GET,PUT DELETE
body: '',
keepalive: true
});
Just an additional read:
https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

Quickbase usertoken to supersede current user credentials/permissions

I have a custom button which is to query and possibly update an Administration App in Quickbase, which the current user doesn't require access to.
I have JS code which is executed on a button click by the user to check the admin app, etc...
my API call to check the app has the appropriate apptoken and usertoken. However, the browser still has the current user's session cached, so the API call errors out with an access denied error message.
I'm looking for either a way to make a hidden incognito window, to then execute this code, or a way to problematically force the usertoken to supersede the current user access/permissions.
I've seen where chrome extensions can use chrome.windows.create... but I have no experience with extensions, and Ideally, I don't want to have to have an extension for just this functionality, and have to possibly install it on every user's PC for this to work...
Here is a snippet of my current code... This code does work if someone has permissions to the Administration App... but this code is residing in a different application:
PreProcURL = "https://<domain>.quickbase.com/db/<dbid>?a=API_DoQuery&apptoken=<>&usertoken=<>&query={'3'.EX.'1'}";
PreProcQuery.open('GET', PreProcURL, 'async');
PreProcQuery.send();
PreProcQuery.onload = function(){
console.log(PreProcQuery.responseXML);
RunBit = (PreProcQuery.responseXML.documentElement.getElementsByTagName("runbit"))[0].innerHTML;
SupportData = (PreProcQuery.responseXML.documentElement.getElementsByTagName("supportdata"))[0].innerHTML;
if(RunBit != "1"){
$.get("https://<domain>.quickbase.com/db/<dbid>?a=API_EditRecord&rid=1&_fid_6=1&_fid_7="+rid+"&apptoken=<>&usertoken=<>");
}else{
if(SupportData == rid){
alert("This PreProc File is already in progress... please wait.");
}else{
alert("Another PreProc is already in progress... please wait.");
}
}
};
Thanks in advance for any assistance on this.
API calls executed in JavaScript that is hosted within quickbase.com (button, pages, etc.) will run as that logged in user that triggered the script. The usertoken gets ignored.
The most common way to accomplish what you are after is to write the API_DoQuery code on a server side location and then trigger it from your JS code.

Facebook Canvas, Unable to login from facebook on mobile devices

I have a canvas facebook application which has both a web page and a designated mobile page.
The web page works fine and also when simulating the browser to mobile with the console everything works fine.
But, when I try to run the app from the facebook mobile app the canvas app loads (which is correct), but it does not login.
I am using the FB.login function.
login: function () {
var deferred = $q.defer();
FB.login(function (response) {
if (!response || response.error) {
deferred.reject('Error occured');
} else {
deferred.resolve(response);
}
}, {
scope: 'email, user_friends'
});
return deferred.promise;
},
and in the settings > advanced - I have the:
Client OAuth Login,Web OAuth Login, Embedded Browser OAuth Login,Valid OAuth redirect URIs and Login from Devices filled correctly.
but still from the facebook mobile app the canvas app does not preform the login.
I have been trying to get this to work all day.
and I cant find a solution anywhere.
I also cant debug the mobile facebook app.
any ideas how to approach this issue?
EDIT
Also looked at my Node server logs and I see that the FB.login is not even called.
EDIT 2
I ended up replacing the login with getLoginStatus which poses no problem to me since its a facebook canvas app... but the question still remains on how to do the login.
EDIT 3 11/26/2015
well so getLoginStatus did not completely solve my issue since it does not in fact log the user in so for the canvas games you probably need to login for the first entry if you need permissions... my solution was to add the login if the getLoginStatus returns not_autorized like so:
/**
* [getLoginStatus get the FB login status]
* #return {[type]} [description]
*/
getLoginStatus: function () {
var deferred = $q.defer();
FB.getLoginStatus(function (response) {
if (response.status === 'connected') {
deferred.resolve(response);
} else if (response.status === 'not_authorized') {
_fbFactory.login().then(function (fbLoginResponse) {
deferred.resolve(fbLoginResponse);
});
} else {
deferred.reject('Error occured');
}
});
return deferred.promise;
},
But wait, there is more... the FB.login function will not work well on mobile canvas games (not sure if its just not triggered or the browsers blog the popups or both). anyway you need to actively call it via button... so for mobile canvas games I had to add a start playing button and then the login does work..
EDIT 4 (Final)
eventually I noticed that FB.login() does not get triggered unless its an external event that triggers it, so I had to make a change for Mobile canvas where if the getLoginStatus doesnt return connected then I show a login button which does the login... the rest stayed the same.
what I did for mobile was similar to the accepted answer only to suit my needs...
I hope this helps someone besides me...
Make sure you're calling FB.login() with an event triggered by the user, such as an onclick on a button, as browsers can block potentially unsafe/dangerous javascript that's called directly. This is an extra layer of security for the end-user. There's 2 ways to create a login button:
Generate a login button with facebooks login button generator:
https://developers.facebook.com/docs/facebook-login/web/login-button
The generated login button will look similar to this:
<fb:login-button scope="public_profile,email" onlogin="checkLoginState();">
</fb:login-button>
Create your own html and use an onclick event to call FB.init():
<button onclick="FB.init()">Login</button>
Notes from the Facebook developers website:
As noted in the reference docs for this function, it results in a
popup window showing the Login dialog, and therefore should only be
invoked as a result of someone clicking an HTML button (so that the
popup isn't blocked by browsers).
https://developers.facebook.com/docs/facebook-login/web
Also, FB.getLoginStatus is the correct first step in logging in to check whether your user is logged into facebook and into your app.
There are a few steps that you will need to follow to integrate
Facebook Login into your web application, most of which are included
in the quickstart example at the top of this page. At a high level
those are:
Checking the login status to see if someone's already logged into your app. During this step, you also should check to see if someone
has previously logged into your app, but is not currently logged in.
If they are not logged in, invoke the login dialog and ask for a set of data permissions.
Verify their identity.
Store the resulting access token.
Make API calls.
Log out.
I see that your game doesn't require a login anymore, but maybe others will find this answer useful. :)

Sending commands from server side (.NET) to browser

We have some web application that allows users login and do some work.
But sometimes users work with our web site opening more then one browser and this causes us a lot of problems.
How could we implement the following - on user log in to our web site, make automatic log out in all his previously logged in browsers?
Thanks a lot.
You can use JS localStorage on page load to detect a user login, the event will be fired on every tabs or window opened within the same domain :
function storageChange(event) {
if(event.key == 'user_login') {
// logout - except current window
}
}
window.addEventListener('storage', storageChange, false);
//when user logs in
window.localStorage.setItem('user_login', true);
That will work only if the user is using the same browser multiple times.

Detect Internet Connection as in Gmail Javascript

I'm creating an HTML autorun. There is no restriction in using javascript as it will be run from XULRunner. I want a way to detect if internet connection exist or not. This doesn't work for me
$(document).ready(function() {
var online = navigator.onLine;
// a workaround for a flaw in the demo system (http://dev.jqueryui.com/ticket/4375), ignore!
function doit() {
if (navigator.onLine(connected)){
alert("YES!");
} else {
alert("NO!");
}
}
Is there a better way?
Update: Came to know that the code above only detects the browser state and not if internet is available. For me the contact form in the autorun has to check if internet is connected and alert the user.
Use an XMLHttpRequest in javascript to request a small file from your server. If the request returns an error or times out, then the site is probably unreachable. If you don't have a particular webserver to test on, you could use something with a high degree of reliability, like the Google server.
Though, if you do use the Google server that wouldn't necessarily correspond to your own site being reachable, it would just mean that you are able to connect to the internet. Your own site may down\otherwise unavailable.

Categories