const crypto = require('crypto') const { db } = require('../../infrastructure/mongodb') const Errors = require('../Errors/Errors') const { promisifyAll } = require('../../util/promises') const ONE_HOUR_IN_S = 60 * 60 const OneTimeTokenHandler = { getNewToken(use, data, options, callback) { // options is optional if (!options) { options = {} } if (typeof options === 'function') { callback = options options = {} } const expiresIn = options.expiresIn || ONE_HOUR_IN_S const createdAt = new Date() const expiresAt = new Date(createdAt.getTime() + expiresIn * 1000) const token = crypto.randomBytes(32).toString('hex') db.tokens.insertOne( { use, token, data, createdAt, expiresAt, }, function (error) { if (error) { return callback(error) } callback(null, token) } ) }, getValueFromTokenAndExpire(use, token, callback) { const now = new Date() db.tokens.findOneAndUpdate( { use, token, expiresAt: { $gt: now }, usedAt: { $exists: false }, }, { $set: { usedAt: now, }, }, function (error, result) { if (error) { return callback(error) } const token = result.value if (!token) { return callback(new Errors.NotFoundError('no token found')) } callback(null, token.data) } ) }, } OneTimeTokenHandler.promises = promisifyAll(OneTimeTokenHandler) module.exports = OneTimeTokenHandler