Redirect after login to backbone route with rails - ruby-on-rails

I am attempting to provide users with a common functionality, redirecting them after login to the originally requested url that is behind a secure path. Example, user clicks link in email triggered via notification in the system, attempts to go to:
https://mysite.com/secure/notifications/1
User is not logged in so kicked back to
https://mysite.com/login
After login they should be brought not to their home page, but to the originally requested url.
I am familar with the technique to store the attempted URL in session before redirecting to login page. The issue is if the URL contains a backbone router after the core URL, ie
https://mysite.com/secure/notifications/1#details
The #details part of the URL is not sent to server it seems, as this is typically for inner page jumping. I am wondering how are web developers dealing with this as JS MVC frameworks like backbone, angular, and other are emerging? Some trick? Any way to actually have the # pass to server in http specification?
Any ideas are appreciated, thank you.

The easiest solution to this problem, if you don't need to support this behaviour for older browsers, is to enable pushState in your backbone router so you don't use # for routes:
Backbone.history.state({pushState: true});
Edit:
The other potential solution, though it is a bit messy, is to do some URL tomfoolery to figure out what should be after the hash and then navigate to that route.
For example, let's say that you want to navigate to:
http://webapp.com/abc/#page1 where 'page1' is the fragment which makes up the Backbone route.
If you instead send the user to http://webapp.com/abc/page1. You can detect whether the browser has pushState. If not, you can replace everything after the 'root' with the hash. Here is some example code which might get you on the right track to supporting both sets of browsers:
var _defaults = {
pushState: Modernizr.history,
silent: true,
root: '/'
};
var start = function(options) {
// Start the routing either with pushstate or without
options = _.extend(_.clone(this._defaults), options);
Backbone.history.start(options);
if (options.pushState) {
Backbone.history.loadUrl(Backbone.history.getFragment());
return;
}
this.degradeToNonHistoryURL();
};
/**
* For fragment URLs, we check if the actual request is for the root i.e '/',
* If it is, we can continue and Backbone will do the magic
* If it isn't we redirect to the root with the route as a fragment
* foo.com/bar/1 -> foo.com/#bar/1
*/
degradeToNonHistoryURL = function() {
var pathName = window.location.pathname;
// If the root is '/', length is one. If the root is 'foo', length is 5 (/foo/)
var rootLength = _getRoot().length;
var isRootRequest = pathName.length === rootLength;
if (!isRootRequest) {
var route = pathName.substr(rootLength);
window.location.href = _getRoot() + '#' + route + window.location.search;
return;
}
Backbone.history.loadUrl(Backbone.history.getFragment());
},
/**
* Get the effective root of the app. Normally it's '/', but if set to 'foo', we want
* to return '/foo/' so we can more easily determine if this is a root request or not.
* #returns {String} The effective root
*/
_getRoot = function() {
if (Backbone.history.options.root === '/') {
return '/';
}
return '/' + Backbone.history.options.root + '/';
},
The trick here is making the pushState URL your canonical URLs and always sending users to those ones. Once browser adoption increases, it should theoretically be easy to cut all of this crap out without having to update all of your links.

After some research it seems there are only two solutions
As recommended by Will, use pushState and only support HTML5 browsers, but this is a massive change for existing apps using hash or hashbang javascript navigation.
Workarounds on server side, the main option here is around providing redirect endpoints to get users where then need to go. Example
/myapp/redirector?pathroot=notifications&hashroot=details&hashparam1=2
this would then build up a url on server side
/myapp/notifications/1#details/2
So in #2 the server cannot receive http requests with hashtags, however it can send them. The browser will receive this full path including hash nav part, and do its normal javascript MVC routing thing.

Related

Workbox redirect the clients page when resource is not cached and offline

Usually whenever I read a blog post about PWA's, the tutorial seems to just precache every single asset. But this seems to go against the app shell pattern a bit, which as I understand is: Cache the bare necessities (only the app shell), and runtime cache as you go. (Please correct me if I understood this incorrectly)
Imagine I have this single page application, it's a simple index.html with a web component: <my-app>. That <my-app> component sets up some routes which looks a little bit like this, I'm using Vaadin router and web components, but I imagine the problem would be the same using React with React Router or something similar.
router.setRoutes([
{
path: '/',
component: 'app-main', // statically loaded
},
{
path: '/posts',
component: 'app-posts',
action: () => { import('./app-posts.js');} // dynamically loaded
},
/* many, many, many more routes */
{
path: '/offline', // redirect here when a resource is not cached and failed to get from network
component: 'app-offline', // also statically loaded
}
]);
My app may have many many routes, and may get very large. I don't want to precache all those resources straight away, but only cache the stuff I absolutely need, so in this case: my index.html, my-app.js, app-main.js, and app-offline.js. I want to cache app-posts.js at runtime, when it's requested.
Setting up runtime caching is simple enough, but my problem arises when my user visits one of the potentially many many routes that is not cached yet (because maybe the user hasn't visited that route before, so the js file may not have loaded/cached yet), and the user has no internet connection.
What I want to happen, in that case (when a route is not cached yet and there is no network), is for the user to be redirected to the /offline route, which is handled by my client side router. I could easily do something like: import('./app-posts.js').catch(() => /* redirect user to /offline */), but I'm wondering if there is a way to achieve this from workbox itself.
So in a nutshell:
When a js file hasn't been cached yet, and the user has no network, and so the request for the file fails: let workbox redirect the page to the /offline route.
Option 1 (not always useful):
As far as I can see and according to this answer, you cannot open a new window or change the URL of the browser from within the service worker. However you can open a new window only if the clients.openWindow() function is called from within the notificationclick event.
Option 2 (hardest):
You could use the WindowClient.navigate method within the activate event of the service worker however is a bit trickier as you still need to check if the file requested exists in the cache or not.
Option 3 (easiest & hackiest):
Otherwise, you could respond with a new Request object to the offline page:
const cacheOnly = new workbox.strategies.CacheOnly();
const networkFirst = new workbox.strategies.NetworkFirst();
workbox.routing.registerRoute(
/\/posts.|\/articles/,
async args => {
const offlineRequest = new Request('/offline.html');
try {
const response = await networkFirst.handle(args);
return response || await cacheOnly.handle({request: offlineRequest});
} catch (error) {
return await cacheOnly.handle({request: offlineRequest})
}
}
);
and then rewrite the URL of the browser in your offline.html file:
<head>
<script>
window.history.replaceState({}, 'You are offline', '/offline');
</script>
</head>
The above logic in Option 3 will respond to the requested URL by using the network first. If the network is not available will fallback to the cache and even if the request is not found in the cache, will fetch the offline.html file instead. Once the offline.html file is parsed, the browser URL will be replaced to /offline.

How to prevent xss

this is my native url:
127.0.0.1//myweb/home.php?u=daniel
now when I include this type of xss:
127.0.0.1//myweb/home.php/"><script>alert('hacked')</script>?u=daniel
it now appears to be hacked, how can I avoid this type XSS attack ?
ADDED
Here is the other codes: (I do not add the fetching the users the data)
require_once 'core/init.php';
$currentUser = new User();
$report = null;
if(!$currentUser->isLoggedIn()) {
Redirect::to('index.php');
}
You can always use php to filter away all the unnecessary part of the url.
This is your web site so you know what character is useless in your web site.
For example, I know that in my web site, the double quotes/" character is useless in my web site.
So, I can straight away filter out any part with double quotes/" character.
You can get your current url from the following code.
$url = $_SERVER['REQUEST_URI']
Then, you just ignore anything after double quotes character by using explode.
$safe_url = explode("\"", $url);
So, you will just use $safe_url[0] as your url.

Sails.js - get previouse url from request

How can i get previouse url without magic and in backend?
Now i get it through policies:
module.exports = function(req, res, next) {
if (!req.session.previouseUrls) {
req.session.previouseUrls = [];
}
req.session.previouseUrl = req.session.currentUrl || "/";
req.session.currentUrl = req.url;
req.session.previouseUrls.push(req.session.previouseUrl);
next();
};
but it's uncomfortable. Can i get previouse Url from backend simpler?
If you need to know the history (or just previous page) of the user's page requests purely on the client-side, could you query native HTML5 History?
..or if you need to support older browsers, maybe History.js?
I would be concerned with how you're doing it now for 2 reasons:
It's going to start filling up your session store. This may not be a big issue if you have short-lives sessions or not many users.
It could record not just traditional page views "clicks" but any request. Unless you're very carful about scoping this policy you may end up adding an Ajax call that goes through this policy check and you probably didn't intend for that.

Titanium: How to redirect from external to internal URL in webview

So I know how to access both external and internal URL's in the Titanium Webview. But I have no idea how to redirect from an external url to the internal url.
I've got a file called "index.html" in the root folder, so for the webview this should work to access it:
Ti.UI.createWebView({
url: 'index.html'
});
External urls are pretty straight forward
Ti.UI.createWebView({
url: 'http://www.google.com'
});
However, when on the external url, how do I redirect to this local file? None of these work:
LOCAL?
LOCAL?
or the javascript variant
window.location = 'file:///index.html';
Any clues on how to do this?
What I discovered, in the end, are 2 possibilities to achieve this. But it can't be done through redirection.
One: Poll for a certain variable using the webview.evalJS() function
var my_data = $.login_webview.evalJS('global.data;');
Of course, it works only with strings, not with objects. So if you're passing JSON, make sure it is set as a string!
Two: Do an actual redirection server side, to another serverside page and monitor for URL change and then do evalJS() once again, but no need for polling
$.login_webview.addEventListener('load',function(e){
if (e.url.indexOf('mobile/redirect.php') > -1){
var my_data = $.login_webview.evalJS('global.data');
}
});
Just make sure, with 2 that you're actually setting the required data in Javascript using server side technology.

Broken relative Url in jQuery getJSON Ajax Method

The Url for my development environment is:
http://localhost/mysite/blah...
I am using jQuery & getJSON to perform some ajax actions on my site, which work fine all the time I specify the url as:
/mysite/controller/action
..but this is not ideal as I don't want to hardcode my development url into my seperate jQuery include files.
When the site goes live, it'll be fine to have controller/action or /controller/action as the url as that will resolve ok, but for the development site, it's no go.
I've tried:
controller/action
..but this returns a 404, which suprised me as I thought the lack of / at the front of the url would prevent from looking at the website root.
There must be a neat solution to this?
I would do this by inserting a global constant in my HTML header:
<script type="text/javascript">
var BASE_URL = '/mysite/';
</script>
That would be inserted from your server so it can be dynamically changed.
Later in your script, you'll be able to make AJAX requests with (jQuery style here):
$.ajax( BASE_URL + '/controller/action', ...);
If you're in
/mysite/controller/action
then the correct relative path to
/mysite/some_other_controller/some_other_action
is
../../some_other_controller/some_other/action
You can use this code to get the current path of the .js script and use it for calculate your relative path.
var url;
$("script").each(function () {
if ($(this).attr("src").indexOf("[YOUR_SCRIPT_NAME.JS]") > 0) {
url = $(this).attr("src");
url = url.substr(0, url.lastIndexOf("/"));
return false;
}
});
var final_url = url + "/your_target_script.js"
Replace YOUR_SCRIPT_NAME with the unique name of your script.

Resources