Skip to content

Commit

Permalink
Merge 30d2b6f into aadab73
Browse files Browse the repository at this point in the history
  • Loading branch information
rhwilr committed Dec 5, 2018
2 parents aadab73 + 30d2b6f commit eea0cd1
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 10 deletions.
11 changes: 11 additions & 0 deletions config/index.js
Expand Up @@ -84,6 +84,17 @@ module.exports = {
*/
dateFormat: 'YYYY-MM-DD HH:mm:ss',

/*
|--------------------------------------------------------------------------
| Valid For
|--------------------------------------------------------------------------
|
| The default time in hours the token is valid for. This can be changed for
| an individual token by calling `isValidFor()` before generating it.
|
*/
validFor: 24,

/*
|--------------------------------------------------------------------------
| Validation messages
Expand Down
47 changes: 44 additions & 3 deletions src/Persona.js
Expand Up @@ -44,7 +44,8 @@ class Persona {
model: 'App/Models/User',
newAccountState: 'pending',
verifiedAccountState: 'active',
dateFormat: 'YYYY-MM-DD HH:mm:ss'
dateFormat: 'YYYY-MM-DD HH:mm:ss',
validFor: 24
})

/**
Expand All @@ -59,6 +60,7 @@ class Persona {

this._encrypter = Encryption.getInstance({ hmac: false })
this._model = null
this._validFor = null
}

/**
Expand Down Expand Up @@ -157,7 +159,7 @@ class Persona {
query
.where('type', type)
.where('is_revoked', false)
.where('updated_at', '>=', moment().subtract(24, 'hours').format(this.config.dateFormat))
.where('expires_at', '>=', moment().format(this.config.dateFormat))
}

/**
Expand Down Expand Up @@ -187,7 +189,16 @@ class Persona {
}

const token = this._encrypter.encrypt(randtoken.generate(16))
await user.tokens().create({ type, token })
const expiresAt = moment().add(this.getValidFor(), 'hours').format(this.config.dateFormat)

this._validFor = null

await user.tokens().create({
type,
token,
expires_at: expiresAt
})

return token
}

Expand Down Expand Up @@ -276,6 +287,36 @@ class Persona {
return this.getModel().table
}

/**
* Returns the duration in hours the a generated token should be valid for
*
* @method getValidFor
*
* @return {Number}
*/
getValidFor () {
if (this._validFor) {
return this._validFor
}

return this.config.validFor
}

/**
* Sets the duration in hours the a generated token should be valid for
*
* @method isValidFor
*
* @param {Number} payload
*
* @return {Persona}
*/
isValidFor (payload) {
this._validFor = payload

return this
}

/**
* Returns an object of registeration rules
*
Expand Down
75 changes: 68 additions & 7 deletions test/persona.spec.js
Expand Up @@ -206,7 +206,8 @@ test.group('Persona', (group) => {
user_id: user.id,
is_revoked: false,
created_at: moment().subtract(2, 'days').format('YYYY-MM-DD HH:mm:ss'),
updated_at: moment().subtract(2, 'days').format('YYYY-MM-DD HH:mm:ss')
updated_at: moment().subtract(2, 'days').format('YYYY-MM-DD HH:mm:ss'),
expires_at: moment().subtract(1, 'days').format('YYYY-MM-DD HH:mm:ss')
})

assert.plan(2)
Expand All @@ -228,7 +229,8 @@ test.group('Persona', (group) => {
user_id: user.id,
is_revoked: false,
created_at: moment().format('YYYY-MM-DD HH:mm:ss'),
updated_at: moment().format('YYYY-MM-DD HH:mm:ss')
updated_at: moment().format('YYYY-MM-DD HH:mm:ss'),
expires_at: moment().add(2, 'days').format('YYYY-MM-DD HH:mm:ss')
})

assert.plan(2)
Expand All @@ -250,7 +252,8 @@ test.group('Persona', (group) => {
is_revoked: false,
user_id: user.id,
created_at: moment().format('YYYY-MM-DD HH:mm:ss'),
updated_at: moment().format('YYYY-MM-DD HH:mm:ss')
updated_at: moment().format('YYYY-MM-DD HH:mm:ss'),
expires_at: moment().add(2, 'days').format('YYYY-MM-DD HH:mm:ss')
})

await this.persona.verifyEmail('hello')
Expand All @@ -271,7 +274,8 @@ test.group('Persona', (group) => {
is_revoked: false,
user_id: user.id,
created_at: moment().format('YYYY-MM-DD HH:mm:ss'),
updated_at: moment().format('YYYY-MM-DD HH:mm:ss')
updated_at: moment().format('YYYY-MM-DD HH:mm:ss'),
expires_at: moment().add(2, 'days').format('YYYY-MM-DD HH:mm:ss')
})

await this.persona.verifyEmail('hello')
Expand Down Expand Up @@ -604,7 +608,8 @@ test.group('Persona', (group) => {
user_id: user.id,
is_revoked: false,
created_at: moment().format('YYYY-MM-DD HH:mm:ss'),
updated_at: moment().format('YYYY-MM-DD HH:mm:ss')
updated_at: moment().format('YYYY-MM-DD HH:mm:ss'),
expires_at: moment().add(2, 'days').format('YYYY-MM-DD HH:mm:ss')
})

try {
Expand All @@ -629,7 +634,8 @@ test.group('Persona', (group) => {
user_id: user.id,
is_revoked: false,
created_at: moment().subtract(2, 'days').format('YYYY-MM-DD HH:mm:ss'),
updated_at: moment().subtract(2, 'days').format('YYYY-MM-DD HH:mm:ss')
updated_at: moment().subtract(2, 'days').format('YYYY-MM-DD HH:mm:ss'),
expires_at: moment().subtract(1, 'days').format('YYYY-MM-DD HH:mm:ss')
})

try {
Expand All @@ -655,7 +661,8 @@ test.group('Persona', (group) => {
user_id: user.id,
is_revoked: false,
created_at: moment().format('YYYY-MM-DD HH:mm:ss'),
updated_at: moment().format('YYYY-MM-DD HH:mm:ss')
updated_at: moment().format('YYYY-MM-DD HH:mm:ss'),
expires_at: moment().add(2, 'days').format('YYYY-MM-DD HH:mm:ss')
})

await this.persona.updatePasswordByToken('hello', { password: 'newsecret', password_confirmation: 'newsecret' })
Expand Down Expand Up @@ -749,4 +756,58 @@ test.group('Persona', (group) => {
assert.equal(users.size(), 1)
assert.equal(users.first().email, 'foo@bar.com')
})

test('generated tokens are valid for 24 hours by default', async (assert) => {
const user = await getUser().create({
username: 'virk',
email: 'foo@bar.com',
account_status: 'active',
password: 'secret'
})

const token = await this.persona.generateToken(user, 'email')

const tokenEntity = await this.persona.getToken(token, 'email')
assert.equal(tokenEntity.expires_at, moment().add(1, 'days').format('YYYY-MM-DD HH:mm:ss'))
})

test('tokens without an expiry date are invalid', async (assert) => {
const user = await getUser().create({ email: 'foo@bar.com' })

await use('Database').table('tokens').insert({
token: 'hello',
type: 'email',
user_id: user.id,
is_revoked: false,
created_at: moment().subtract(2, 'days').format('YYYY-MM-DD HH:mm:ss'),
updated_at: moment().subtract(2, 'days').format('YYYY-MM-DD HH:mm:ss'),
expires_at: null
})

assert.plan(2)

try {
await this.persona.verifyEmail('hello')
} catch ({ message, name }) {
assert.equal(message, 'The token is invalid or expired')
assert.equal(name, 'InvalidTokenException')
}
})

test('the expiry date for a tokens can be changed for each token', async (assert) => {
const user = await getUser().create({
username: 'virk',
email: 'foo@bar.com',
account_status: 'active',
password: 'secret'
})

const token = await this.persona.isValidFor(48).generateToken(user, 'email')
const tokenEntity = await this.persona.getToken(token, 'email')
assert.equal(tokenEntity.expires_at, moment().add(2, 'days').format('YYYY-MM-DD HH:mm:ss'))

const token1 = await this.persona.generateToken(user, 'password')
const tokenEntity1 = await this.persona.getToken(token1, 'password')
assert.equal(tokenEntity1.expires_at, moment().add(1, 'days').format('YYYY-MM-DD HH:mm:ss'))
})
})
1 change: 1 addition & 0 deletions test/setup.js
Expand Up @@ -76,6 +76,7 @@ module.exports = {
table.string('token').notNull()
table.string('type').notNull()
table.boolean('is_revoked').defaultsTo(false)
table.timestamp('expires_at').nullable()
table.timestamps()
})
},
Expand Down

0 comments on commit eea0cd1

Please sign in to comment.