I use the Phonegap Childbrowser for oAuth 2.0 authentication. After the authentication, I want to use Javascript in the web page to hide the Childbrowser without pressing the "done" button. How to do that?
For example, after authentication, we always get some callback parameters. That means our authentication is successful. At this time, we should close our browser, and I want to close the browser by Javascript without pressing any buttons.
Capture onLocationChange on childBrowser and check the url parameter to see if it contains what you're looking for. If so, call childBrowser.close().
One weirdness of ChildBrowser is that it doesn't have a .clear() method, so I've created a page called nothing.html that is blank. If you don't, you'll briefly see your auth page the next time you use ChildBrowser. This doubles as my redirectUrl for Facebook and Twitter auth. So when it gets to that page, I know it's time to close.
var URL_NOTHING = 'nothing.html';
window.plugins.childBrowser.onLocationChange = function ( url ) {
if ( url.indexOf( URL_NOTHING ) > -1 ) {
if ( url.indexOf( 'oauth_token' ) > -1 ) { //twitter
window.plugins.childBrowser.close();
//do twittery stuff
} else { //facebook
window.plugins.childBrowser.close();
//do facebooky stuff
};
};
};
ChildBrowser plugin has a close() method to close the window from javascript code.
window.plugins.childBrowser.close();
Related
Im implementing auth using this and am currently showing a loading icon in React when a user clicks the button to sign in and the auth2 account selection/login window shows.
However if a user closes the window, there doesnt seem to be any event fired i.e the signIn() function which returns a promise never resolves, I would have thought google would return an error for this promise if the window is closed. As a result there is no way for me to stop showing the loader icon and reshow the login menu.
I was wondering if anyone had a solution for this?
I try to modifiy my code that call Google OAuth 2.0 window.
You only have to add extra AJAX method that cover what is Google OAuth error result.
gapi.auth2.getAuthInstance().signIn()
Change it to this one,
gapi.auth2.getAuthInstance().signIn().then(function(response){
//If Google OAuth 2 works fine
console.log(response);
}, function(error){
//If Google OAuth 2 occured error
console.log(error);
if(error.error === 'popup_closed_by_user'){
alert('Oh Dude, Why you close authentication user window...!');
}
});
That's it...
For more detail about Google OAuth 2.0 information, you can visit this link.
https://developers.google.com/api-client-library/javascript/samples/samples#authorizing-and-making-authorized-requests
Sample code on JavaScript:
https://github.com/google/google-api-javascript-client/blob/master/samples/authSample.html
Although the API provides a mechanism for detecting when the user clicks the Deny button, there is not a built-in way for detecting that the user abruptly closed the popup window (or exited their web browser, shut down their computer, and so on). The Deny condition is provided in case you want to re-prompt the user with reduced scopes (e.g. you requested "email" but only need profile and will let the user proceed without giving you their email).
If the response from the sign-in callback contains the error, access_denied, it indicates the user clicked the deny button:
function onSignInCallback(authResult) {
if (authResult['error'] && authResult['error'] == 'access_denied') {
// User explicitly denied this application's requested scopes
}
}
You should be able to implement sign-in without detecting whether the window was closed; this is demonstrated in virtually all of the Google+ sample apps. In short, you should avoid using a spinner as you're doing and instead should hide authenticated UI until the user has successfully signed in.
It's not recommended you do this, but to implement detection of the pop-up closing, you could do something like override the global window.open call, then detect in window.unload or poll whether the window was closed without the user authenticating:
var lastOpenedWindow = undefined;
window.open = function (open) {
return function (url, name, features) {
// set name if missing here
name = name || "default_window_name";
lastOpenedWindow = open.call(window, url, name, features);
return lastOpenedWindow;
};
}(window.open);
var intervalHandle = undefined;
function detectClose() {
intervalHandle = setInterval(function(){
if (lastOpenedWindow && lastOpenedWindow.closed) {
// TODO: check user was !authenticated
console.log("Why did the window close without auth?");
window.clearInterval(intervalHandle);
}
}, 500);
}
Note that as I've implemented it, this mechanism is unreliable and subject to race conditions.
I have built an app using titanium alloy
index.js
// Use the Alloy.Globals.Facebook namespace to make Facebook module API calls
var facebookModule = Alloy.Globals.Facebook;
//set facebook app id
facebookModule.appid = Ti.App.Properties.getString("ti.facebook.appid");
//set permissions i.e what data I want
facebookModule.permissions = ['user_friends','user_photos'];
// Do not force a facebook html popover but use the native dialog if possible
facebookModule.forceDialogAuth = false;
//invoke method onto button from module
$.fbButton.style = facebookModule.BUTTON_STYLE_WIDE;
$.index.open();
In my index.js controller I have this segment of code, it executes and I am presented with a log in screen.
I then fall into 2 problems:
1) "FB Session: Should only be used from a single thread"
2) I am unable to get the access token.
Not sure how to resolve both as the inbuilt login function has it's own event handler.
Cheers
Like you said, the inbuilt login function does have it's own handler.. so you should listen for event changes, something like this:
facebookModule.addEventListener('login', function(e) {
if (e.success) {
Ti.App.Properties.setString('face_token', facebookModule.getAccessToken());
// DO SOMETHING WITH THE TOKEN - open new window, auth the user...
}
});
If you try to get the access token BEFORE the login event is fired, you'll end up bad.
Now about the single thread thing.. I did run into this a while back.. I'm not sure exactly what I did to solve it, but I think it might be related to opening multiple windows or event allowing more than one call to the facebook API. Try to check if you are closing your windows and if the login function is being called more than once.
Let me know if that works for you. Good luck.
I have a ASP.net MVC web application which consists of several pages. The requirement is like this:
when users are using the application, suppose user is in page 7, suddenly user navigates away from the application by typing a external internet URL say Google.com.
Now when user presses the back button of the browser, Instead of bringing him back to page 7, we need to redirect him to Page 0 which is the landing page of the application.
Is there any way to achieve this? we have a base controller which gets executed every time a page loads as well as a master page (aspx). Can we do something there so that this behavior can be implemented in all the pages?
I think the best solution is to use iframe and switch between your steps inside of iframe. It would be quite easy to do, because you don't need to redesign your application. Anytime when user tries to switch to other url and come back, the iframe will be loaded again from the first step.
Be sure to disable caching on every step of your application. You can do this by applying NoCache attribute to your controller's actions:
public class NoCache : ActionFilterAttribute
{
public override void OnResultExecuting(ResultExecutingContext filterContext)
{
filterContext.HttpContext.Response.Cache.SetExpires(DateTime.UtcNow.AddDays(-1));
filterContext.HttpContext.Response.Cache.SetValidUntilExpires(false);
filterContext.HttpContext.Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches);
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
filterContext.HttpContext.Response.Cache.SetNoStore();
base.OnResultExecuting(filterContext);
}
}
There is 2 case over here
First is browser in online mode, in this case you have to store your last page get request in session, if user hit back button it will re initiate get request for that page again you can trap it and send them to landing page, You have to take care that get request for page happen only once other action must be post.
Second is browser in offline mode, in this case you have to take care that your response should not put any cache foot print in browser, there are many code example you can found on net for this purpose.
I can offer the following idea:
When user press <a href='external url' onclick='clearHistory'>link</a>
You can save in browser history of the desired url:
<script>
function clearHistory()
{
var reternUrl = getReternUrl();
History.pushState({}, null, reternUrl);
}
</script>
more about history.js
Edit: ok, then handle beforeunload event:
$(window).on('beforeunload', function () {
var reternUrl = getReternUrl();
History.pushState({}, null, reternUrl);
});
EDIT: Shortened and slightly changed code to better answer exact question (based on first comment to this answer)
Addition to answer above about editing the browser history for the case where the user types the external URL in the browser address bar.
You could try to detect url change as posted in How to detect URL change in JavaScript.
Example of this using jquery (taken and edited slightlyfrom post linked to above):
For newer browsers:
$(window).bind('hashchange', function() {
/* edit browser history */
});
For older browsers:
function callback(){
/* edit browser history */
}
function hashHandler(callback){
this.oldHash = window.location.hash;
this.Check;
var that = this;
var detect = function(){
if(that.oldHash!=window.location.hash){
callback("HASH CHANGED - new hash" + window.location.hash);
that.oldHash = window.location.hash;
}
};
this.Check = setInterval(function(){ detect() }, 100);
}
hashHandler(callback); //start detecting (callback will be called when a change is detected)
I'll get back to you on bookmarks (still need to check that out).
I'm wrapping a web app in a Windows Store app shell using a x-ms-webview. This works fine, but I have one problem. I use PayPal and since PayPal doesn't allow to be iframed I need to open PayPal in a new browser window.
On regular browsers this isn't a problem. The window open and when the user returns from PayPal I can a callback on "opener" and update the users account.
But when doing this in a Windows Store app the window.open triggers IE to launch. The problem is to return to my app and let it know that the user finished the transaction.
My first idea was just to use a URI activation. This kind of works, but I having trouble knowing if the PayPal page was launch from a regular browser or an app. I also think it is confusing for the user to be taken to another app to make the purchase.
I would prefer to have the window open in my app, but I'm not sure how I would open open a new x-ms-webview as a modal window overlapping existing webview.
What is the best way to communicate from the current web view and the app?
Can I use postMessage to send messages between the app and the x-ms-webview even though the src of the web view is a http hosted site?
Thank you for your help.
I found a solution to this.
First, you will need to use a https url for the embedded site. The reason for this is that the solution include postMessage and invokeScriptAsync.
First, my markup in my app looks something like this to have one webview for the app and one web view for the PayPal popup.
<x-ms-webview id="webview" src="https://myapp"></x-ms-webview>
<div id="paypalContainer">
<div class="paypal-header"><button id="paypalClose" type="reset">Close</button></div>
<div class="paypal-body"><x-ms-webview id="paypalWebView" src="about:blank"></x-ms-webview></div>
</div>
Then, when the web app is ready to use PayPal, I use window.external.notify to send a message to the Windows Store app.
if (window.external && 'notify' in window.external) {
window.external.notify(JSON.stringify({ action: 'paypal' }));
}
The windows store app listens for Script Notify events and displays the paypalWebView.
webview.addEventListener("MSWebViewScriptNotify", scriptNotify);
function scriptNotify(e) {
var data = JSON.parse(e.value);
if (data.action === "paypal") {
var loading = document.getElementById("loading-indicator");
var container = document.getElementById("paypalContainer");
var paypalWebView = document.getElementById("paypalWebView");
var paypalClose = document.getElementById("paypalClose");
if (paypalWebView.src === "about:blank") {
paypalWebView.addEventListener('MSWebViewNavigationCompleted', function (e) {
loading.classList.remove('loading');
var successUrl = '/paypal/success';
if (event.target.src.indexOf(successUrl) !== -1) {
var operation = webview.invokeScriptAsync("updateUser");
operation.oncomplete = function () {
(new Windows.UI.Popups.MessageDialog("Your account is refreshed", "")).showAsync().done();
};
operation.start();
}
});
paypalWebView.addEventListener('MSWebViewNavigationStarting', function (e) {
console.log("Started loading");
loading.classList.add('loading');
});
paypalClose.addEventListener('click', function () {
container.classList.remove("visible");
});
}
paypalWebView.src = "https://myapp/paypal/";
container.classList.add("visible");
}
}
So, basically, when the script notify event fires, I parse the sent json string to an object and check what kind of action it is. If it's the first time I run this I setup some naviation event handlers that check if the web view reach the Success page. If we have, I use incokeScriptAsync to let the web app know that we're done so it can refresh the user account the new payment.
I think you can use a similar solution for authentication and just check your your return URL after authenticating.
Hope this helps!
I need to use JavaScript (jQuery if applicable) to trigger my modal call if the result of my function is true and the referring URL is not of the domain.
The desire is that the user visits the main splash page and as long as they have not been redirected there by the site itself (via timeout on a session, invalid login credentials, etc) it displays the message so:
function showModalIf() {
if (checkFunction) {
if(////// REFERRING URL not from this site)
Trigger Modal Call
else
Don't Do anything else
}
}
Assuming you use jQuery UI Dialog to show the modal
function checkReferrerExternal() {
if (!document.referrer || document.referrer == '') return false;
var regex = /^https?:\/\/\/?([^?:\/\s]+).*/;
var referrermatch = regex.exec(document.referrer);
var locationmatch = regex.exec(document.location);
return referrermatch[1] != locationmatch[1];
}
function showModalIf() {
if (checkReferrerExternal()) {
//show jQuery UI Dialog modal or replace with whatever
$("div#dialog").dialog('open');
}
}
Check demo page http://jsbin.com/efico
If you are talking about forced redirection in the code, and not just a hyperlink click from elsewhere in the site, you could add a query string parameter on your redirection and check that way. Another option is to set a cookie and check for the cookie in javascript.
Here is a nice link on cookie handling in Javascript:
Javascript - Cookies
And here's one for parsing query string params/hashes in Javascript as well:
Parsing The Querystring with Javascript
Hope this points you in the right direction :)