Skip to content

Commit

Permalink
Convert TokenModel to an ES6 class and extract utils function for cal…
Browse files Browse the repository at this point in the history
…culating lifetime
  • Loading branch information
menewman committed Aug 16, 2023
1 parent 320f947 commit e4e2834
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 42 deletions.
99 changes: 57 additions & 42 deletions lib/models/token-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,63 +3,78 @@
/**
* Module dependencies.
*/

const InvalidArgumentError = require('../errors/invalid-argument-error');
const { getLifetimeFromExpiresAt } = require('../utils/date-util');

/**
* Constructor.
* The core model attributes allowed when allowExtendedTokenAttributes is false.
*/
const modelAttributes = new Set([
'accessToken',
'accessTokenExpiresAt',
'refreshToken',
'refreshTokenExpiresAt',
'scope',
'client',
'user'
]);

class TokenModel {
constructor(data = {}, options = {}) {
const {
accessToken,
accessTokenExpiresAt,
refreshToken,
refreshTokenExpiresAt,
scope,
client,
user,
} = data;

if (!accessToken) {
throw new InvalidArgumentError('Missing parameter: `accessToken`');
}

const modelAttributes = ['accessToken', 'accessTokenExpiresAt', 'refreshToken', 'refreshTokenExpiresAt', 'scope', 'client', 'user'];

function TokenModel(data, options) {
data = data || {};
if (!client) {
throw new InvalidArgumentError('Missing parameter: `client`');
}

if (!data.accessToken) {
throw new InvalidArgumentError('Missing parameter: `accessToken`');
}
if (!user) {
throw new InvalidArgumentError('Missing parameter: `user`');
}

if (!data.client) {
throw new InvalidArgumentError('Missing parameter: `client`');
}
if (accessTokenExpiresAt && !(accessTokenExpiresAt instanceof Date)) {
throw new InvalidArgumentError('Invalid parameter: `accessTokenExpiresAt`');
}

if (!data.user) {
throw new InvalidArgumentError('Missing parameter: `user`');
}
if (refreshTokenExpiresAt && !(refreshTokenExpiresAt instanceof Date)) {
throw new InvalidArgumentError('Invalid parameter: `refreshTokenExpiresAt`');
}

if (data.accessTokenExpiresAt && !(data.accessTokenExpiresAt instanceof Date)) {
throw new InvalidArgumentError('Invalid parameter: `accessTokenExpiresAt`');
}
this.accessToken = accessToken;
this.accessTokenExpiresAt = accessTokenExpiresAt;
this.client = client;
this.refreshToken = refreshToken;
this.refreshTokenExpiresAt = refreshTokenExpiresAt;
this.scope = scope;
this.user = user;

if (data.refreshTokenExpiresAt && !(data.refreshTokenExpiresAt instanceof Date)) {
throw new InvalidArgumentError('Invalid parameter: `refreshTokenExpiresAt`');
}
if (accessTokenExpiresAt) {
this.accessTokenLifetime = getLifetimeFromExpiresAt(accessTokenExpiresAt);
}

this.accessToken = data.accessToken;
this.accessTokenExpiresAt = data.accessTokenExpiresAt;
this.client = data.client;
this.refreshToken = data.refreshToken;
this.refreshTokenExpiresAt = data.refreshTokenExpiresAt;
this.scope = data.scope;
this.user = data.user;
const { allowExtendedTokenAttributes } = options;

if (options && options.allowExtendedTokenAttributes) {
this.customAttributes = {};
if (allowExtendedTokenAttributes) {
this.customAttributes = {};

for (const key in data) {
if ( Object.prototype.hasOwnProperty.call(data, key) && (modelAttributes.indexOf(key) < 0)) {
this.customAttributes[key] = data[key];
}
Object.keys(data).forEach(key => {
if (!modelAttributes.has(key)) {
this.customAttributes[key] = data[key];
}
});
}
}

if(this.accessTokenExpiresAt) {
this.accessTokenLifetime = Math.floor((this.accessTokenExpiresAt - new Date()) / 1000);
}
}

/**
* Export constructor.
*/

module.exports = TokenModel;
13 changes: 13 additions & 0 deletions lib/utils/date-util.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict';

/**
* @param expiresAt {Date} The date at which something (e.g. a token) expires.
* @return {number} The number of seconds until the expiration date.
*/
function getLifetimeFromExpiresAt(expiresAt) {
return Math.floor((expiresAt - new Date()) / 1000);
}

module.exports = {
getLifetimeFromExpiresAt,
};
33 changes: 33 additions & 0 deletions test/unit/models/token-model_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,38 @@ describe('Model', function() {
model.accessTokenLifetime.should.a('number');
model.accessTokenLifetime.should.be.approximately(3600, 2);
});

it('should throw if the required arguments are not provided', () => {
should.throw(() => {
new TokenModel({});
});
});

it('should ignore custom attributes if allowExtendedTokenAttributes is not specified as true', () => {
const model = new TokenModel({
accessToken: 'token',
client: 'client',
user: 'user',
myCustomAttribute: 'myCustomValue'
});

should.not.exist(model['myCustomAttribute']);
should.not.exist(model['customAttributes']);
});

it('should set custom attributes on the customAttributes field if allowExtendedTokenAttributes is specified as true', () => {
const model = new TokenModel({
accessToken: 'token',
client: 'client',
user: 'user',
myCustomAttribute: 'myCustomValue'
}, {
allowExtendedTokenAttributes: true
});

should.not.exist(model['myCustomAttribute']);
model['customAttributes'].should.be.an('object');
model['customAttributes']['myCustomAttribute'].should.equal('myCustomValue');
});
});
});
26 changes: 26 additions & 0 deletions test/unit/utils/date-util__test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
const dateUtil = require('../../../lib/utils/date-util');

const sinon = require('sinon');
require('chai').should();

describe('DateUtil', function() {
describe('getLifetimeFromExpiresAt', () => {
const now = new Date('2023-01-01T00:00:00.000Z');

beforeEach(() => {
sinon.useFakeTimers(now);
});

it('should convert a valid expiration date into seconds from now', () => {
const expiresAt = new Date('2023-01-01T00:00:10.000Z');
const lifetime = dateUtil.getLifetimeFromExpiresAt(expiresAt);

lifetime.should.be.a('number');
lifetime.should.be.approximately(10, 2);
});

afterEach(() => {
sinon.restore();
});
});
});

0 comments on commit e4e2834

Please sign in to comment.