extra users url when trying to combine backbone and rails - ruby-on-rails

I have a rails app that uses backbone on the homepage. It has a search field in the navbar. If a user searches a name, a dropdown bar opens showing all the users with a specific letter in the name, at which point the user can click a link to any of the profiles. The Backbone collection 'Users" builds on the url like this, with 'key' representing the letter(s) entered in the search box.
var url = "users/search/" + key;
However, the app only uses backbone in a limited way. For example, after the user clicks on a link, there is a page change and they are taken to localhost:3000/users/28. I want the search bar to be available on a user's profile page, however, if I search a name from a profile page, the url (in the console logs) now becomes.
/users/users/search/" + key;
In other words, searching from a user's profile page adds an extra "users" into the search query (and a 404 not found error), even though the url for the ajax request the Users collection is like this
var url = "users/search/" + key;
Out of curiosity, I added a route to the routes.rb to try to deal with the '/users/users' situation
match '/users/search/:query' => 'users#getUsersByName', defaults: {format: :json}
match '/users/users/search/:query' => 'users#getUsersByName', defaults: {format: :json}
However, even though this eliminates the 404 error, and returns search results, if I click the link, to visit another user's profile (from a user's profile page), Rails is taking me to /users/users/28, because the link in the template is being tacked onto the base users url.
Can anyone recommend how I might go about dealing with this problem?
link in the template
<a href='users/{{= id }}'>
Users collection
window.Users = Backbone.Collection.extend({
model: User,
url:"users",
findByName:function (key) {
var url = "users/search/" + key;
console.log('findByName: ' + key);
var self = this;
$.ajax({
url:url,
dataType:"json"
success:function (data) {

It needs to have a forward slash before users. So instead of this
var url = "users/search/" + key;
Do
var url = "/users/search/" + key;

Related

if user change url in browser and request was Invalid stay in current page in yii2

I want to prevent from IDOR attack in yii2.
If user change url in browser and request was Invalid stay in current page.
I use below code .I stay the current page and dot render page with id manipulate after change Id by firebug in link page.
But if I change id in browser I redirected to home page.
for example, the user(by Yii::$app->user->identity->id that is 19) is on this page : url http://localhost:8080/profile/test/19 and see own profile. if user change url to http://localhost:8080/profile/test/25 in browser and press enter , see the same page again http://localhost:8080/profile/test/19 That is, his profile but I go to home page, I think Yii::$app->request->referrer in empty in this case.
public function actionTest($id) {
if (Yii::$app->user->identity->id == $id) {
return $this->render('view', [
'model' => User::findOne($id),
]);
} else {
$this->goBack(Yii::$app->request->referrer);
}
}

Redirect after login to backbone route with 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.

Ember.js route for the current user's /settings page

A common pattern for a user's settings page would be for it to live at /settings.
In my Rails app, I'm accomplishing this on the API side by mapping get 'settings' to Settings#show and looking for the current_user's settings.
But on the Ember side, I'm stumped. There's no ID to use for the GET request, so I can't use the typical pattern of this.store.find('setting', params.id) within my route.
What's the "Ember way" of handling this sort of use case?
This has been discussed here: http://discuss.emberjs.com/t/fetching-single-records/529/3
The issue with loading a single record not based on an ID, is that you need to get back a DS.Model object as a promise. If you get back a record that's already in the client's memory you would now have two different objects representing the same record (type and id combination). Take this example:
var user123 = App.User.find(123);
var currentUser = App.findByUrl('/users/current'); //This is an imaginary method, i.e. Ember Data don't support it
notEqual(user123, currentUser, "The user objects can't be the same cause we don't know what the current user is yet");
Now we get this response from the server:
{
"user": {
"id": 123,
"name": "Mufasa"
}
}
Now currentUser and user123 both have id 123, but they are essentially different objects = very bad. This is why this approach wouldn't work.
Instead you will want to load a record array of users, listen for it to load, and then take the firstObject from the loaded records. Like this:
var users = App.User.find({ is_current: true });
users.one('didLoad', function() {
App.set('currentUser', users.get('firstObject');
});
$.ajax({
type: 'GET',
url: '/users/current',
success: function(payload) {
var store = this.store;
var userReference = store.load(App.User, payload.user);
App.set('currentUser', store.recordForReference(userReference));
}.bind(this)
});

Create Snapshot/Thumbnail of a blog entry using mvc

I need to generate a snapshot from multiple links of blogs.
What i have is a list of text like these
"Report: Twitter Will Release Music Discovery App This Month http://on.mash.to/10L1v49 via #mashable"
I want to show the links as snapshot of the blog, followed by its text in my view. Or at least i need to get the picture attached to the blog.
Using facebook debug, http://developers.facebook.com/tools/debug ,i am getting this..
fb:app_id: 122071082108
og:url: http://mashable.com/2013/03/13/twitter-music-app/
og:type: article
og:title: Report: Twitter Will Release Music Discovery App This Month
og:image:
og:description: Twitter is planning to release a standalone music app for iOS called Twitter Music as soon as the end of this month, according to CNET. CNET reports that Twitter Music will help...
og:site_name: Mashable
og:updated_time: 1363267654
I tried the same link from my c# code, accessed the link with parameter 'q' as my desired link. I got the same html as reply but i am unable to find the image associated as it is coming differently for different links.
Can anyone suggest a better method to do this in mvc?
My code in controller to access facebook debug :
var client = new RestClient
{
BaseUrl = "http://developers.facebook.com/tools/debug/og/object"
};
var request = new RestRequest
{
DateFormat = DataFormat.Xml.ToString(),
Resource = "Add",
Method = Method.GET
};
request.AddParameter("q", "http://on.mash.to/10L1v49");
IRestResponse response = client.Execute(request);
var content = response.Content; // raw content as string
What i understand from your question is, you need something like the preview of a link what we get on pasting some link on facebook share area.
Facebook debug method returns an html page which has the image of your blog entry from the link given.
Use HtmlAgilityPack to parse your html returned from facebook debug
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(content);
HtmlNode root = doc.DocumentNode;
var imageurl = doc.DocumentNode.SelectNodes("//img/#src").LastOrDefault();
string imagesrc = imageurl.OuterHtml.ToString();
int start = imagesrc.IndexOf("url=");
int to = imagesrc.IndexOf("\"", start + "url=".Length);
string s = imagesrc.Substring(
start + "url=".Length,
to - start - "url=".Length);
string a = Uri.UnescapeDataString(s);
and..there you have your image of the blog entry. Same function can be modified to retireve the title, description and the updated time of the blog entry.

User not valid from external link

I have a website that outputs Excel reports with hyperlinks back to secure content. One of the links would look like this...
http://www.[site].com/externalLinkDigester?externalSession=[SHA Encrypted Text]
The query string argument (externalSession) is a unique alphanumeric string that is only valid for 24 hours and can only be accessed by the user who created the report. My controller looks something like this...
class ExternalLinkDigester{
def springSecurityService;
def index = {
def currentUser = springSecurityService?.currentUser
if (!currentUser){
redirect(controller:'login')
}
def request = ExternalSession.findByName(params.externalSession);
if (request.isExpired(){
//show expired content page
}
if (sameUser(currentUser, request.user){
//show content
}else{
redirect(controller:'login')
}
}
}
The problem is that no matter what the springSecurityService.currentUser is always null when coming form an external program like Excel even when I am logged before clicking the link however, if I copy and paste the link into the browser it seems to work fine. Help!
How can I securely access content this way?
Is it possible that Excel is opening up a different browser than the one you logged in with (eg. you logged in with Firefox and when clicking the link within excel, it defaults to opening the link within Internet Explorer). The new browser will not have the session cookie for the authenticated session so "currentUser" will appear as null.

Resources