Commit 80631186064bd17aa5d2e8898c3bfb822c171f88
Add sign in functionality
Right now this app, authenticates with the sweet store. The sweet store
implements a very naive authentication. It does not even send back a session
token! It only sends back a 200 if the auth was successful else a 403. Based on
that the client has to set some auth token. This should improve. The sweet
store can send back a session token which the client can store in its cookie,
which results in smoother auth mechanism. Right now there is no auth as such.
Sweet store sends back 200 if the auth was successful, and then subsequent
requests are made by the client injecting the 'who' parameter, and the server
accepts and agrees with the client. Here the client can tamper with the
username or 'who'. The correct way is, when the auth is successful, sweet store
sends back a auth token, which the client stores in the cookie. And subsequent
sweet store requests are made along with that cookie. Then the sweet store
should identify the username or 'who' from the cookie.
| | | | 1 | #swt-maker { | 1 | #swt-maker { |
---|
2 | } | 2 | } |
---|
| | 3 | #signinview { |
---|
| | 4 | margin 0 20px; |
---|
| | 5 | padding: 10px; |
---|
| | 6 | text-align: center; |
---|
| | 7 | } |
---|
3 | #img-annotation-wrapper { | 8 | #img-annotation-wrapper { |
---|
4 | margin: 30px auto 0 auto; | 9 | margin: 30px auto 0 auto; |
---|
5 | /*border: 1px solid black;*/ | 10 | /*border: 1px solid black;*/ |
---|
| | | | 149 | //TODO: move this to a annotation view or something | 149 | //TODO: move this to a annotation view or something |
---|
150 | anno.removeAll(); | 150 | anno.removeAll(); |
---|
151 | _.each(swtr.sweets.models, function(swt) { | 151 | _.each(swtr.sweets.models, function(swt) { |
---|
152 | swt.get('how')['editable'] = false; | | swt.get('how')['editable'] = false; |
---|
| | 152 | if(!_.has(swt.get('how'), 'editable')) { | | | 153 | swt.get('how')['editable'] = false; |
---|
| | 154 | swt.get('how').text += '\n - by ' + swt.get('who'); |
---|
| | 155 | } |
---|
153 | anno.addAnnotation(swt.get('how')); | 156 | anno.addAnnotation(swt.get('how')); |
---|
154 | }); | 157 | }); |
---|
155 | //console.log(swtr.sweets.toJSON()); | 158 | //console.log(swtr.sweets.toJSON()); |
---|
… | | … | |
---|
164 | } | 164 | } |
---|
165 | }); | 165 | }); |
---|
166 | this.cleanUp(); | 166 | this.cleanUp(); |
---|
| | 167 | return false; |
---|
167 | }, | 168 | }, |
---|
168 | cleanUp: function() { | 169 | cleanUp: function() { |
---|
169 | console.log('cleaning up'); | | console.log('cleaning up'); |
---|
| | 170 | //console.log('cleaning up'); | 170 | $(this.el).hide(); | 171 | $(this.el).hide(); |
---|
171 | } | 172 | } |
---|
172 | }); | 173 | }); |
---|
… | | … | |
---|
176 | el: $('#swt-maker'), | 176 | el: $('#swt-maker'), |
---|
177 | events: { | 177 | events: { |
---|
178 | 'click #img-url-submit': 'setImage', | 178 | 'click #img-url-submit': 'setImage', |
---|
179 | 'click #sweet': 'sweet' | | 'click #sweet': 'sweet' |
---|
| | 179 | 'click #sweet': 'sweet', | | | 180 | 'click #signin-credentials': 'getSignInCredentials' |
---|
180 | }, | 181 | }, |
---|
181 | initialize: function() { | 182 | initialize: function() { |
---|
182 | //var allElements = $('body *'); | 183 | //var allElements = $('body *'); |
---|
… | | … | |
---|
218 | getExistingAnnotations: function() { | 218 | getExistingAnnotations: function() { |
---|
219 | this.helpview.step(0); | 219 | this.helpview.step(0); |
---|
220 | this.$overlay.show(); | 220 | this.$overlay.show(); |
---|
221 | console.log('getting existing annotations of ', this.imgURL); | | console.log('getting existing annotations of ', this.imgURL); |
---|
| | 221 | //console.log('getting existing annotations of ', this.imgURL); | 222 | swtr.sweets.getAll({ | 222 | swtr.sweets.getAll({ |
---|
223 | where: this.imgURL, | 223 | where: this.imgURL, |
---|
224 | success: function(data) { | 224 | success: function(data) { |
---|
… | | … | |
---|
226 | swtr.sweets.add(data); | 226 | swtr.sweets.add(data); |
---|
227 | _.each(data, function(swt) { | 227 | _.each(data, function(swt) { |
---|
228 | swt.how['editable'] = false; | 228 | swt.how['editable'] = false; |
---|
229 | swt.how.text+= '\n - by ' + swt.who; | | swt.how.text+= '\n - by ' + swt.who; |
---|
| | 229 | swt.how.text += '\n - by ' + swt.who; | 230 | anno.addAnnotation(swt.how); | 230 | anno.addAnnotation(swt.how); |
---|
231 | }); | 231 | }); |
---|
232 | swtr.appView.$overlay.hide(); | 232 | swtr.appView.$overlay.hide(); |
---|
… | | … | |
---|
235 | }, | 235 | }, |
---|
236 | error: function(jqxhr, error, statusText) { | 236 | error: function(jqxhr, error, statusText) { |
---|
237 | if(jqxhr.status === 404) { //annotations don't exist for this image | 237 | if(jqxhr.status === 404) { //annotations don't exist for this image |
---|
238 | console.log('annotations don\'t exist for this image. Create one!'); | | console.log('annotations don\'t exist for this image. Create one!'); |
---|
| | 238 | //console.log('annotations don\'t exist for this image. Create one!'); | 239 | } | 239 | } |
---|
240 | swtr.appView.$overlay.hide(); | 240 | swtr.appView.$overlay.hide(); |
---|
241 | swtr.appView.helpview.step(2); | 241 | swtr.appView.helpview.step(2); |
---|
… | | … | |
---|
266 | this.getSweets(); | 266 | this.getSweets(); |
---|
267 | this.showSweets(); | 267 | this.showSweets(); |
---|
268 | return false; | 268 | return false; |
---|
| | 269 | }, |
---|
| | 270 | getSignInCredentials: function(event) { |
---|
| | 271 | event.preventDefault(); |
---|
| | 272 | if(swtr.who === 'Guest' && !$('#username').length) { |
---|
| | 273 | var template = _.template($('#signin-credentials-template').html()); |
---|
| | 274 | $('#signin-msg').html(template()); |
---|
| | 275 | } |
---|
| | 276 | else if($('#username').length && $('#username').val()) { |
---|
| | 277 | var username = $('#username').val(); |
---|
| | 278 | var password = $('#password').val(); |
---|
| | 279 | this.signIn(username, password); |
---|
| | 280 | } |
---|
| | 281 | return false; |
---|
| | 282 | }, |
---|
| | 283 | signIn: function(username, password) { |
---|
| | 284 | this.$overlay.show(); |
---|
| | 285 | $.ajax({ |
---|
| | 286 | url: swtr.swtstoreURL() + swtr.endpoints.auth, |
---|
| | 287 | type: 'POST', |
---|
| | 288 | data: {user: username, hash: password}, |
---|
| | 289 | success: function(data) { |
---|
| | 290 | swtr.appView.$overlay.hide(); |
---|
| | 291 | swtr.who = username; |
---|
| | 292 | $('#signinview').html('You are signed in.'); |
---|
| | 293 | }, |
---|
| | 294 | error: function(jqxhr, status, error) { |
---|
| | 295 | swtr.appView.$overlay.hide(); |
---|
| | 296 | if(error === 'FORBIDDEN') { |
---|
| | 297 | $('#signin-msg').html('Error signing in. Please check your username and password. '); |
---|
| | 298 | } |
---|
| | 299 | else { |
---|
| | 300 | $('#signin-msg').html('Error signin in. Please try again.'); |
---|
| | 301 | } |
---|
| | 302 | } |
---|
| | 303 | }); |
---|
269 | } | 304 | } |
---|
270 | }); | 305 | }); |
---|
271 | | 306 | |
---|
… | | … | |
---|
335 | break; | 335 | break; |
---|
336 | } | 336 | } |
---|
337 | $(this.el).html(text); | 337 | $(this.el).html(text); |
---|
| | 338 | $(window).scrollTop(0, 0); |
---|
338 | } | 339 | } |
---|
339 | }); | 340 | }); |
---|
340 | | 341 | |
---|
| | | | 16 | | 16 | |
---|
17 | <div id="swt-maker" class="container"> | 17 | <div id="swt-maker" class="container"> |
---|
18 | <div id="helpview" class="alert alert-info"></div> | 18 | <div id="helpview" class="alert alert-info"></div> |
---|
| | 19 | <div class="row" id="signinview"> |
---|
| | 20 | <form class="form-inline" role="form"> |
---|
| | 21 | <span id="signin-msg">You are not signed in. </span> |
---|
| | 22 | <button class="btn btn-sm btn-primary" id="signin-credentials"> |
---|
| | 23 | Sign In |
---|
| | 24 | </button> |
---|
| | 25 | </form> |
---|
| | 26 | </div> |
---|
19 | <div id="img-input"> | 27 | <div id="img-input"> |
---|
20 | <div class="form-group"> | 28 | <div class="form-group"> |
---|
21 | <input type="text" placeholder="Enter URL of the image" | 29 | <input type="text" placeholder="Enter URL of the image" |
---|
… | | … | |
---|
52 | <script> | 52 | <script> |
---|
53 | window.swtr = window.swtr || {}; | 53 | window.swtr = window.swtr || {}; |
---|
54 | swtr.swtstoreURL = function() { return '{{ conf.swtstoreURL }}'; } | 54 | swtr.swtstoreURL = function() { return '{{ conf.swtstoreURL }}'; } |
---|
55 | swtr.endpoints = {'get': '/sweets/q', 'post': '/sweets'}; | | swtr.endpoints = {'get': '/sweets/q', 'post': '/sweets'}; |
---|
| | 55 | swtr.endpoints = {'get': '/sweets/q', 'post': '/sweets', 'auth': | | | 56 | '/authenticate'}; |
---|
56 | window.onload = function() { | 57 | window.onload = function() { |
---|
57 | swtr.init(); | 58 | swtr.init(); |
---|
58 | }; | 59 | }; |
---|
… | | … | |
---|
71 | /<a href="<%= where %>"><%= where.substr(0, 30) + '...' %></a> | 71 | /<a href="<%= where %>"><%= where.substr(0, 30) + '...' %></a> |
---|
72 | <%= how %> | 72 | <%= how %> |
---|
73 | </li> | 73 | </li> |
---|
| | 74 | </script> |
---|
| | 75 | <script type="text/template" id="signin-credentials-template"> |
---|
| | 76 | <div class="form-group"> |
---|
| | 77 | <label class="sr-only" for="username">Username</label> |
---|
| | 78 | <input type="text" class="form-control" id="username" placeholder="Enter username"> |
---|
| | 79 | </div> |
---|
| | 80 | <div class="form-group"> |
---|
| | 81 | <label class="sr-only" for="password">Password</label> |
---|
| | 82 | <input type="password" class="form-control" id="password" placeholder="Password"> |
---|
| | 83 | </div> |
---|
74 | </script> | 84 | </script> |
---|
75 | </body> | 85 | </body> |
---|
76 | </html> | 86 | </html> |
---|