Skip to content
This repository has been archived by the owner on Apr 3, 2019. It is now read-only.

Commit

Permalink
fix(server): ensure tokens get a fresh createdAt timestamp (#1389) r=…
Browse files Browse the repository at this point in the history
…vladikoff

* fix(server): ensure tokens get a fresh createdAt timestamp

* fix(tokens): default sessionToken.accountCreatedAt to null
  • Loading branch information
philbooth authored and vladikoff committed Aug 5, 2016
1 parent 09aee43 commit 6acb9e0
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 11 deletions.
9 changes: 1 addition & 8 deletions lib/routes/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ module.exports = function (
emailCode: account.emailCode,
emailVerified: account.emailVerified,
verifierSetAt: account.verifierSetAt,
createdAt: optionallyOverrideCreatedAt(),
createdAt: parseInt(query._createdAt),
tokenVerificationId: tokenVerificationId
}, userAgentString)
.then(
Expand All @@ -237,13 +237,6 @@ module.exports = function (
)
}

function optionallyOverrideCreatedAt () {
var createdAt = parseInt(query._createdAt)
if (createdAt < Date.now() && ! config.isProduction) {
return createdAt
}
}

function sendVerifyCode () {
if (! account.emailVerified) {
mailer.sendVerifyCode(account, account.emailCode, {
Expand Down
7 changes: 6 additions & 1 deletion lib/tokens/session_token.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ module.exports = function (log, inherits, Token) {
this.emailVerified = !!details.emailVerified
this.verifierSetAt = details.verifierSetAt
this.locale = details.locale || null
this.accountCreatedAt = details.createdAt

if (details.createdAt > 0) {
this.accountCreatedAt = details.createdAt
} else {
this.accountCreatedAt = null
}

// Tokens are considered verified if no tokenVerificationId exists
this.tokenVerificationId = details.tokenVerificationId || null
Expand Down
16 changes: 15 additions & 1 deletion lib/tokens/token.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
*
*/

var config = require('../../config').getProperties()

module.exports = function (log, crypto, P, hkdf, Bundle, error) {

// Token constructor.
Expand All @@ -38,7 +40,19 @@ module.exports = function (log, crypto, P, hkdf, Bundle, error) {
this.algorithm = 'sha256'
this.uid = details.uid || null
this.lifetime = details.lifetime || Infinity
this.createdAt = details.createdAt >= 0 ? details.createdAt : Date.now()
this.createdAt = optionallyOverrideCreatedAt(details.createdAt)
}

function optionallyOverrideCreatedAt (timestamp) {
var now = Date.now()

if (! config.isProduction && timestamp >= 0 && timestamp < now) {
// In the wild, all tokens should have a fresh createdAt timestamp.
// For testing purposes only, allow createdAt to be overridden.
return timestamp
}

return now
}

// Create a new token of the given type.
Expand Down
18 changes: 18 additions & 0 deletions test/local/session_token_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var SessionToken = tokens.SessionToken
var TOKEN_FRESHNESS_THRESHOLD = require('../../lib/tokens/session_token').TOKEN_FRESHNESS_THREADHOLD

var ACCOUNT = {
createdAt: Date.now(),
uid: 'xxx',
email: Buffer('test@example.com').toString('hex'),
emailCode: '123456',
Expand Down Expand Up @@ -67,6 +68,23 @@ test(
}
)

test(
'create with NaN createdAt',
function (t) {
return SessionToken.create({
createdAt: NaN,
email: 'foo',
uid: 'bar'
}).then(
function (token) {
var now = Date.now()
t.ok(token.createdAt > now - 1000 && token.createdAt <= now)
t.equal(token.accountCreatedAt, null)
}
)
}
)

test(
'sessionToken key derivations are test-vector compliant',
function (t) {
Expand Down
75 changes: 75 additions & 0 deletions test/local/token_tests.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict'

var crypto = require('crypto')
var hkdf = require('../../lib/crypto/hkdf')
var mocks = require('../mocks')
var P = require('../../lib/promise')
var sinon = require('sinon')
var test = require('tap').test

var Bundle = {
bundle: sinon.spy(),
unbundle: sinon.spy()
}
var log = mocks.spyLog()
var modulePath = '../../lib/tokens/token'

test('NODE_ENV=dev', function (t) {
process.env.NODE_ENV = 'dev'
var Token = require(modulePath)(log, crypto, P, hkdf, Bundle, null)

t.plan(4)

t.test('Token constructor was exported', function (t) {
t.equal(typeof Token, 'function', 'Token is function')
t.equal(Token.name, 'Token', 'function is called Token')
t.equal(Token.length, 2, 'function expects two arguments')
t.end()
})

t.test('Token constructor sets createdAt', function (t) {
var now = Date.now() - 1
var token = new Token({}, { createdAt: now })

t.equal(token.createdAt, now, 'token.createdAt is correct')
t.end()
})

t.test('Token constructor does not set createdAt if it is negative', function (t) {
var notNow = -Date.now()
var token = new Token({}, { createdAt: notNow })

t.ok(token.createdAt > 0, 'token.createdAt seems correct')
t.end()
})

t.test('Token constructor does not set createdAt if it is in the future', function (t) {
var notNow = Date.now() + 1000
var token = new Token({}, { createdAt: notNow })

t.ok(token.createdAt > 0 && token.createdAt < notNow, 'token.createdAt seems correct')
t.end()
})
})

test('NODE_ENV=prod', function (t) {
process.env.NODE_ENV = 'prod'
delete require.cache[require.resolve(modulePath)]
delete require.cache[require.resolve('../../config')]
var Token = require(modulePath)(log, crypto, P, hkdf, Bundle, null)

t.plan(1)

t.test('Token constructor does not set createdAt', function (t) {
var notNow = Date.now() - 1
var token = new Token({}, { createdAt: notNow })

t.ok(token.createdAt > notNow, 'token.createdAt seems correct')
t.end()
})
})

3 changes: 2 additions & 1 deletion test/remote/base_path_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

process.env.PUBLIC_URL = 'http://127.0.0.1:9000/auth'

var test = require('../ptaptest')
var TestServer = require('../test_server')
var Client = require('../client')
var P = require('../../lib/promise')
var request = require('request')

process.env.PUBLIC_URL = 'http://127.0.0.1:9000/auth'
var config = require('../../config').getProperties()

TestServer.start(config)
Expand Down

0 comments on commit 6acb9e0

Please sign in to comment.