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

Commit

Permalink
feat(devices): added fxa-deviceId to the signed certificate
Browse files Browse the repository at this point in the history
  • Loading branch information
dannycoates committed Feb 19, 2016
1 parent 571f2d8 commit a866e8f
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 30 deletions.
25 changes: 25 additions & 0 deletions lib/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,31 @@ module.exports = function (
)
}

DB.prototype.sessionWithDevice = function (id) {
log.trace({ op: 'DB.sessionWithDevice', id: id })
return this.pool.get('/sessionToken/' + id.toString('hex') + '/device')
.then(
function (body) {
var data = bufferize(body, {
ignore: [
'uaBrowser',
'uaBrowserVersion',
'uaOS',
'uaOSVersion',
'uaDeviceType'
]
})
return SessionToken.fromHex(data.tokenData, data)
},
function (err) {
if (isNotFoundError(err)) {
err = error.invalidToken()
}
throw err
}
)
}

// UPDATE

DB.prototype.updatePasswordForgotToken = function (token) {
Expand Down
33 changes: 23 additions & 10 deletions lib/routes/sign.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ module.exports = function (log, isA, error, signer, db, domain) {
path: '/certificate/sign',
config: {
auth: {
strategy: 'sessionToken',
strategy: 'sessionTokenWithDevice',
payload: 'required'
},
validate: {
Expand Down Expand Up @@ -88,23 +88,36 @@ module.exports = function (log, isA, error, signer, db, domain) {
}
}
var uid = sessionToken.uid.toString('hex')
signer.sign(
var deviceId = sessionToken.deviceId ?
sessionToken.deviceId.toString('hex') : null

return signer.sign(
{
email: uid + '@' + domain,
publicKey: publicKey,
domain: domain,
duration: duration,
generation: sessionToken.verifierSetAt,
lastAuthAt: sessionToken.lastAuthAt(),
verifiedEmail: sessionToken.email
verifiedEmail: sessionToken.email,
deviceId: deviceId
}
).then(function(certResult) {
log.activityEvent('account.signed', request, {
uid: uid,
account_created_at: sessionToken.accountCreatedAt
})
reply(certResult)
}, reply)
)
.then(
function(certResult) {
log.activityEvent(
'account.signed',
request,
{
uid: uid,
account_created_at: sessionToken.accountCreatedAt,
device_id: deviceId
}
)
reply(certResult)
},
reply
)
}
}
]
Expand Down
8 changes: 8 additions & 0 deletions lib/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ function create(log, error, config, routes, db) {
server.connection(connectionOptions)

server.register(require('hapi-auth-hawk'), function (err) {
server.auth.strategy(
'sessionTokenWithDevice',
'hawk',
{
getCredentialsFunc: makeCredentialFn(db.sessionWithDevice.bind(db)),
hawk: hawkOptions
}
)
server.auth.strategy(
'sessionToken',
'hawk',
Expand Down
3 changes: 2 additions & 1 deletion lib/signer.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ module.exports = function (secretKeyFile, domain) {
exp: now + data.duration,
'fxa-generation': data.generation,
'fxa-lastAuthAt': data.lastAuthAt,
'fxa-verifiedEmail': data.verifiedEmail
'fxa-verifiedEmail': data.verifiedEmail,
'fxa-deviceId': data.deviceId
}
)
.then(
Expand Down
16 changes: 13 additions & 3 deletions lib/tokens/session_token.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ module.exports = function (log, inherits, Token) {

function SessionToken(keys, details) {
Token.call(this, keys, details)
this.forceUpdate(details)
this.setUserAgentInfo(details)
this.setDeviceInfo(details)
this.email = details.email || null
this.emailCode = details.emailCode || null
this.emailVerified = !!details.emailVerified
Expand Down Expand Up @@ -60,7 +61,7 @@ module.exports = function (log, inherits, Token) {
return false
}

this.forceUpdate(freshData)
this.setUserAgentInfo(freshData)

return true
}
Expand All @@ -83,7 +84,7 @@ module.exports = function (log, inherits, Token) {
return result
}

SessionToken.prototype.forceUpdate = function (data) {
SessionToken.prototype.setUserAgentInfo = function (data) {
this.uaBrowser = data.uaBrowser
this.uaBrowserVersion = data.uaBrowserVersion
this.uaOS = data.uaOS
Expand All @@ -92,6 +93,15 @@ module.exports = function (log, inherits, Token) {
this.lastAccessTime = data.lastAccessTime
}

SessionToken.prototype.setDeviceInfo = function (data) {
this.deviceId = data.deviceId
this.deviceName = data.deviceName
this.deviceType = data.deviceType
this.deviceCreatedAt = data.deviceCreatedAt
this.callbackURL = data.callbackURL
this.callbackPublicKey = data.callbackPublicKey
}

return SessionToken
}

Expand Down
2 changes: 1 addition & 1 deletion npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

29 changes: 14 additions & 15 deletions test/local/session_token_tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ test(
t.equal(typeof token.lastAuthAt, 'function', 'lastAuthAt method is defined')
t.equal(typeof token.update, 'function', 'update method is defined')
t.equal(typeof token.isFresh, 'function', 'isFresh method is defined')
t.equal(typeof token.forceUpdate, 'function', 'forceUpdate method is defined')
t.equal(typeof token.setUserAgentInfo, 'function', 'setUserAgentInfo method is defined')
})
}
)
Expand Down Expand Up @@ -81,11 +81,11 @@ test(
)

test(
'SessionToken.forceUpdate',
'SessionToken.setUserAgentInfo',
function (t) {
return SessionToken.create(ACCOUNT)
.then(function (token) {
token.forceUpdate({
token.setUserAgentInfo({
data: 'foo',
tokenId: 'foo',
authKey: 'foo',
Expand Down Expand Up @@ -217,7 +217,7 @@ test(
sinon.stub(SessionToken.prototype, 'isFresh', function () {
return true
})
sinon.spy(SessionToken.prototype, 'forceUpdate')
sinon.spy(SessionToken.prototype, 'setUserAgentInfo')

t.equal(
token.update(
Expand All @@ -240,11 +240,11 @@ test(
t.ok(isFreshData.lastAccessTime > Date.now() - 10000, 'lastAccessTime was greater than 10 seconds ago')
t.ok(isFreshData.lastAccessTime < Date.now(), 'lastAccessTime was less then Date.now()')

t.equal(SessionToken.prototype.forceUpdate.callCount, 0, 'forceUpdate was not called')
t.equal(SessionToken.prototype.setUserAgentInfo.callCount, 0, 'setUserAgentInfo was not called')
})
.finally(function () {
SessionToken.prototype.isFresh.restore()
SessionToken.prototype.forceUpdate.restore()
SessionToken.prototype.setUserAgentInfo.restore()
})
}
)
Expand All @@ -257,7 +257,7 @@ test(
sinon.stub(SessionToken.prototype, 'isFresh', function () {
return false
})
sinon.spy(SessionToken.prototype, 'forceUpdate')
sinon.spy(SessionToken.prototype, 'setUserAgentInfo')

t.equal(
token.update(
Expand All @@ -266,19 +266,18 @@ test(
)

t.equal(SessionToken.prototype.isFresh.callCount, 1, 'isFresh was called once')
var isFreshArgs = SessionToken.prototype.forceUpdate.args[0]
var isFreshArgs = SessionToken.prototype.setUserAgentInfo.args[0]
t.equal(isFreshArgs.length, 1, 'isFresh was passed one argument')

t.equal(SessionToken.prototype.forceUpdate.callCount, 1, 'forceUpdate called once')
t.equal(SessionToken.prototype.forceUpdate.thisValues[0], token, 'forceUpdate context was token')
var forceUpdateArgs = SessionToken.prototype.forceUpdate.args[0]
t.equal(forceUpdateArgs.length, 1, 'forceUpdate was passed one argument')
t.deepEqual(forceUpdateArgs[0], isFreshArgs[0], 'forceUpdate was passed correct argument')
t.equal(SessionToken.prototype.setUserAgentInfo.callCount, 1, 'setUserAgentInfo called once')
t.equal(SessionToken.prototype.setUserAgentInfo.thisValues[0], token, 'setUserAgentInfo context was token')
var setUserAgentInfoArgs = SessionToken.prototype.setUserAgentInfo.args[0]
t.equal(setUserAgentInfoArgs.length, 1, 'setUserAgentInfo was passed one argument')
t.deepEqual(setUserAgentInfoArgs[0], isFreshArgs[0], 'setUserAgentInfo was passed correct argument')
})
.finally(function () {
SessionToken.prototype.isFresh.restore()
SessionToken.prototype.forceUpdate.restore()
SessionToken.prototype.setUserAgentInfo.restore()
})
}
)

0 comments on commit a866e8f

Please sign in to comment.