From b8e4ba3c841869cc671acf19ef7bddf0c298d81f Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 16 Nov 2015 11:39:16 -0700 Subject: [PATCH 1/5] Remove ES6 features from config --- config/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/environment.js b/config/environment.js index 5ec51ce..e8cfd47 100644 --- a/config/environment.js +++ b/config/environment.js @@ -61,7 +61,7 @@ module.exports = function(environment) { } ENV.apiURL = apiURL; - ENV.contentSecurityPolicy['connect-src'] = `'self' ${apiURL}`; + ENV.contentSecurityPolicy['connect-src'] = "'self' " + apiURL; return ENV; }; From c561e0ec769deaab7d3e48572fc5a7853f163135 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 16 Nov 2015 11:39:53 -0700 Subject: [PATCH 2/5] Changed mind on strain model MU prop Closes #55. --- app/models/strain.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/models/strain.js b/app/models/strain.js index ef5e41c..8643017 100644 --- a/app/models/strain.js +++ b/app/models/strain.js @@ -2,7 +2,7 @@ import DS from 'ember-data'; import Ember from 'ember'; const { Model, hasMany, belongsTo, attr } = DS; -const { computed } = Ember; +const { computed, String: { htmlSafe } } = Ember; export default Model.extend({ measurements : hasMany('measurements', { async: false }), @@ -28,9 +28,7 @@ export default Model.extend({ return `${this.get('species.speciesName')} ${this.get('strainNameMU')}`; }), - // TODO: move this to component/helper - // Can't move until Select2 refactor - fullNameMU: function() { - return Ember.String.htmlSafe(`${this.get('species.speciesName')} ${this.get('strainName')}`); - }.property('species', 'strainNameMU').readOnly(), + fullNameMU: computed('species', 'strainName', function() { + return htmlSafe(`${this.get('species.speciesName')} ${this.get('strainName')}`); + }), }); From 9218c29c0ee2ae0191501f8fa486e4c6b539bef9 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 16 Nov 2015 12:25:27 -0700 Subject: [PATCH 3/5] Tweaking bower.json to fix CI build errors --- bower.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bower.json b/bower.json index db98942..4dc55ed 100644 --- a/bower.json +++ b/bower.json @@ -8,7 +8,8 @@ "ember-data": "1.13.15", "ember-load-initializers": "0.1.7", "ember-qunit": "0.4.16", - "ember-qunit-notifications": "0.1.0", + "ember-qunit-notifications": "~0.1.0", + "qunit-notifications": "~0.1.0", "ember-resolver": "~0.1.20", "loader.js": "ember-cli/loader.js#3.2.1", "qunit": "~1.20.0", From 6b30b3328178f5c27922978acb761c00339d7b6d Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 16 Nov 2015 12:42:02 -0700 Subject: [PATCH 4/5] Remove quint-notifications Trying on travis --- bower.json | 1 - 1 file changed, 1 deletion(-) diff --git a/bower.json b/bower.json index 4dc55ed..639f127 100644 --- a/bower.json +++ b/bower.json @@ -9,7 +9,6 @@ "ember-load-initializers": "0.1.7", "ember-qunit": "0.4.16", "ember-qunit-notifications": "~0.1.0", - "qunit-notifications": "~0.1.0", "ember-resolver": "~0.1.20", "loader.js": "ember-cli/loader.js#3.2.1", "qunit": "~1.20.0", From 55f71b0a0056955837c0021658562b184fa24419 Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Mon, 16 Nov 2015 16:58:00 -0700 Subject: [PATCH 5/5] Customizing refresh token flow Departs from oauth2, oh well. Fixes #58. --- app/authenticators/oauth2.js | 63 ++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/app/authenticators/oauth2.js b/app/authenticators/oauth2.js index c5c9221..8af289b 100644 --- a/app/authenticators/oauth2.js +++ b/app/authenticators/oauth2.js @@ -1,6 +1,69 @@ import OAuth2PasswordGrant from 'ember-simple-auth/authenticators/oauth2-password-grant'; import config from '../config/environment'; +import parseBase64 from '../utils/parse-base64'; +const { RSVP: { Promise }, isEmpty, run, Logger: { warn } } = Ember; export default OAuth2PasswordGrant.extend({ serverTokenEndpoint: `${config.apiURL}/api/authenticate`, + serverTokenRefreshEndpoint: `${config.apiURL}/api/refresh`, + + authenticate: function(identification, password, scope = []) { + return new Promise((resolve, reject) => { + const data = { username: identification, password }; + const serverTokenEndpoint = this.get('serverTokenEndpoint'); + this.makeRequest(serverTokenEndpoint, data).then((response) => { + run(() => { + const token = parseBase64(response['access_token']); + const expiresAt = this._absolutizeExpirationTime(token['exp']); + this._scheduleAccessTokenRefresh(expiresAt, response['access_token']); + if (!isEmpty(expiresAt)) { + response = Ember.merge(response, { 'expires_at': expiresAt }); + } + resolve(response); + }); + }, (xhr) => { + run(null, reject, xhr.responseJSON || xhr.responseText); + }); + }); + }, + + _scheduleAccessTokenRefresh: function(expiresAt, accessToken) { + if (this.get('refreshAccessTokens')) { + const now = (new Date()).getTime(); + const offset = (Math.floor(Math.random() * 5) + 5) * 1000; + if (!isEmpty(accessToken) && !isEmpty(expiresAt) && expiresAt > now - offset) { + run.cancel(this._refreshTokenTimeout); + delete this._refreshTokenTimeout; + if (!Ember.testing) { + this._refreshTokenTimeout = run.later(this, this._refreshAccessToken, expiresAt, accessToken, expiresAt - now - offset); + } + } + } + }, + + _refreshAccessToken: function(expiresAt, accessToken) { + const data = { 'token': accessToken }; + const serverTokenRefreshEndpoint = this.get('serverTokenRefreshEndpoint'); + return new Promise((resolve, reject) => { + this.makeRequest(serverTokenRefreshEndpoint, data).then((response) => { + run(() => { + const token = parseBase64(response['access_token']); + const expiresAt = this._absolutizeExpirationTime(token['exp']); + const data = Ember.merge(response, { 'expires_at': expiresAt }); + this._scheduleAccessTokenRefresh(expiresAt, response['access_token']); + this.trigger('sessionDataUpdated', data); + resolve(data); + }); + }, (xhr, status, error) => { + warn(`Access token could not be refreshed - server responded with ${error}.`); + reject(); + }); + }); + }, + + _absolutizeExpirationTime: function(expiresAt) { + if (!isEmpty(expiresAt)) { + return new Date(expiresAt * 1000).getTime(); + } + } });