meshblu-core-manager-token
Version:
Meshblu Token Manager
113 lines (95 loc) • 4.38 kB
text/coffeescript
_ = require 'lodash'
crypto = require 'crypto'
class TokenManager
constructor: ({@datastore,@pepper,@uuidAliasResolver}) ->
throw new Error "Missing mandatory parameter: @pepper" if _.isEmpty @pepper
generateAndStoreToken: ({ uuid, metadata, expiresOn, root }, callback) =>
@uuidAliasResolver.resolve uuid, (error, uuid) =>
token = @_generateToken()
hashedToken = @hashToken {uuid, token}
return callback new Error 'Unable to hash token' unless hashedToken?
@_storeHashedToken { uuid, hashedToken, metadata, expiresOn, root }, (error) =>
return callback error if error?
callback null, token
hashToken: ({uuid, token}) =>
return unless uuid? and token?
hasher = crypto.createHash 'sha256'
hasher.update token
hasher.update uuid
hasher.update @pepper
hasher.digest 'base64'
search: ({uuid, query, projection}, callback) =>
return callback new Error 'Missing uuid' unless uuid?
query ?= {}
projection ?= {}
secureQuery = _.clone query
secureQuery.uuid = uuid
options =
limit: 1000
maxTimeMS: 2000
sort: {_id: -1}
@datastore.find secureQuery, projection, options, (error, tokens) =>
return callback error if error?
results = _.map tokens, (token) =>
_.omit token, ['hashedToken']
callback null, results
storeToken: ({ uuid, token, expiresOn, root }, callback) =>
@uuidAliasResolver.resolve uuid, (error, uuid) =>
return callback error if error?
hashedToken = @hashToken {uuid, token}
return callback new Error 'Unable to hash token' unless hashedToken?
@_storeHashedToken { uuid, hashedToken, expiresOn, root }, callback
removeRootToken: ({uuid}, callback) =>
@uuidAliasResolver.resolve uuid, (error, uuid) =>
return callback error if error?
@datastore.remove {uuid, root: true}, callback
revokeToken: ({uuid, token}, callback) =>
@uuidAliasResolver.resolve uuid, (error, uuid) =>
return callback error if error?
hashedToken = @hashToken {uuid, token}
return callback new Error 'Unable to hash token' unless hashedToken?
@datastore.remove { uuid, hashedToken }, (error) =>
return callback error if error?
callback null, true
revokeTokenByQuery: ({uuid, query}, callback) =>
@uuidAliasResolver.resolve uuid, (error, uuid) =>
return callback error if error?
removeQuery = { uuid }
_.each query, (value, key) =>
removeQuery["metadata.#{key}"] = value
@datastore.remove removeQuery, (error) =>
return callback error if error?
callback null, true
verifyToken: ({ uuid, token }, callback) =>
return callback null, false unless uuid? and token?
@uuidAliasResolver.resolve uuid, (error, uuid) =>
return callback error if error?
@_verifyHashedToken { uuid, token }, callback
_generateToken: =>
return crypto.createHash('sha1').update((new Date()).valueOf().toString() + Math.random().toString()).digest('hex')
# Becuase I didn't want to make a breaking change
_hashToken: ({ uuid, token }) =>
return @hashToken({ uuid, token })
_storeHashedToken: ({ uuid, hashedToken, metadata, expiresOn, root }, callback) =>
record = { uuid, hashedToken }
return callback new Error('expires on must be a date') if expiresOn? && !_.isDate(expiresOn)
record.expiresOn = expiresOn if expiresOn?
record.root = root if root
record.metadata = metadata if _.isPlainObject metadata
record.metadata ?= {}
@datastore.findOne { uuid, hashedToken }, { uuid: true }, (error, found) =>
return callback error if error?
return @datastore.insert record, callback unless found?
@datastore.update { uuid, hashedToken }, { $set: record }, callback
_verifyHashedToken: ({ uuid, token }, callback) =>
hashedToken = @hashToken { uuid, token }
return callback new Error 'Unable to hash token' unless hashedToken?
query = { uuid, hashedToken }
@datastore.findOne query, { uuid: true }, (error, record) =>
return callback error if error?
return callback null, false unless record?
return callback null, true unless record.expiresOn?
@datastore.remove query, (error) =>
return callback error if error?
return callback null, true
module.exports = TokenManager