GWT and Third Party Cross Domain JavaScript - javascript

I currently have a GWT project utilizes the Activities and Places model provided by Google. We are integrating with a third party cross domain JavaScript solution that renders an external domain's JSP in an iframe and utilizes window.location transport to notify our domain when the user has finished doing work in this JSP.
The issue is that by using window.location transport GWT's place system will catch the editing of the URL and attempt to navigate to a nonexistant place.
We do have some influence to get the third party to change so the three options I can see are:
Catch the attempted place navigation and ignore it if it contains a certain list of reserved strings that this third party JS uses.
Get the third party to change their solution to utilize window.name (less refactoring on their part)
Get the third party to change their solution to utilize JSONP (more refactoring on their part)
Is there any way to actually achieve #1?
EDIT So I figured out how to achieve #1 by rolling my own version of GWT's PlaceHistoryHandler and changing the handleHistoryToken method. The real question is which of these three solutions is the best practice?

My vote would be on changing the cross-domain signaling, if possible. The browser-displayed URL implies that the page can be bookmarked to be loaded again, and it provides a way to manipulate the history of the page. Building another mechanism based on that risks the user bookmarking or navigating to a page/place that has no meaning for the history token handling system, and may even signal the app that the iframe is loaded when it actually isn't.
That said, if you aren't actually using history with places, you could just as easily use Places + Activities with a custom PlaceHistoryHandler-like class that keeps a stack of recent places to allow returning to them if your application allows it. This would prevent the browser back button from making sense, but could still allow navigation by places internally.
Unless that is a case that makes sense (app doesn't need the hash token, so leave it to be used for inter-domain communication), I'd vote for #2 or #3.

Related

Authenticate websites that are using my service through iframe

I have a service that I provide to different websites. For the website to use the service they implement a javascript that triggers a lightbox with a iframe in it.
The problem is I don't want any website to be able to use the service/iframe. Is there any way I can authenticate the websites using the iframe?
The way I see it, a random website can just take the javascript from a website using the service/iframe and implement it on it's own website.
Authenticating the actual users inside the iframe is no problem, there will be a login form and a register form. It's just the websites using the iframe I want to identify and authenticate.
Any suggestions is appriciated!
You could check document.referrer in JavaScript, and if the referring domain is not within a whitelist you provide (or the referrer is empty), don't display content at all.
But we all know how unreliable the referrer is, and it might exclude users even under wrong conditions.
Another way would only work it the sites embedding your iframe have server-side scripting and so can calculate some kind of hash - f.e. the hash of the current date and a secret keyword - and pass it as a GET parameter in your iframe URL. In your script, you check if the given value is the same as the hash you create with the same data - and display content based on that or not.
Using the current date could be problematic though if time zone settings for your server and the other site are different, and it might also break when a user calls the page around midnight. To prevent such problems, you could have the remote sites include the unix timestamp value used to create the hash as GET parameter as well - then you can check if that timestamp is not to old, and create the hash with that exact value. (Then other sites might try to just copy the parameters and use them on their page as well, but it will only work for a small time window.)

What's the best fallback if Google Ajax API is not available (since Google does not permit to install it locally)?

In my site I have:
...
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
...
The script above is the Google script to load up other resources dynamically.
(eg Google charts API)
This works 99.99% of the time.
However, I just got a client that for some reasons got his company restricting access to google.com.
As a consequence of this my website simply threw a JavaScript error.
Now I know how to handle that, and I can check if window.Google exists.
but my question is
"what's the standard way to deal with this? "
In other words if you embed 3rd party JavaScript how best do you deal with their JS not available?
NOTE: VERY IMPORTANT
You can not host the chart code locally or on an intranet.
SEE FAQ from Google: https://developers.google.com/chart/interactive/faq#localdownload
Can I download and host the chart code locally, or on an intranet?
Sorry; our terms of service do not allow you to download and save or
host the Google.load or Google.visualization code.
There is no real alternative. Due to Google's terms of service you cannot use Google API without access to google.com.
Check the connection to Google and iform user that function is not available
Develop your own or use non-google api. Still you can use Google if available
The solution is that your client's company review their content filtering policies. Google are quite clear in their previous answer concerning offline access:
…your computer must have live access to http://www.google.com/jsapi in order to use charts.
You are using a third-party solution according to their terms and conditions, which naturally imposes limits on how that solution may be used by your clients. You need to stand firm or find a more liberally-licensed solution. (At any rate, you are more likely to succeed at convincing your client's IT department than petitioning Google to change their TOS.)
For the more general case of third party JS APIs that may not load but for which you are allowed to keep a local copy on your server, see this question.
You can try it like this:
Instead of using the direct link to the Google libraries you want to use, use a link which points to your server:
<script type="text/javascript" src="https://www.myserver.com/jsapi"></script>
When your server gets an incoming request to this URL, your server now makes a request to Google to get the API and sends the response to the client.
That means you do not install the API anywhere locally or on a server and always get the most actual version directly from Google. People also do not need access to Google (as in the company you mentioned) and therefore can use your service.
Use Firebug or the Chrome Dev Tools to inspect your HTML source once the charts scripts are loaded. Access the scripts in your browser and save them locally, then serve them from your own server. This isn't recommended, of course, but if you don't have any other choice...
For example, checking the code of one of the pages I use it on, the core script for the Google Charts library is located at:
https://www.google.com/uds/api/visualization/1.0/3d781368978b51b3ca00a01566dccf40/format+en,default,corechart.I.js
Use the javascript window.onload to check whether the api has loaded or not, if no then load it from your server.
You already know how to check whether or not your library has been loaded (checking the object), if it fails, than what you can do within giving constrains:
Keep checking the object with timer and trying to download library, displaying message for a user
In case first one fails, you have two ways again:
Stopping your application and displaying an error: "Application error... try later"
Or downloading different library as a fallback
Are you progressively enhancing or gracefully degrading the page? If so, what do you display to users without JavaScript for this chart? A table? A list? This is what you should leave in the page and only start changing it once google's JS is available. Either that, or find an alternative library like raphaeljs that lets you keep all your code within your project.
IF (BIG IF) you are not worried about the interactivity the Google Charts and want to display them to the user just to see - maybe add your own javascript to it but not depend on the Google Javascript at all, this can turn the google charts into a image that you can display to the user.
Also this requires access to install a command line tool on the server.
http://code.google.com/p/wkhtmltopdf/ is a command line tool that will generate an image from an html page. If you build a simple page that only shows the chart you want and point the wkhtmltoimage tool at the local html file it will load the Google Charts javascript and generate the chart then generate an image out of the results.
YES I understand this is VERY kludgy and is adding a big tool for a small problem but with the browser restriction and the Google Terms of Service this will solve most of the problem.
You can try going straight to google and if it fails (if google is restricted) you can bounce the request off of your server which forwards the request using CURL to google. If that doesn't work then Google is most likely down. This should cover the issue that you described in your question, but there isn't really a fix for if google itself actually goes down. It should, however, give your application access around domain restrictions because the request will be routed to your server rather than straight to google. I use this architecture for all requests so that I don't have ajax requests routed to random servers. It allows me to control what interacts with my front end using my backend. There are other benefits to this, especially if you are using something like AngularJS with NodeJS because you can decouple a lot of your third party libraries. This however, is beyond the scope of your question!
Basically, it works like this (pseudo code):
If(!Browser->Google->Browser){
return Browser->MyServer->Google->MyServer->Browser;
}
An answer has been accepted already, but still I would like to leave an additional aspect elaborating on the comment I made above ....
It has been accepted that the Google Server is the only place from where the API can be loaded. We don't know whether the client's IT manager will re-think their content policy, they might have good reasons for that.
Given a non-100% availability of all the components along the path between a user browser and the Google API, sooner or later a user will end up in an error situation; statistically this is unavoidable.
What is not acceptable (and avoidable) for a user is to receive an "unspecific" JS error making him/her believe there's a bug on the page. So my solution would be to trap the failure loading the Google API and display a message "Third party components temporarily unavailable - Please try later".
This will demonstrate to the user that
we know what's going on
there's nothing we can do about it now
but it's not totally unexpected and still somehow under control

ColdFusion - Detect top window

is there a function in ColdFusion that detects whether or not a browser window is the top window? (Similar to (if (window == window.top)) in JavaScript)
The reason I ask is because I would like to make certain page elements present when the page is directly accessed by the user, and not present if my page is iframed.
CFML code runs on the CF server, whereas any considerations about browser windows obviously run on the client. CF is completely unaware of the UI configuration of the client system, all it sees is "a request". Indeed the requests don't even come from the client, they come from the web server which acts as a go-between for CF-serviced requests: CF has no interaction with the client itself.
The only information the web server gives to CF that in any way relates to the client browser is some of the stuff in the CGI scope, and obviously that's limited. And none of it relates to the configuration of browser windows / iframes.
You will need to solve this with Javascript (which I will add to the tags of your question).
To trigger different code to execute on CF given a certain browsing situation, you are going to need to use Javascript to add some information to the request to identify the situation to CF. This could be adding a parameter on the query string, or something like that.
If someone was 'wrapping' one of my products I'd want to know who and how so I could improve the experience for the user and the site owner. With that in mind, what I would do is automatically break out of any frames by default. I would then create a simple api and provide instructions to other webmasters on the proper way to include your content. Display different content once you've determined if your content is PROPERLY being included in another site. For webmasters that want to include your content:
Provide recommended height/width for the iFrame so you can
include your logo or ads with the content.
Provide anything you want them to include in the query string to help track usage.
You could even add fun stuff to your api to make your content look more integrated into the including website like reacting to url.bgcolor or url.bgimage.
You could go as simple as looking for and recording the value of some url variable like url.remoteSiteAddress or as complicated as registering the site and providing unique key. Of course there are other considerations to take into account to enforce the key. Being that you don't really care that the content is being displayed on a remote site, I suspect just recording a simple url variable is more your speed.
If a different website is putting your page in an iframe on their website, then you could use the CGI.HTTP_REFERRER variable to check if the website domain is yours or not, and load content as desired.

Dual login: One login, 2 servers

Okay, this just feels plain nasty, but I've been directed to do it, and just wanted to run it past some people who actually have a clue, so they can point out all the massive holes in it.....so here goes.....
We've got this legacy site & a new public beta-test one. Apparently it's super cereal that moving from one to the other is seamless, so in a manner of speaking, we need a single signon solution.
As we're not allowed to put any serious development into the legacy site (It's also in old school ASP, a language I don't care to learn.) I can't do a proper single sign-on solution, so I proposed the following: On login, the legacy site performs an AJAX post to the login controller of the new beta site, logging the user in there, it then simply proceeds with the login on the legacy site as normal. This may not be acceptable as there's code to prevent a user from being logged on twice, I'm not sure if it's been written to apply across sites.
The other idea I had was to pass a salted hash of the user's details across with their username when they try to access the 2nd site. If the hash matches the details of the user, then access is granted. This would need ASP development obviously as generating the hash on the client side would only serve to enhance the idiocy even further.
Does anyone have any thoughts?
The old ASP site must have some concept of a session if it requires a logon. You will, at a minimum, need to understand how to provide the session information to the legacy site and splice some code in to keep it copacetic if both sites need to be kept up indefinitely.
"Classic" ASP isn't so bad if you can read/write VB6, VBA, VBScript or VB.net. It probably won't be difficult to graft session initialization provided the code is half way decent.
Consider creating a common logon page for both sites + either an automatic redirect based on either the requested URL (I'm guessing the old and new sites have distinct URLs) or cookies passed with the request (the old site, if it used cookies, could identify a legacy user). This common logon page could initialize session on both the legacy site (only if required by user type) and on the new site. This will allow you to keep your new logon process unencumbered by the legacy process while maintaining the old as long as required.
Bear in mind that your first approach (AJAX request from one site to the other) won't work if the sites are on different domains, because of javascript security restrictions.
You might be able to work around this by using a hidden iframe for the post like this, but it's getting a little hacky.

Communicating between websites (using Javascript or ?)

Here's my problem - I'd like to communicate between two websites and I'm looking for a clean solution. The current solution uses Javascript but there are nasty workarounds because of (understandable) cross-site scripting restrictions.
At the moment, website A opens a modal window containing website B using a jQuery plug-in called jqModal. Website B does some work and returns some results to website A. To return that information we have to work around cross-site scripting restrictions - website B creates an iframe that refers to a page on website A and includes *fragment identifiers" containing the information to be returned. The iframe is polled by website A to detect the returned information. It's a common technique but it's hacky.
There are variations such as CrossSite and I could perhaps use an HTTP POST from website B to website A but I'm trying to avoid page refreshes.
Does anyone have any alternatives?
EDIT: I'd like to avoid having to save state on website B.
My best suggestion would be to create a webservice on each site that the other could call with the information that needs to get passed. If security is necessary, it's easy to add an SSL-like authentication scheme (or actual SSL even, if you like) to this system to ensure that only the two servers are able to talk to their respective web services.
This would let you avoid the hackiness that's inherent in any scheme that involves one site opening windows on the other.
With jQuery newer than 1.2 you can use JSONP
#jmein - you've described how to create a modal popup (which is exactly what jqModal does) however you've missed that the content of the modal window is served from another domain. The two domains involved belong to two separate companies so can't be combined in the way you describe.
i believe #pat was refering to this
"As of jQuery 1.2, you can load JSON data located on another domain if you specify a JSONP callback, "
http://docs.jquery.com/Ajax/jQuery.getJSON#urldatacallback

Categories