Angular app spanning subdomains - javascript

So I am building an angular app that allows people to create books and share them (digital books mind you) with a subdomain link.
So something like mycoolbook.theappsite.com would be a sharable link.
I (perhaps stupidly) built the routes so that editing books would be at the url "mycoolbook.theappsite.com/settings".
This being an angular page I am having to do hard redirects between those pages and so miss out on much of the SPA-y goodness. Is there a way to keep the app instance running between those pages?
If not I might move all the admin pages back behind the url like "theappsite.com/book/mycoolbook/settings" instead.
Is this at all possible?
I've already done all the hard work of getting sessions and ajax request working across the domains, it's just the state linking that becomes bothersome.

Short answer is no and have the URL change to reflect it. You cannot change book.domain.com -> domain.com because angular manipulates the URL, but only the fragment section of the URL in hash mode and just the path, search string, hash in HTML5 Mode. Not the other parts of the URL. If your application is using HTML5 mode your server must be able to map URLs properly so they return the correct page (ie index.html) as you change the URL. That would mean both DNS locations would have to send back the same page.
Now you can send AJAX requests between the two domains provided you understand how to deal with cross domain issues (JSONP, CORS, etc).

Related

VueJS: Redirecting URL to SPA Routing

I am currently working the first time with vue-router and I am wondering if there is a way to handle redirecting through vue or if there are other options in a node.js environment to do so.
For example, if someone wants to visit my site through typing the URL
example.com/contact
he will currently get to
example.com/contact#/home
But of course I want to redirect to the correct path.
You have two options.
The first one is to keep using hash router, which means that you will have to add a hashtag before the path so the correct url would be example.com#/contact. Hash router has the benefit that it works with your web server out of the box without any other configuration.
Another option is to switch to history mode on the Vue router. History mode lets you have URLs without the hashtag, however there's a drawback that it doesn't work with most web servers without separate configuration. The link above includes the necessary configurations for many web servers, where you will need to add it somewhere depending on the web server.

Have facebook scrape a different URL than what was shared

I have a Single Page Application built in ember.js, we have this hosted on AWS S3 and I'm trying to come up with a solution for when someone shares a URL from our site to facebook to have facebook be able to scrape the content on that page properly.
Obviously this won't work at this time because facebook does not support indexing javascript like the google search engine does. So one solution I've seen is to use apache .htaccess to redirect requests from facebook to a server file that can make a barebones html page with the necessary open graph tags like in this post
https://rck.ms/angular-handlebars-open-graph-facebook-share/
However since we're on S3 I can't do an apache .htaccess, and from what I've been able to gather from the sparse docs on how their S3 redirect rules work and what they can do I'm not sure if there is a way to do this with that method.
So my question is does facebook or open graph or even just normal meta tags have away of allowing the user to share a url, have facebook use that but follow a link to a server generated file, and then if someone clicks that link actually have it point the user to the real single page application page instead of the server file facebook will use for the scrape data.
Facebook supports “pointers” to request the meta data from a different URL – but that likely won’t help you here, because the reference to the URL that serves the meta data would again have to be part of the HTML code of your original URL that you want to share.
You might do better the other way around: Let your users share the URL to your server-generated document that contains the correct meta data – and redirect human visitors that follow that link to the real target URL within your application. You can either do that via JS (location.href='…'), or server-side (but in that case you need to implement an exception from that redirect for the FB scraper; it can be recognized by its User Agent, see https://developers.facebook.com/docs/plugins/faqs#scraperinfo)

Angular.js and SEO

I'd like to create a site with Angular (I'm new), but also want to be able to have different "views" be cachable in the search engines and have their own URL routes. How would I achieve this with Angular, or is best not to use it?
Enable pushState in Angular with $locationProvider.html5Mode(true); so that you have real URLs and make sure that, when the URL is requested by the client, you deliver the complete page for that URL from the server (and not a set of empty templates that you populate with JS).
When a link is followed, you'll go through an Angular view and update the existing DOM (while changing the URL with pushState) but the initial load should be a complete page.
This does mean duplicating effort (you need client and server side versions of the code for building each page). Isomorphic JS is popular for dealing with that issue.
If you want to expose Angular views to search engines and other bots, I suggest using an open source framework that we developed at Say Media. It uses node.js to render the pages on the server when it detects a bot vs a real user. You can find it here:
https://github.com/saymedia/angularjs-server
I would suggest not using different routes, however, as most search engines will penalize you for having duplicate content on multiple urls. And while you might think they would just hit the bot version of your site, they are getting more sophisticated about crawling single page app like sites. I would be cautious about duplicate routes for the same content.
Good Luck!

Security in embedded iframe/javascript widget

I'm building a website that is functionally similar to Google Analytics. I'm not doing analytics, but I am trying to provide either a single line of javascript or a single line iframe that will add functionality to other websites.
Specifically, the embedded content will be a button that will popup a new window and allow the user to perform some actions. Eventually the user will finish and the window will close, at which point the button will update to a new element reflecting that the user completed the flow.
The popup window will load content from my site, but my question pertains to the embedded line of javascript (or the iframe). What's the best practice way of doing this? Google analytics and optimizely use javascript to modify the host page. Obviously an iFrame would work too.
The security concern I have is that someone will copy the embed code from one site and put it on another. Each page/site combination that implements my script/iframe is going to have a unique ID that the site's developers will generate from an authenticated account on my site. I then supply them with the appropriate embed code.
My first thought was to just use an iframe that loads a page off my site with url parameters specific to the page/site combo. If I go that route, is there a way to determine that the page is only loaded from an iframe embedded on a particular domain or url prefix? Could something similar be accomplished with javascript?
I read this post which was very helpful, but my use case is a bit different since I'm actually going to pop up content for users to interact with. The concern is that an enemy of the site hosting my embed will deceptively lure their own users to use the widget. These users will believe they are interacting with my site on behalf of the enemy site but actually be interacting on behalf of the friendly site.
If you want to keep it as a simple, client-side only widget, the simple answer is you can't do it exactly like you describe.
The two solutions that come to mind for this are as follows, the first being a compromise but simple and the second being a bit more involved (for both you and users of your widget).
Referer Check
You could validate the referer HTTP header to check that the domain matches the one expected for the particular Site ID, but keep in mind that not all browsers will send this (and most will not if the referring page is HTTPS) and that some browser privacy plugins can be configured to withhold it, in which case your widget would not work or you would need an extra, clunky, step in the user experience.
Website www.foo.com embeds your widget using say an embedded script <script src="//example.com/widget.js?siteId=1234&pageId=456"></script>
Your widget uses server side code to generate the .js file dynamically (e.g. the request for the .js file could follow a rewrite rule on your server to map to a PHP / ASPX).
The server side code checks the referer HTTP header to see if it matches the expected value in your database.
On match the widget runs as normal.
On mismatch, or if the referer is blank/missing, the widget will still run, but there will be an extra step that asks the user to confirm that they have accessed the widget from www.foo.com
In order for the confirmation to be safe from clickjacking, you must open the confirmation step in a popup window.
Server Check
Could be a bit over engineered for your purposes and runs the risk of becoming too complicated for clients who wish to embed your widget - you decide.
Website www.foo.com wants to embed your widget for the current page request it is receiving from a user.
The www.foo.com server makes an API request (passing a secret key) to an API you host, requesting a one time key for Page ID 456.
Your API validates the secret key, generates a secure one time key and passes back a value whilst recording the request in the database.
www.foo.com embeds the script as follows <script src="//example.com/widget.js?siteId=1234&oneTimeKey=231231232132197"></script>
Your widget uses server side code to generate the js file dynamically (e.g. the .js could follow a rewrite rule on your server to map to a PHP / ASPX).
The server side code checks the oneTimeKey and siteId combination to check it is valid, and if so generates the widget code and deletes the database record.
If the user reloads the page the above steps would be repeated and a new one time key would be generated. This would guard against evil.com from page scraping the embed code and parameters.
The response here is very thorough and provides lots of great information and ideas. I solved this problem by validating X-Frame-Options headers on the server-side , though the support for those is incomplete in browsers and possibly spoofable.

Backbone routers and compatibility with web server controller

How do I get compatibility between my web server's controllers and Backbone router?
I have it set it so when a user clicks on a link, a view is rendered, and the URL looks like this: /test/1, which is what I want. The problem comes in when the user tries to access test/1 by entering it into the address bar. My backend has controllers that is in charge of routing URLS.
How would I get it so it uses the Backbone routes rather than the backend routes?
One way that works is when I access the url #test/1. It is bookmarkable and can be entered into the address bar. The problem is that backbone stripes the # on load.
So, I see two solutions to my problem:
Get the backend controllers to interact with Backbone routes
Make it so the #'s aren't removed when they are entered inside of the address bar.
Which of the above solutions is recommended. And, how would I implement them. The second solution seems easier, but how would I make it so backbone doesn't strip the URLs of the hashes?
From what I understand when the user navigates to the root page and then test/1 via a link the logic is handled by backbone and a view is rendered. But when the user navigates directly to test/1 this is not handled correctly.
To handle this you need to setup a route on your server that points any URLs handled by backbone to the root page. The logic for this depends on your server which you have not specified. To do something like this in ASP you might setup a route like this:
RouteTable.Routes.MapWebPageRoute("test/{id}", "~/Default.cshtml", new {}, new { id = "\\d+" });
This would cause a URL such as test/1 to be handled by the default page which be the same handler as if the user navigated to /. Once the page has loaded on the client the Backbone router would fire for the test/1 route.
Well, really, there are many reasons why you want the URL to include the # all the time. It makes lots of things work better. For example, the correct controller is automatically selected by the web server and the correct route is automatically provided to Backbone whether you manually type in the URL, use a bookmark, use a link from another site, or use the back and forward buttons on the web browser. So choice 2 is definitely the one you want. This is also the standard behavior of Backbone.
So my question is "How did you get backbone to stop using the # in the first place?"
Edit: Thanks to Chris Herring for pointing us to a great article explaining why # is bad. With that, I will leave it as an exercise to the reader about which kind of pain they want to endure. I think # is still the way to go so long as all the Backbone route is changing is how the information on the page is displayed and not what information is on the page. If a web crawler that does not support JavaScript can scrape all the same information regardless of what comes after the #, then I still don't see a problem with it.

Categories

Resources