diff --git a/bin/key_server.js b/bin/key_server.js index 4ec60ab4..2529d94a 100644 --- a/bin/key_server.js +++ b/bin/key_server.js @@ -163,6 +163,12 @@ function main() { server.log.fatal(err) process.exit(8) }) + process.on('unhandledRejection', (reason, promise) => { + server.log.fatal({ + op: 'promise.unhandledRejection', + error: reason + }) + }) process.on('SIGINT', shutdown) server.log.on('error', shutdown) diff --git a/lib/crypto/butil.js b/lib/crypto/butil.js index e16b1144..e2ddb6c7 100644 --- a/lib/crypto/butil.js +++ b/lib/crypto/butil.js @@ -4,11 +4,11 @@ 'use strict' -const HEX = /^(?:[a-fA-F0-9]{2})+$/ - module.exports.ONES = Buffer('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff', 'hex') module.exports.buffersAreEqual = function buffersAreEqual(buffer1, buffer2) { + buffer1 = Buffer.from(buffer1, 'hex') + buffer2 = Buffer.from(buffer2, 'hex') var mismatch = buffer1.length - buffer2.length if (mismatch) { return false @@ -20,6 +20,8 @@ module.exports.buffersAreEqual = function buffersAreEqual(buffer1, buffer2) { } module.exports.xorBuffers = function xorBuffers(buffer1, buffer2) { + buffer1 = Buffer.from(buffer1, 'hex') + buffer2 = Buffer.from(buffer2, 'hex') if (buffer1.length !== buffer2.length) { throw new Error( 'XOR buffers must be same length (%d != %d)', @@ -33,46 +35,3 @@ module.exports.xorBuffers = function xorBuffers(buffer1, buffer2) { } return result } - -module.exports.unbuffer = (object, inplace) => { - return Object.keys(object).reduce((unbuffered, key) => { - unbuffered[key] = unbufferDatum.call(object, key, object[key]) - return unbuffered - }, inplace ? object : {}) -} - -module.exports.unbufferDatum = unbufferDatum - -// Invoked as the `replacer` in calls to JSON.stringify. -// If you're going to call it elsewhere, `this` must be -// set as it would be then. -function unbufferDatum (key, value) { - const unstringifiedValue = this[key] - - if (Buffer.isBuffer(unstringifiedValue)) { - return unstringifiedValue.toString('hex') - } - - return value -} - -module.exports.bufferize = function bufferize(object, options) { - var keys = Object.keys(object) - options = options || {} - var copy = options.inplace ? object : {} - var ignore = options.ignore || [] - for (var i = 0; i < keys.length; i++) { - var key = keys[i] - var value = object[key] - if ( - ignore.indexOf(key) === -1 && - typeof value === 'string' && - HEX.test(value) - ) { - copy[key] = Buffer(value, 'hex') - } else { - copy[key] = value - } - } - return copy -} diff --git a/lib/crypto/password.js b/lib/crypto/password.js index 9569e557..a960951e 100644 --- a/lib/crypto/password.js +++ b/lib/crypto/password.js @@ -21,10 +21,10 @@ module.exports = function(log, config) { function Password(authPW, authSalt, version) { version = typeof(version) === 'number' ? version : 1 - this.authPW = authPW - this.authSalt = authSalt + this.authPW = Buffer.from(authPW, 'hex') + this.authSalt = Buffer.from(authSalt, 'hex') this.version = version - this.stretchPromise = hashVersions[version](authPW, authSalt) + this.stretchPromise = hashVersions[version](this.authPW, this.authSalt) this.verifyHashPromise = this.stretchPromise.then(hkdfVerify) } @@ -51,7 +51,7 @@ module.exports = function(log, config) { return hkdf(stretched, context, null, 32) .then( function (wrapper) { - return butil.xorBuffers(wrapper, wrapped) + return butil.xorBuffers(wrapper, wrapped).toString('hex') } ) } @@ -60,7 +60,7 @@ module.exports = function(log, config) { Password.prototype.wrap = Password.prototype.unwrap function hkdfVerify(stretched) { - return hkdf(stretched, 'verifyHash', null, 32) + return hkdf(stretched, 'verifyHash', null, 32).then(buf => buf.toString('hex')) } Password.stat = function () { diff --git a/lib/crypto/pbkdf2.js b/lib/crypto/pbkdf2.js index 80d2af7d..50b6adec 100644 --- a/lib/crypto/pbkdf2.js +++ b/lib/crypto/pbkdf2.js @@ -16,7 +16,7 @@ function derive(input, salt, iterations, len) { var saltBits = sjcl.codec.hex.toBits(salt.toString('hex')) var result = sjcl.misc.pbkdf2(password, saltBits, iterations, len * 8, sjcl.misc.hmac) - return P.resolve(Buffer(sjcl.codec.hex.fromBits(result), 'hex')) + return P.resolve(Buffer.from(sjcl.codec.hex.fromBits(result), 'hex')) } module.exports.derive = derive diff --git a/lib/crypto/random.js b/lib/crypto/random.js index 7f4fea3b..f2311a58 100644 --- a/lib/crypto/random.js +++ b/lib/crypto/random.js @@ -4,4 +4,33 @@ 'use strict' -module.exports = require('../promise').promisify(require('crypto').randomBytes) +const randomBytes = require('../promise').promisify(require('crypto').randomBytes) + +function random(bytes) { + if (arguments.length > 1) { + bytes = Array.from(arguments) + const sum = bytes.reduce((acc, val) => acc + val, 0) + return randomBytes(sum).then(buf => { + let pos = 0 + return bytes.map(num => { + const slice = buf.slice(pos, pos + num) + pos += num + return slice + }) + }) + } else { + return randomBytes(bytes) + } +} + +random.hex = function hex() { + return random.apply(null, arguments).then(bufs => { + if (Array.isArray(bufs)) { + return bufs.map(buf => buf.toString('hex')) + } else { + return bufs.toString('hex') + } + }) +} + +module.exports = random diff --git a/lib/db.js b/lib/db.js index 062cd601..77f7a4b4 100644 --- a/lib/db.js +++ b/lib/db.js @@ -9,7 +9,6 @@ const P = require('./promise') const Pool = require('./pool') const userAgent = require('./userAgent') -const bufferize = require('./crypto/butil').bufferize const random = require('./crypto/random') module.exports = ( @@ -55,7 +54,7 @@ module.exports = ( data.createdAt = data.verifierSetAt = Date.now() data.normalizedEmail = data.email.toLowerCase() return this.pool.put( - '/account/' + data.uid.toString('hex'), + '/account/' + data.uid, data ) .then( @@ -177,9 +176,8 @@ module.exports = ( // READ DB.prototype.checkPassword = function (uid, verifyHash) { - verifyHash = Buffer(verifyHash).toString('hex') log.trace({ op: 'DB.checkPassword', uid: uid, verifyHash: verifyHash }) - return this.pool.post('/account/' + uid.toString('hex') + '/checkPassword', + return this.pool.post('/account/' + uid + '/checkPassword', { 'verifyHash': verifyHash }) @@ -198,7 +196,7 @@ module.exports = ( DB.prototype.accountExists = function (email) { log.trace({ op: 'DB.accountExists', email: email }) - return this.pool.head('/emailRecord/' + Buffer(email, 'utf8').toString('hex')) + return this.pool.head('/emailRecord/' + hexEncode(email)) .then( function () { return true @@ -214,38 +212,14 @@ module.exports = ( DB.prototype.sessions = function (uid) { log.trace({ op: 'DB.sessions', uid: uid }) - return this.pool.get('/account/' + uid.toString('hex') + '/sessions') - .then( - function (body) { - return body.map(function (sessionToken) { - return bufferize(sessionToken, { - ignore: [ - 'uaBrowser', - 'uaBrowserVersion', - 'uaOS', - 'uaOSVersion', - 'uaDeviceType' - ] - }) - }) - } - ) + return this.pool.get('/account/' + uid + '/sessions') } DB.prototype.sessionToken = function (id) { log.trace({ op: 'DB.sessionToken', id: id }) - return this.pool.get('/sessionToken/' + id.toString('hex')) + return this.pool.get('/sessionToken/' + id) .then( - function (body) { - var data = bufferize(body, { - ignore: [ - 'uaBrowser', - 'uaBrowserVersion', - 'uaOS', - 'uaOSVersion', - 'uaDeviceType' - ] - }) + function (data) { return SessionToken.fromHex(data.tokenData, data) }, function (err) { @@ -257,18 +231,9 @@ module.exports = ( DB.prototype.sessionTokenWithVerificationStatus = function (id) { log.trace({ op: 'DB.sessionTokenWithVerificationStatus', id: id }) - return this.pool.get('/sessionToken/' + id.toString('hex') + '/verified') + return this.pool.get('/sessionToken/' + id + '/verified') .then( - function (body) { - var data = bufferize(body, { - ignore: [ - 'uaBrowser', - 'uaBrowserVersion', - 'uaOS', - 'uaOSVersion', - 'uaDeviceType' - ] - }) + function (data) { return SessionToken.fromHex(data.tokenData, data) }, function (err) { @@ -280,10 +245,9 @@ module.exports = ( DB.prototype.keyFetchToken = function (id) { log.trace({ op: 'DB.keyFetchToken', id: id }) - return this.pool.get('/keyFetchToken/' + id.toString('hex')) + return this.pool.get('/keyFetchToken/' + id) .then( - function (body) { - var data = bufferize(body) + function (data) { return KeyFetchToken.fromId(id, data) }, function (err) { @@ -295,10 +259,9 @@ module.exports = ( DB.prototype.keyFetchTokenWithVerificationStatus = function (id) { log.trace({ op: 'DB.keyFetchTokenWithVerificationStatus', id: id }) - return this.pool.get('/keyFetchToken/' + id.toString('hex') + '/verified') + return this.pool.get('/keyFetchToken/' + id + '/verified') .then( - function (body) { - var data = bufferize(body) + function (data) { return KeyFetchToken.fromId(id, data) }, function (err) { @@ -310,10 +273,9 @@ module.exports = ( DB.prototype.accountResetToken = function (id) { log.trace({ op: 'DB.accountResetToken', id: id }) - return this.pool.get('/accountResetToken/' + id.toString('hex')) + return this.pool.get('/accountResetToken/' + id) .then( - function (body) { - var data = bufferize(body) + function (data) { return AccountResetToken.fromHex(data.tokenData, data) }, function (err) { @@ -325,10 +287,9 @@ module.exports = ( DB.prototype.passwordForgotToken = function (id) { log.trace({ op: 'DB.passwordForgotToken', id: id }) - return this.pool.get('/passwordForgotToken/' + id.toString('hex')) + return this.pool.get('/passwordForgotToken/' + id) .then( - function (body) { - var data = bufferize(body) + function (data) { return PasswordForgotToken.fromHex(data.tokenData, data) }, function (err) { @@ -340,10 +301,9 @@ module.exports = ( DB.prototype.passwordChangeToken = function (id) { log.trace({ op: 'DB.passwordChangeToken', id: id }) - return this.pool.get('/passwordChangeToken/' + id.toString('hex')) + return this.pool.get('/passwordChangeToken/' + id) .then( - function (body) { - var data = bufferize(body) + function (data) { return PasswordChangeToken.fromHex(data.tokenData, data) }, function (err) { @@ -355,10 +315,9 @@ module.exports = ( DB.prototype.emailRecord = function (email) { log.trace({ op: 'DB.emailRecord', email: email }) - return this.pool.get('/emailRecord/' + Buffer(email, 'utf8').toString('hex')) + return this.pool.get('/emailRecord/' + hexEncode(email)) .then( - function (body) { - var data = bufferize(body) + function (data) { data.emailVerified = !! data.emailVerified return data }, @@ -373,10 +332,9 @@ module.exports = ( DB.prototype.account = function (uid) { log.trace({ op: 'DB.account', uid: uid }) - return this.pool.get('/account/' + uid.toString('hex')) + return this.pool.get('/account/' + uid) .then( - function (body) { - var data = bufferize(body) + function (data) { data.emailVerified = !! data.emailVerified return data }, @@ -392,11 +350,11 @@ module.exports = ( DB.prototype.devices = function (uid) { log.trace({ op: 'DB.devices', uid: uid }) - return this.pool.get('/account/' + uid.toString('hex') + '/devices') + return this.pool.get('/account/' + uid + '/devices') .then( function (body) { return body.map(function (item) { - return bufferize({ + return { id: item.id, sessionToken: item.sessionTokenId, lastAccessTime: marshallLastAccessTime(item.lastAccessTime, uid, item.email), @@ -410,12 +368,7 @@ module.exports = ( uaOS: item.uaOS, uaOSVersion: item.uaOSVersion, uaDeviceType: item.uaDeviceType - }, { - ignore: [ - 'name', 'type', 'pushCallback', 'pushPublicKey', 'pushAuthKey', - 'uaBrowser', 'uaBrowserVersion', 'uaOS', 'uaOSVersion', 'uaDeviceType' - ] - }) + } }) }, function (err) { @@ -440,18 +393,9 @@ module.exports = ( DB.prototype.sessionWithDevice = function (id) { log.trace({ op: 'DB.sessionWithDevice', id: id }) - return this.pool.get('/sessionToken/' + id.toString('hex') + '/device') + return this.pool.get('/sessionToken/' + id + '/device') .then( - function (body) { - var data = bufferize(body, { - ignore: [ - 'uaBrowser', - 'uaBrowserVersion', - 'uaOS', - 'uaOSVersion', - 'uaDeviceType' - ] - }) + function (data) { return SessionToken.fromHex(data.tokenData, data) }, function (err) { @@ -493,13 +437,13 @@ module.exports = ( DB.prototype.createDevice = function (uid, sessionTokenId, deviceInfo) { log.trace({ op: 'DB.createDevice', uid: uid, id: deviceInfo.id }) - return random(16) + return random.hex(16) .then(id => { deviceInfo.id = id deviceInfo.createdAt = Date.now() return this.pool.put( - '/account/' + uid.toString('hex') + - '/device/' + deviceInfo.id.toString('hex'), + '/account/' + uid + + '/device/' + deviceInfo.id, { sessionTokenId: sessionTokenId, createdAt: deviceInfo.createdAt, @@ -524,7 +468,7 @@ module.exports = ( // return an appropriate error. devices => { const isDuplicateDeviceId = devices.reduce((is, device) => { - is || device.id.toString('hex') === deviceInfo.id.toString('hex') + is || device.id === deviceInfo.id }, false) if (isDuplicateDeviceId) { @@ -543,8 +487,8 @@ module.exports = ( DB.prototype.updateDevice = function (uid, sessionTokenId, deviceInfo) { log.trace({ op: 'DB.updateDevice', uid: uid, id: deviceInfo.id }) return this.pool.post( - '/account/' + uid.toString('hex') + - '/device/' + deviceInfo.id.toString('hex') + '/update', + '/account/' + uid + + '/device/' + deviceInfo.id + '/update', { sessionTokenId: sessionTokenId, name: deviceInfo.name, @@ -574,7 +518,7 @@ module.exports = ( DB.prototype.deleteAccount = function (authToken) { log.trace({ op: 'DB.deleteAccount', uid: authToken && authToken.uid }) - return this.pool.del('/account/' + authToken.uid.toString('hex')) + return this.pool.del('/account/' + authToken.uid) } DB.prototype.deleteSessionToken = function (sessionToken) { @@ -641,7 +585,7 @@ module.exports = ( } ) return this.pool.del( - '/account/' + uid.toString('hex') + '/device/' + deviceId.toString('hex') + '/account/' + uid + '/device/' + deviceId ) .catch( function (err) { @@ -662,7 +606,7 @@ module.exports = ( } ) return this.pool.get( - '/account/' + uid.toString('hex') + '/tokens/' + tokenVerificationId.toString('hex') + '/device' + '/account/' + uid + '/tokens/' + tokenVerificationId + '/device' ) .catch( function (err) { @@ -680,7 +624,7 @@ module.exports = ( log.trace({ op: 'DB.resetAccount', uid: accountResetToken && accountResetToken.uid }) data.verifierSetAt = Date.now() return this.pool.post( - '/account/' + accountResetToken.uid.toString('hex') + '/reset', + '/account/' + accountResetToken.uid + '/reset', data ) } @@ -691,13 +635,13 @@ module.exports = ( uid: account && account.uid, emailCode: emailCode }) - return this.pool.post('/account/' + account.uid.toString('hex') + '/verifyEmail/' + emailCode.toString('hex')) + return this.pool.post('/account/' + account.uid + '/verifyEmail/' + emailCode) } DB.prototype.verifyTokens = function (tokenVerificationId, accountData) { log.trace({ op: 'DB.verifyTokens', tokenVerificationId: tokenVerificationId }) return this.pool.post( - '/tokens/' + tokenVerificationId.toString('hex') + '/verify', + '/tokens/' + tokenVerificationId + '/verify', { uid: accountData.uid } ) .then( @@ -739,7 +683,7 @@ module.exports = ( DB.prototype.updateLocale = function (uid, locale) { log.trace({ op: 'DB.updateLocale', uid: uid, locale: locale }) return this.pool.post( - '/account/' + uid.toString('hex') + '/locale', + '/account/' + uid + '/locale', { locale: locale } ) } @@ -779,7 +723,7 @@ module.exports = ( params: params }) - return this.pool.get('/securityEvents/' + params.uid.toString('hex') + '/ip/' + params.ipAddr) + return this.pool.get('/securityEvents/' + params.uid + '/ip/' + params.ipAddr) } DB.prototype.createUnblockCode = function (uid) { @@ -790,7 +734,7 @@ module.exports = ( return UnblockCode() .then( (unblock) => { - return this.pool.put('/account/' + uid.toString('hex') + '/unblock/' + unblock) + return this.pool.put('/account/' + uid + '/unblock/' + unblock) .then( () => { return unblock @@ -818,7 +762,7 @@ module.exports = ( op: 'DB.consumeUnblockCode', uid: uid }) - return this.pool.del('/account/' + uid.toString('hex') + '/unblock/' + code) + return this.pool.del('/account/' + uid + '/unblock/' + code) .catch( function (err) { if (isNotFoundError(err)) { @@ -844,7 +788,7 @@ module.exports = ( email: email }) - return this.pool.get('/emailBounces/' + Buffer(email, 'utf8').toString('hex')) + return this.pool.get('/emailBounces/' + hexEncode(email)) } DB.prototype.accountEmails = function (uid) { @@ -853,7 +797,7 @@ module.exports = ( uid: uid }) - return this.pool.get('/account/' + uid.toString('hex') + '/emails') + return this.pool.get('/account/' + uid + '/emails') } DB.prototype.getSecondaryEmail = function (email) { @@ -862,10 +806,7 @@ module.exports = ( email: email }) - return this.pool.get('/email/' + Buffer(email, 'utf8').toString('hex')) - .then((body) => { - return bufferize(body) - }) + return this.pool.get('/email/' + hexEncode(email)) .catch((err) => { if (isNotFoundError(err)) { throw error.unknownSecondaryEmail() @@ -881,7 +822,7 @@ module.exports = ( uid: emailData.uid }) - return this.pool.post('/account/' + uid.toString('hex') + '/emails', emailData) + return this.pool.post('/account/' + uid + '/emails', emailData) .catch( function (err) { if (isEmailAlreadyExistsError(err)) { @@ -898,7 +839,7 @@ module.exports = ( uid: uid }) - return this.pool.del('/account/' + uid.toString('hex') + '/emails/' + email) + return this.pool.del('/account/' + uid + '/emails/' + email) .catch( function (err) { if (isEmailDeletePrimaryError(err)) { @@ -912,10 +853,10 @@ module.exports = ( DB.prototype.createSigninCode = function (uid, flowId) { log.trace({ op: 'DB.createSigninCode' }) - return random(config.signinCodeSize) + return random.hex(config.signinCodeSize) .then(code => { const data = { uid, createdAt: Date.now(), flowId } - return this.pool.put(`/signinCodes/${code.toString('hex')}`, data) + return this.pool.put(`/signinCodes/${code}`, data) .then(() => code, err => { if (isRecordAlreadyExistsError(err)) { log.warn({ op: 'DB.createSigninCode.duplicate' }) @@ -930,7 +871,7 @@ module.exports = ( DB.prototype.consumeSigninCode = function (code) { log.trace({ op: 'DB.consumeSigninCode', code }) - return this.pool.post(`/signinCodes/${code.toString('hex')}/consume`) + return this.pool.post(`/signinCodes/${code}/consume`) .catch(err => { if (isNotFoundError(err)) { throw error.invalidSigninCode() @@ -947,6 +888,10 @@ module.exports = ( return err } + function hexEncode(str) { + return Buffer(str, 'utf8').toString('hex') + } + return DB } diff --git a/lib/devices.js b/lib/devices.js index e4dfd356..1d6123f0 100644 --- a/lib/devices.js +++ b/lib/devices.js @@ -25,8 +25,8 @@ module.exports = function (log, db, push) { .then(function (device) { result = device return request.emitMetricsEvent(event, { - uid: sessionToken.uid.toString('hex'), - device_id: result.id.toString('hex'), + uid: sessionToken.uid, + device_id: result.id, is_placeholder: isPlaceholderDevice }) }) @@ -39,7 +39,7 @@ module.exports = function (log, db, push) { deviceName = synthesizeName(deviceInfo) } if (sessionToken.tokenVerified) { - push.notifyDeviceConnected(sessionToken.uid, deviceName, result.id.toString('hex')) + push.notifyDeviceConnected(sessionToken.uid, deviceName, result.id) } if (isPlaceholderDevice) { log.info({ diff --git a/lib/email/bounces.js b/lib/email/bounces.js index e23af4ea..c7583e4c 100644 --- a/lib/email/bounces.js +++ b/lib/email/bounces.js @@ -13,7 +13,7 @@ module.exports = function (log, error) { return function start(bounceQueue, db) { function accountDeleted(uid, email) { - log.info({ op: 'accountDeleted', uid: uid.toString('hex'), email: email }) + log.info({ op: 'accountDeleted', uid: uid, email: email }) } function gotError(email, err) { diff --git a/lib/features.js b/lib/features.js index 2a0f187d..19722133 100644 --- a/lib/features.js +++ b/lib/features.js @@ -67,10 +67,6 @@ function isSampledUser (sampleRate, uid, key) { return false } - if (Buffer.isBuffer(uid)) { - uid = uid.toString('hex') - } - // Extract the maximum entropy we can safely handle as a number then reduce // it to a value between 0 and 1 for comparison against the sample rate. const cohort = parseInt( diff --git a/lib/log.js b/lib/log.js index b5142561..ed6bffd4 100644 --- a/lib/log.js +++ b/lib/log.js @@ -9,7 +9,6 @@ const util = require('util') const mozlog = require('mozlog') const config = require('../config') const logConfig = config.get('log') -const unbuffer = require('./crypto/butil').unbuffer function Lug(options) { @@ -110,10 +109,10 @@ Lug.prototype.summary = function (request, response) { if (line.code >= 500) { line.trace = request.app.traced line.stack = response.stack - this.error(unbuffer(line, true), response.message) + this.error(line, response.message) } else { - this.info(unbuffer(line, true)) + this.info(line) } } @@ -126,7 +125,7 @@ Lug.prototype.notifyAttachedServices = function (name, request, data) { metricsContextData => { var e = { event: name, - data: unbuffer(data) + data: data } e.data.metricsContext = metricsContextData this.notifier.send(e) @@ -159,7 +158,6 @@ Lug.prototype.flowEvent = function (data) { this.logger.info('flowEvent', data) } -var onUnhandledRejection module.exports = function (level, name, options) { if (arguments.length === 1 && typeof level === 'object') { options = level @@ -181,16 +179,5 @@ module.exports = function (level, name, options) { } ) - if (onUnhandledRejection) { - process.removeListener('unhandledRejection', onUnhandledRejection) - } - onUnhandledRejection = (reason, promise) => { - log.fatal({ - op: 'promise.unhandledRejection', - error: reason - }) - } - process.on('unhandledRejection', onUnhandledRejection) - return log } diff --git a/lib/metrics/context.js b/lib/metrics/context.js index c2450260..4b45216d 100644 --- a/lib/metrics/context.js +++ b/lib/metrics/context.js @@ -107,7 +107,7 @@ module.exports = function (log, config) { if (request.payload && request.payload.uid && request.payload.code) { return { - uid: Buffer(request.payload.uid, 'hex'), + uid: request.payload.uid, id: request.payload.code } } diff --git a/lib/metrics/events.js b/lib/metrics/events.js index 5656ce39..07fe67de 100644 --- a/lib/metrics/events.js +++ b/lib/metrics/events.js @@ -189,12 +189,11 @@ function optionallySetService (data, request) { function coalesceUid (data, request) { if (data && data.uid) { - return Buffer.isBuffer(data.uid) ? data.uid.toString('hex') : data.uid + return data.uid } return request.auth && request.auth.credentials && - request.auth.credentials.uid && - request.auth.credentials.uid.toString('hex') + request.auth.credentials.uid } diff --git a/lib/pool.js b/lib/pool.js index 7f52a468..a0d10505 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -6,7 +6,6 @@ const P = require('./promise') const Poolee = require('poolee') -const unbufferDatum = require('./crypto/butil').unbufferDatum function parseUrl(url) { var match = /([a-zA-Z]+):\/\/(\S+)/.exec(url) @@ -43,7 +42,7 @@ Pool.prototype.request = function (method, path, data) { headers: { 'Content-Type': 'application/json' }, - data: data ? JSON.stringify(data, unbufferDatum) : undefined + data: data ? JSON.stringify(data) : undefined }, handleResponse ) diff --git a/lib/push.js b/lib/push.js index d83a8079..12303646 100644 --- a/lib/push.js +++ b/lib/push.js @@ -134,7 +134,7 @@ module.exports = function (log, db, config) { function reportPushError(err, uid, deviceId) { log.error({ op: LOG_OP_PUSH_TO_DEVICES, - uid: uid.toString('hex'), + uid: uid, deviceId: deviceId, err: err }) @@ -323,7 +323,7 @@ module.exports = function (log, db, config) { version: PUSH_PAYLOAD_SCHEMA_VERSION, command: PUSH_COMMANDS.ACCOUNT_DESTROYED, data: { - uid: uid.toString('hex') + uid: uid } })) var options = { data: data, TTL: TTL_ACCOUNT_DESTROYED } @@ -348,7 +348,7 @@ module.exports = function (log, db, config) { function (devices) { if (options.excludedDeviceIds) { devices = devices.filter(function(device) { - return options.excludedDeviceIds.indexOf(device.id.toString('hex')) === -1 + return options.excludedDeviceIds.indexOf(device.id) === -1 }) } var pushOptions = filterOptions(options) @@ -372,7 +372,7 @@ module.exports = function (log, db, config) { return db.devices(uid).then( function (devices) { devices = devices.filter(function(device) { - return ids.indexOf(device.id.toString('hex')) !== -1 + return ids.indexOf(device.id) !== -1 }) if (devices.length === 0) { return P.reject('Devices ids not found in devices') @@ -435,7 +435,7 @@ module.exports = function (log, db, config) { reportPushError(new Error(ERR_TOO_MANY_DEVICES), uid, null) } return P.each(devices, function(device) { - var deviceId = device.id.toString('hex') + var deviceId = device.id log.trace({ op: LOG_OP_PUSH_TO_DEVICES, diff --git a/lib/routes/account.js b/lib/routes/account.js index 1615be08..cd5b3c97 100644 --- a/lib/routes/account.js +++ b/lib/routes/account.js @@ -99,7 +99,7 @@ module.exports = ( var form = request.payload var query = request.query var email = form.email - var authPW = Buffer(form.authPW, 'hex') + var authPW = form.authPW var locale = request.app.acceptLanguage var userAgentString = request.headers['user-agent'] var service = form.service || query.service @@ -158,7 +158,7 @@ module.exports = ( throw error.verifiedSecondaryEmailAlreadyExists() } - return db.deleteEmail(Buffer.from(secondaryEmailRecord.uid, 'hex'), secondaryEmailRecord.email) + return db.deleteEmail(secondaryEmailRecord.uid, secondaryEmailRecord.email) }) .catch((err) => { if (err.errno !== error.ERRNO.SECONDARY_EMAIL_UNKNOWN) { @@ -179,14 +179,11 @@ module.exports = ( return P.resolve() } function generateRandomValues() { - return random(16) - .then(bytes => { - emailCode = bytes - tokenVerificationId = bytes - return random(32) - }) - .then(bytes => { - authSalt = bytes + return random.hex(16, 32) + .then(hexes => { + emailCode = hexes[0] + tokenVerificationId = emailCode + authSalt = hexes[1] }) } @@ -212,15 +209,15 @@ module.exports = ( }) } - return random(64) - .then(bytes => db.createAccount({ - uid: uuid.v4('binary'), + return random.hex(32, 32) + .then(hexes => db.createAccount({ + uid: uuid.v4('binary').toString('hex'), createdAt: Date.now(), email: email, emailCode: emailCode, emailVerified: preVerified, - kA: bytes.slice(0, 32), // 0..31 - wrapWrapKb: bytes.slice(32), // 32..63 + kA: hexes[0], + wrapWrapKb: hexes[1], accountResetToken: null, passwordForgotToken: null, authSalt: authSalt, @@ -234,7 +231,7 @@ module.exports = ( account = result return request.emitMetricsEvent('account.created', { - uid: account.uid.toString('hex') + uid: account.uid }) } ) @@ -291,7 +288,7 @@ module.exports = ( // so stash the data against a synthesized "token" instead. return request.stashMetricsContext({ uid: account.uid, - id: account.emailCode.toString('hex') + id: account.emailCode }) } ) @@ -320,7 +317,7 @@ module.exports = ( .then(function () { // only create reminder if sendVerifyCode succeeds verificationReminder.create({ - uid: account.uid.toString('hex') + uid: account.uid }).catch(function (err) { log.error({op: 'Account.verificationReminder.create', err: err}) }) @@ -329,7 +326,7 @@ module.exports = ( // Log server-side metrics for confirming verification rates log.info({ op: 'account.create.confirm.start', - uid: account.uid.toString('hex'), + uid: account.uid, tokenVerificationId: tokenVerificationId }) } @@ -341,7 +338,7 @@ module.exports = ( // Log possible email bounce, used for confirming verification rates log.error({ op: 'account.create.confirm.error', - uid: account.uid.toString('hex'), + uid: account.uid, err: err, tokenVerificationId: tokenVerificationId }) @@ -385,13 +382,13 @@ module.exports = ( function createResponse () { var response = { - uid: account.uid.toString('hex'), - sessionToken: sessionToken.data.toString('hex'), + uid: account.uid, + sessionToken: sessionToken.data, authAt: sessionToken.lastAuthAt() } if (keyFetchToken) { - response.keyFetchToken = keyFetchToken.data.toString('hex') + response.keyFetchToken = keyFetchToken.data } return P.resolve(response) @@ -435,7 +432,7 @@ module.exports = ( const form = request.payload const email = form.email - const authPW = Buffer(form.authPW, 'hex') + const authPW = form.authPW const service = request.payload.service || request.query.service const redirectTo = request.payload.redirectTo const resume = request.payload.resume @@ -587,7 +584,7 @@ module.exports = ( if (requestNow - code.createdAt > unblockCodeLifetime) { log.info({ op: 'Account.login.unblockCode.expired', - uid: emailRecord.uid.toString('hex') + uid: emailRecord.uid }) throw error.invalidUnblockCode() } @@ -648,14 +645,14 @@ module.exports = ( log.info({ op: 'Account.history.verified', - uid: emailRecord.uid.toString('hex'), + uid: emailRecord.uid, events: events.length, recency: coarseRecency }) } else { log.info({ op: 'Account.history.unverified', - uid: emailRecord.uid.toString('hex'), + uid: emailRecord.uid, events: events.length }) } @@ -667,7 +664,7 @@ module.exports = ( log.error({ op: 'Account.history.error', err: err, - uid: emailRecord.uid.toString('hex') + uid: emailRecord.uid }) } ) @@ -722,7 +719,7 @@ module.exports = ( } return request.emitMetricsEvent('account.login', { - uid: emailRecord.uid.toString('hex') + uid: emailRecord.uid }) } ) @@ -754,7 +751,7 @@ module.exports = ( if (securityEventVerified && securityEventRecency < allowedRecency) { log.info({ op: 'Account.ipprofiling.seenAddress', - uid: account.uid.toString('hex') + uid: account.uid }) return true } @@ -768,7 +765,7 @@ module.exports = ( if (accountAge <= skipForNewAccounts.maxAge) { log.info({ op: 'account.signin.confirm.bypass.age', - uid: account.uid.toString('hex') + uid: account.uid }) return true } @@ -801,8 +798,8 @@ module.exports = ( return P.resolve() .then(() => { if (needsVerificationId) { - return random(16).then(bytes => { - tokenVerificationId = bytes + return random.hex(16).then(hex => { + tokenVerificationId = hex }) } }) @@ -832,7 +829,7 @@ module.exports = ( // so stash the data against a synthesized "token" instead. return request.stashMetricsContext({ uid: emailRecord.uid, - id: tokenVerificationId.toString('hex') + id: tokenVerificationId }) } } @@ -885,7 +882,7 @@ module.exports = ( if (didSigninUnblock) { log.info({ op: 'Account.login.unverified.unblocked', - uid: emailRecord.uid.toString('hex') + uid: emailRecord.uid }) } @@ -967,7 +964,7 @@ module.exports = ( if (doSigninConfirmation) { log.info({ op: 'account.signin.confirm.start', - uid: emailRecord.uid.toString('hex'), + uid: emailRecord.uid, tokenVerificationId: tokenVerificationId }) @@ -1011,8 +1008,8 @@ module.exports = ( function createResponse () { var response = { - uid: sessionToken.uid.toString('hex'), - sessionToken: sessionToken.data.toString('hex'), + uid: sessionToken.uid, + sessionToken: sessionToken.data, verified: sessionToken.emailVerified, authAt: sessionToken.lastAuthAt() } @@ -1022,7 +1019,7 @@ module.exports = ( return P.resolve(response) } - response.keyFetchToken = keyFetchToken.data.toString('hex') + response.keyFetchToken = keyFetchToken.data if (! emailRecord.emailVerified) { response.verified = false @@ -1057,7 +1054,7 @@ module.exports = ( reply({ exists: true, locale: sessionToken.locale }) } else if (request.query.uid) { - var uid = Buffer(request.query.uid, 'hex') + var uid = request.query.uid db.account(uid) .then( function (account) { @@ -1134,7 +1131,7 @@ module.exports = ( if (auth.strategy === 'sessionToken') { uid = auth.credentials.uid } else { - uid = Buffer(auth.credentials.user, 'hex') + uid = auth.credentials.user } function hasProfileItemScope(item) { if (auth.strategy === 'sessionToken') { @@ -1197,14 +1194,14 @@ module.exports = ( .then( function () { return request.emitMetricsEvent('account.keyfetch', { - uid: keyFetchToken.uid.toString('hex') + uid: keyFetchToken.uid }) } ) .then( function () { return { - bundle: keyFetchToken.keyBundle.toString('hex') + bundle: keyFetchToken.keyBundle } } ) @@ -1275,7 +1272,7 @@ module.exports = ( } } else if (sessionToken.deviceId) { // Keep the old id, which is probably from a synthesized device record - payload.id = sessionToken.deviceId.toString('hex') + payload.id = sessionToken.deviceId } if (payload.pushCallback && (! payload.pushPublicKey || ! payload.pushAuthKey)) { @@ -1284,9 +1281,7 @@ module.exports = ( } devices.upsert(request, sessionToken, payload).then( - function (device) { - reply(butil.unbuffer(device)) - }, + reply, reply ) @@ -1295,7 +1290,7 @@ module.exports = ( // Check if anything has actually changed, and log lots metrics on what. function isSpuriousUpdate(payload, token) { var spurious = true - if (! token.deviceId || payload.id !== token.deviceId.toString('hex')) { + if (! token.deviceId || payload.id !== token.deviceId) { spurious = false } if (payload.name && payload.name !== token.deviceName) { @@ -1369,19 +1364,18 @@ module.exports = ( } var endpointAction = 'devicesNotify' - var stringUid = uid.toString('hex') function catchPushError(err) { // push may fail due to not found devices or a bad push action // log the error but still respond with a 200. log.error({ op: 'Account.devicesNotify', - uid: stringUid, + uid: uid, error: err }) } - return customs.checkAuthenticated(endpointAction, ip, stringUid) + return customs.checkAuthenticated(endpointAction, ip, uid) .then(function () { if (body.to === 'all') { push.pushToAllDevices(uid, endpointAction, pushOptions) @@ -1400,12 +1394,12 @@ module.exports = ( if (payload.data.collections.length === 1 && payload.data.collections[0] === 'clients') { var deviceId = undefined if (sessionToken.deviceId) { - deviceId = sessionToken.deviceId.toString('hex') + deviceId = sessionToken.deviceId } return request.emitMetricsEvent('sync.sentTabToDevice', { device_id: deviceId, service: 'sync', - uid: stringUid + uid: uid }) } } @@ -1457,7 +1451,7 @@ module.exports = ( } device.isCurrentDevice = - device.sessionToken.toString('hex') === sessionToken.tokenId.toString('hex') + device.sessionToken === sessionToken.tokenId device.lastAccessTimeFormatted = localizeTimestamp.format(device.lastAccessTime, request.headers['accept-language']) @@ -1469,7 +1463,7 @@ module.exports = ( delete device.uaOSVersion delete device.uaDeviceType - return butil.unbuffer(device) + return device })) }, reply @@ -1509,7 +1503,7 @@ module.exports = ( db.sessions(uid).then( function (sessions) { reply(sessions.map(function (session) { - session.id = session.tokenId.toString('hex') + session.id = session.tokenId // if session has a device record session.isDevice = !! session.deviceId @@ -1523,7 +1517,7 @@ module.exports = ( session.deviceType = session.uaDeviceType || 'desktop' } - session.isCurrentDevice = session.id === sessionToken.tokenId.toString('hex') + session.isCurrentDevice = session.id === sessionToken.tokenId session.lastAccessTimeFormatted = localizeTimestamp.format(session.lastAccessTime, request.headers['accept-language']) @@ -1541,7 +1535,7 @@ module.exports = ( delete session.uaOSVersion delete session.uaDeviceType - return butil.unbuffer(session) + return session })) }, reply @@ -1582,7 +1576,7 @@ module.exports = ( function (res) { result = res return request.emitMetricsEvent('device.deleted', { - uid: uid.toString('hex'), + uid: uid, device_id: id }) } @@ -1837,9 +1831,8 @@ module.exports = ( } }, handler: function (request, reply) { - const uidHex = request.payload.uid - const uid = Buffer(uidHex, 'hex') - const code = Buffer(request.payload.code, 'hex') + const uid = request.payload.uid + const code = request.payload.code const service = request.payload.service || request.query.service const reminder = request.payload.reminder || request.query.reminder const type = request.payload.type || request.query.type @@ -1880,11 +1873,11 @@ module.exports = ( return db.accountEmails(account.uid) .then((emails) => { const isEmailVerification = emails.some((email) => { - if (email.emailCode && (code.toString('hex') === email.emailCode)) { + if (email.emailCode && (code === email.emailCode)) { matchedEmail = email log.info({ op: 'account.verifyEmail.secondary.started', - uid: uidHex, + uid: uid, code: request.payload.code }) return true @@ -1901,7 +1894,7 @@ module.exports = ( if (matchedEmail.isVerified) { log.info({ op: 'account.verifyEmail.secondary.already-verified', - uid: uidHex, + uid: uid, code: request.payload.code }) return P.resolve() @@ -1911,7 +1904,7 @@ module.exports = ( .then(() => { log.info({ op: 'account.verifyEmail.secondary.confirmed', - uid: uidHex, + uid: uid, code: request.payload.code }) return mailer.sendPostVerifySecondaryEmail( @@ -1935,7 +1928,7 @@ module.exports = ( log.error({ op: 'Account.RecoveryEmailVerify', err: err, - uid: uidHex, + uid: uid, code: code }) } @@ -1958,11 +1951,11 @@ module.exports = ( // Don't log sign-in confirmation success for the account verification case log.info({ op: 'account.signin.confirm.success', - uid: uidHex, + uid: uid, code: request.payload.code }) request.emitMetricsEvent('account.confirmed', { - uid: uidHex + uid: uid }) push.notifyUpdate(uid, 'accountConfirm') } @@ -1974,7 +1967,7 @@ module.exports = ( } log.error({ op: 'account.signin.confirm.invalid', - uid: uidHex, + uid: uid, code: request.payload.code, error: err }) @@ -1982,7 +1975,7 @@ module.exports = ( }) .then(function () { if (device) { - push.notifyDeviceConnected(uid, device.name, device.id.toString('hex')) + push.notifyDeviceConnected(uid, device.name, device.id) } }) .then(function () { @@ -2005,7 +1998,7 @@ module.exports = ( }) .then(function () { return request.emitMetricsEvent('account.verified', { - uid: uidHex + uid: uid }) }) .then(function () { @@ -2019,7 +2012,7 @@ module.exports = ( name: reminderOp }) return request.emitMetricsEvent('account.reminder', { - uid: uidHex + uid: uid }) } }) @@ -2028,7 +2021,7 @@ module.exports = ( push.notifyUpdate(uid, 'accountVerify') // remove verification reminders verificationReminder.delete({ - uid: uidHex + uid: uid }).catch(function (err) { log.error({op: 'Account.RecoveryEmailVerify', err: err}) }) @@ -2190,7 +2183,7 @@ module.exports = ( // Only delete secondary email if it is unverified and does not belong // to the current user. if (! secondaryEmailRecord.isVerified && ! butil.buffersAreEqual(secondaryEmailRecord.uid, uid)) { - return db.deleteEmail(Buffer.from(secondaryEmailRecord.uid, 'hex'), secondaryEmailRecord.email) + return db.deleteEmail(secondaryEmailRecord.uid, secondaryEmailRecord.email) } }) .catch((err) => { @@ -2201,9 +2194,9 @@ module.exports = ( } function generateRandomValues() { - return random(16) - .then(bytes => { - emailData.emailCode = bytes + return random.hex(16) + .then(hex => { + emailData.emailCode = hex }) } @@ -2374,7 +2367,7 @@ module.exports = ( } }, handler: function (request, reply) { - var uid = Buffer(request.payload.uid, 'hex') + var uid = request.payload.uid var code = request.payload.unblockCode.toUpperCase() log.begin('Account.RejectUnblockCode', request) @@ -2413,7 +2406,7 @@ module.exports = ( handler: function accountReset(request, reply) { log.begin('Account.reset', request) var accountResetToken = request.auth.credentials - var authPW = Buffer(request.payload.authPW, 'hex') + var authPW = request.payload.authPW var account, sessionToken, keyFetchToken, verifyHash, wrapKb, devicesToNotify var hasSessionToken = request.payload.sessionToken @@ -2448,10 +2441,10 @@ module.exports = ( function resetAccountData () { let authSalt, password, wrapWrapKb - return random(64) - .then(bytes => { - authSalt = bytes.slice(0, 32) // 0..31 - wrapWrapKb = bytes.slice(32) // 32..63 + return random.hex(32, 32) + .then(hexes => { + authSalt = hexes[0] + wrapWrapKb = hexes[1] password = new Password(authPW, authSalt, config.verifierVersion) return password.verifyHash() }) @@ -2482,7 +2475,7 @@ module.exports = ( function (accountData) { account = accountData return request.emitMetricsEvent('account.reset', { - uid: account.uid.toString('hex') + uid: account.uid }) } ) @@ -2574,14 +2567,14 @@ module.exports = ( var response = { - uid: sessionToken.uid.toString('hex'), - sessionToken: sessionToken.data.toString('hex'), + uid: sessionToken.uid, + sessionToken: sessionToken.data, verified: sessionToken.emailVerified, authAt: sessionToken.lastAuthAt() } if (requestHelper.wantsKeys(request)) { - response.keyFetchToken = keyFetchToken.data.toString('hex') + response.keyFetchToken = keyFetchToken.data } return response @@ -2602,7 +2595,7 @@ module.exports = ( handler: function accountDestroy(request, reply) { log.begin('Account.destroy', request) var form = request.payload - var authPW = Buffer(form.authPW, 'hex') + var authPW = form.authPW var uid var devicesToNotify customs.check( @@ -2643,7 +2636,7 @@ module.exports = ( .then( function () { return request.emitMetricsEvent('account.deleted', { - uid: uid.toString('hex') + uid: uid }) } ) diff --git a/lib/routes/password.js b/lib/routes/password.js index 80988ad6..1e188211 100644 --- a/lib/routes/password.js +++ b/lib/routes/password.js @@ -54,7 +54,7 @@ module.exports = function ( handler: function (request, reply) { log.begin('Password.changeStart', request) var form = request.payload - var oldAuthPW = Buffer(form.oldAuthPW, 'hex') + var oldAuthPW = form.oldAuthPW customs.check( request, @@ -119,8 +119,8 @@ module.exports = function ( function (tokens) { reply( { - keyFetchToken: tokens.keyFetchToken.data.toString('hex'), - passwordChangeToken: tokens.passwordChangeToken.data.toString('hex'), + keyFetchToken: tokens.keyFetchToken.data, + passwordChangeToken: tokens.passwordChangeToken.data, verified: tokens.keyFetchToken.emailVerified } ) @@ -150,8 +150,8 @@ module.exports = function ( handler: function (request, reply) { log.begin('Password.changeFinish', request) var passwordChangeToken = request.auth.credentials - var authPW = Buffer(request.payload.authPW, 'hex') - var wrapKb = Buffer(request.payload.wrapKb, 'hex') + var authPW = request.payload.authPW + var wrapKb = request.payload.wrapKb var sessionTokenId = request.payload.sessionToken var wantsKeys = requestHelper.wantsKeys(request) const ip = request.app.clientAddress @@ -169,8 +169,7 @@ module.exports = function ( function getSessionVerificationStatus() { if (sessionTokenId) { - var tokenId = Buffer(sessionTokenId, 'hex') - return db.sessionTokenWithVerificationStatus(tokenId) + return db.sessionTokenWithVerificationStatus(sessionTokenId) .then( function (tokenData) { verifiedStatus = tokenData.tokenVerified @@ -196,9 +195,9 @@ module.exports = function ( function changePassword() { let authSalt, password - return random(32) - .then(bytes => { - authSalt = bytes + return random.hex(32) + .then(hex => { + authSalt = hex password = new Password(authPW, authSalt, verifierVersion) return db.deletePasswordChangeToken(passwordChangeToken) }) @@ -230,7 +229,7 @@ module.exports = function ( .then( function (result) { return request.emitMetricsEvent('account.changedPassword', { - uid: passwordChangeToken.uid.toString('hex') + uid: passwordChangeToken.uid }) .then( function () { @@ -287,7 +286,7 @@ module.exports = function ( return P.resolve() .then(() => { if (! verifiedStatus) { - return random(16) + return random.hex(16) } }) .then(maybeToken => { @@ -337,14 +336,14 @@ module.exports = function ( } var response = { - uid: sessionToken.uid.toString('hex'), - sessionToken: sessionToken.data.toString('hex'), + uid: sessionToken.uid, + sessionToken: sessionToken.data, verified: sessionToken.emailVerified && sessionToken.tokenVerified, authAt: sessionToken.lastAuthAt() } if (wantsKeys) { - response.keyFetchToken = keyFetchToken.data.toString('hex') + response.keyFetchToken = keyFetchToken.data } return response @@ -467,7 +466,7 @@ module.exports = function ( function (passwordForgotToken) { reply( { - passwordForgotToken: passwordForgotToken.data.toString('hex'), + passwordForgotToken: passwordForgotToken.data, ttl: passwordForgotToken.ttl(), codeLength: passwordForgotToken.passCode.length, tries: passwordForgotToken.tries @@ -563,7 +562,7 @@ module.exports = function ( function () { reply( { - passwordForgotToken: passwordForgotToken.data.toString('hex'), + passwordForgotToken: passwordForgotToken.data, ttl: passwordForgotToken.ttl(), codeLength: passwordForgotToken.passCode.length, tries: passwordForgotToken.tries @@ -596,7 +595,7 @@ module.exports = function ( handler: function (request, reply) { log.begin('Password.forgotVerify', request) var passwordForgotToken = request.auth.credentials - var code = Buffer(request.payload.code, 'hex') + var code = request.payload.code request.validateMetricsContext() @@ -653,7 +652,7 @@ module.exports = function ( reply( { - accountResetToken: accountResetToken.data.toString('hex') + accountResetToken: accountResetToken.data } ) }, diff --git a/lib/routes/session.js b/lib/routes/session.js index 8a08d71b..a7f7ff8f 100644 --- a/lib/routes/session.js +++ b/lib/routes/session.js @@ -28,20 +28,19 @@ module.exports = function (log, db) { log.begin('Session.destroy', request) var sessionToken = request.auth.credentials var uid = request.auth.credentials.uid - var uidHex = uid.toString('hex') return P.resolve() .then(() => { if (request.payload && request.payload.customSessionToken) { - const customTokenHex = request.payload.customSessionToken + const customSessionToken = request.payload.customSessionToken - return db.sessionToken(customTokenHex) + return db.sessionToken(customSessionToken) .then(function (tokenData) { // NOTE: validate that the token belongs to the same user - if (tokenData && uidHex === tokenData.uid.toString('hex')) { + if (tokenData && uid === tokenData.uid) { sessionToken = { - id: Buffer.from(customTokenHex), - uid: Buffer.from(uidHex) + id: customSessionToken, + uid: uid, } return sessionToken @@ -83,7 +82,7 @@ module.exports = function (log, db) { const sessionToken = request.auth.credentials reply({ state: sessionToken.state, - uid: sessionToken.uid.toString('hex') + uid: sessionToken.uid }) } } diff --git a/lib/routes/sign.js b/lib/routes/sign.js index 31706d6a..01a2a737 100644 --- a/lib/routes/sign.js +++ b/lib/routes/sign.js @@ -60,7 +60,7 @@ module.exports = (log, signer, db, domain, devices) => { .then( function () { if (sessionToken.deviceId) { - deviceId = sessionToken.deviceId.toString('hex') + deviceId = sessionToken.deviceId } else if (! service || service === 'sync') { // Synthesize a device record for Sync sessions that don't already have one. // Include the UA info so that we can synthesize a device name @@ -74,7 +74,7 @@ module.exports = (log, signer, db, domain, devices) => { return devices.upsert(request, sessionToken, deviceInfo) .then( function (result) { - deviceId = result.id.toString('hex') + deviceId = result.id } ) } @@ -125,7 +125,7 @@ module.exports = (log, signer, db, domain, devices) => { }) } } - uid = sessionToken.uid.toString('hex') + uid = sessionToken.uid return signer.sign( { diff --git a/lib/routes/signin-codes.js b/lib/routes/signin-codes.js index f106c87b..b253814c 100644 --- a/lib/routes/signin-codes.js +++ b/lib/routes/signin-codes.js @@ -32,11 +32,11 @@ module.exports = (log, db, customs) => { request.validateMetricsContext() customs.checkIpOnly(request, 'consumeSigninCode') - .then(bufferizeSigninCode) + .then(hexSigninCode) .then(consumeSigninCode) .then(reply, reply) - function bufferizeSigninCode () { + function hexSigninCode () { let base64 = request.payload.code.replace(/-/g, '+').replace(/_/g, '/') const padCount = base64.length % 4 @@ -44,7 +44,7 @@ module.exports = (log, db, customs) => { base64 += '=' } - return Buffer.from(base64, 'base64') + return Buffer.from(base64, 'base64').toString('hex') } function consumeSigninCode (code) { diff --git a/lib/senders/db.js b/lib/senders/db.js index ef7c2a30..4ecd0c6a 100644 --- a/lib/senders/db.js +++ b/lib/senders/db.js @@ -2,14 +2,11 @@ * 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/. */ -var butil = require('../crypto/butil') var log = require('./log')('db') var P = require('../promise') var Pool = require('./pool') var qs = require('querystring') -var bufferize = butil.bufferize - module.exports = function () { function DB(options) { @@ -36,10 +33,9 @@ module.exports = function () { } DB.prototype.emailRecord = function (email) { - return this.pool.get('/emailRecord/' + Buffer(email, 'utf8').toString('hex')) + return this.pool.get('/emailRecord/' + Buffer.from(email, 'utf8').toString('hex')) .then( - function (body) { - var data = bufferize(body) + function (data) { data.emailVerified = !! data.emailVerified return data }, @@ -51,10 +47,9 @@ module.exports = function () { DB.prototype.account = function (uid) { log.trace({ op: 'DB.account', uid: uid }) - return this.pool.get('/account/' + uid.toString('hex')) + return this.pool.get('/account/' + uid) .then( - function (body) { - var data = bufferize(body) + function (data) { data.emailVerified = !! data.emailVerified return data }, diff --git a/lib/senders/index.js b/lib/senders/index.js index 30e95650..bfdd2fd6 100644 --- a/lib/senders/index.js +++ b/lib/senders/index.js @@ -61,8 +61,8 @@ module.exports = function (log, config, error, bounces, translator, sender) { email: primaryEmail, flowId: opts.flowId, flowBeginTime: opts.flowBeginTime, - uid: account.uid.toString('hex'), - code: opts.code.toString('hex'), + uid: account.uid, + code: opts.code, service: opts.service, redirectTo: opts.redirectTo, resume: opts.resume, @@ -84,7 +84,7 @@ module.exports = function (log, config, error, bounces, translator, sender) { .then(function (mailer) { return mailer.verifyLoginEmail({ acceptLanguage: opts.acceptLanguage || defaultLanguage, - code: opts.code.toString('hex'), + code: opts.code, ccEmails: ccEmails, email: primaryEmail, ip: opts.ip, @@ -99,7 +99,7 @@ module.exports = function (log, config, error, bounces, translator, sender) { uaBrowserVersion: opts.uaBrowserVersion, uaOS: opts.uaOS, uaOSVersion: opts.uaOSVersion, - uid: account.uid.toString('hex') + uid: account.uid }) }) }, @@ -111,7 +111,7 @@ module.exports = function (log, config, error, bounces, translator, sender) { .then(function (mailer) { return mailer.verifySecondaryEmail({ acceptLanguage: opts.acceptLanguage || defaultLanguage, - code: opts.code.toString('hex'), + code: opts.code, email: verifyEmailAddress, ip: opts.ip, location: opts.location, @@ -123,7 +123,7 @@ module.exports = function (log, config, error, bounces, translator, sender) { uaBrowserVersion: opts.uaBrowserVersion, uaOS: opts.uaOS, uaOSVersion: opts.uaOSVersion, - uid: account.uid.toString('hex'), + uid: account.uid, primaryEmail: primaryEmail }) }) @@ -139,8 +139,8 @@ module.exports = function (log, config, error, bounces, translator, sender) { email: primaryEmail, flowId: opts.flowId, flowBeginTime: opts.flowBeginTime, - token: opts.token.data.toString('hex'), - code: opts.code.toString('hex'), + token: opts.token.data, + code: opts.code, service: opts.service, redirectTo: opts.redirectTo, resume: opts.resume, @@ -253,7 +253,7 @@ module.exports = function (log, config, error, bounces, translator, sender) { uaBrowserVersion: opts.uaBrowserVersion, uaOS: opts.uaOS, uaOSVersion: opts.uaOSVersion, - uid: account.uid.toString('hex'), + uid: account.uid, unblockCode: opts.unblockCode }) }) diff --git a/lib/senders/sms.js b/lib/senders/sms.js index a53d36e4..bd1c87e8 100644 --- a/lib/senders/sms.js +++ b/lib/senders/sms.js @@ -98,7 +98,11 @@ module.exports = function (log, translator, templates, config) { }).text } - function urlSafeBase64 (buffer) { - return buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '') + function urlSafeBase64 (hex) { + return Buffer.from(hex, 'hex') + .toString('base64') + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=/g, '') } } diff --git a/lib/senders/verification-reminders.js b/lib/senders/verification-reminders.js index bb9e0268..286e53b4 100644 --- a/lib/senders/verification-reminders.js +++ b/lib/senders/verification-reminders.js @@ -30,8 +30,8 @@ module.exports = function (mailer, db, options) { // if account is not verified then send the reminder mailer.verificationReminderEmail({ email: account.email, - uid: account.uid.toString('hex'), - code: account.emailCode.toString('hex'), + uid: account.uid, + code: account.emailCode, type: reminderData.type, acceptLanguage: account.locale }) diff --git a/lib/server.js b/lib/server.js index 7f1878c2..d36289c1 100644 --- a/lib/server.js +++ b/lib/server.js @@ -77,7 +77,7 @@ function create(log, error, config, routes, db, translator) { if (! HEX_STRING.test(id)) { return process.nextTick(cb.bind(null, null, null)) // not found } - dbGetFn(Buffer(id, 'hex')) + dbGetFn(id) .then( function (token) { if (token.expired(Date.now())) { diff --git a/lib/tokens/bundle.js b/lib/tokens/bundle.js index edf63386..e76ad527 100644 --- a/lib/tokens/bundle.js +++ b/lib/tokens/bundle.js @@ -34,6 +34,8 @@ module.exports = { // Encrypt the given buffer into a hex ciphertext string. // bundle(key, keyInfo, payload) { + key = Buffer.from(key, 'hex') + payload = Buffer.from(payload, 'hex') return deriveBundleKeys(key, keyInfo, payload.length) .then( function (keys) { @@ -49,7 +51,8 @@ module.exports = { // Decrypt the given hex string into a buffer of plaintext data. // unbundle(key, keyInfo, payload) { - payload = Buffer(payload, 'hex') + key = Buffer.from(key, 'hex') + payload = Buffer.from(payload, 'hex') var ciphertext = payload.slice(0, -32) var expectedHmac = payload.slice(-32) return deriveBundleKeys(key, keyInfo, ciphertext.length) @@ -61,7 +64,7 @@ module.exports = { if (! butil.buffersAreEqual(mac, expectedHmac)) { throw error.invalidSignature() } - return butil.xorBuffers(ciphertext, keys.xorKey) + return butil.xorBuffers(ciphertext, keys.xorKey).toString('hex') } ) } diff --git a/lib/tokens/key_fetch_token.js b/lib/tokens/key_fetch_token.js index 4e62e495..ae6166fb 100644 --- a/lib/tokens/key_fetch_token.js +++ b/lib/tokens/key_fetch_token.js @@ -28,7 +28,7 @@ module.exports = function (log, Token) { return token.bundleKeys(details.kA, details.wrapKb) .then( function (keyBundle) { - token.keyBundle = Buffer(keyBundle, 'hex') //TODO see if we can skip hex + token.keyBundle = keyBundle return token } ) @@ -48,6 +48,8 @@ module.exports = function (log, Token) { KeyFetchToken.prototype.bundleKeys = function (kA, wrapKb) { log.trace({ op: 'keyFetchToken.bundleKeys', id: this.id }) + kA = Buffer.from(kA, 'hex') + wrapKb = Buffer.from(wrapKb, 'hex') return this.bundle('account/keys', Buffer.concat([kA, wrapKb])) } @@ -57,8 +59,8 @@ module.exports = function (log, Token) { .then( function (plaintext) { return { - kA: plaintext.slice(0, 32), - wrapKb: plaintext.slice(32, 64) + kA: plaintext.slice(0, 64), // strings, not buffers + wrapKb: plaintext.slice(64, 128) } } ) diff --git a/lib/tokens/password_forgot_token.js b/lib/tokens/password_forgot_token.js index 0589149b..72249f59 100644 --- a/lib/tokens/password_forgot_token.js +++ b/lib/tokens/password_forgot_token.js @@ -27,7 +27,7 @@ module.exports = (log, Token, lifetime) => { uid: details.uid, email: details.email }) - return random(16) + return random.hex(16) .then(bytes => { details.passCode = bytes details.tries = 3 diff --git a/lib/tokens/token.js b/lib/tokens/token.js index dcc5e011..bcf2f5d3 100644 --- a/lib/tokens/token.js +++ b/lib/tokens/token.js @@ -27,6 +27,8 @@ const Bundle = require('./bundle') const hkdf = require('../crypto/hkdf') const random = require('../crypto/random') +const KEYS = ['data', 'tokenId', 'authKey', 'bundleKey'] + module.exports = (log, config) => { // Token constructor. @@ -35,10 +37,9 @@ module.exports = (log, config) => { // You probably want to call a helper rather than use this directly. // function Token(keys, details) { - this.data = keys.data - this.tokenId = keys.tokenId - this.authKey = keys.authKey - this.bundleKey = keys.bundleKey + KEYS.forEach(name => { + this[name] = keys[name] && keys[name].toString('hex') + }) this.algorithm = 'sha256' this.uid = details.uid || null this.lifetime = details.lifetime || Infinity @@ -62,7 +63,7 @@ module.exports = (log, config) => { // This uses known seed data to derive the keys. // Token.createTokenFromHexData = function(TokenType, hexData, details) { - var data = Buffer(hexData, 'hex') + var data = Buffer.from(hexData, 'hex') return Token.deriveTokenKeys(TokenType, data) .then(keys => new TokenType(keys, details || {})) } @@ -115,7 +116,7 @@ module.exports = (log, config) => { Token.prototype, { id: { - get: function () { return this.tokenId.toString('hex') } + get: function () { return this.tokenId } }, key: { get: function () { return this.authKey } diff --git a/test/client/index.js b/test/client/index.js index ba2f357a..c21b6bff 100644 --- a/test/client/index.js +++ b/test/client/index.js @@ -272,7 +272,7 @@ module.exports = config => { ) .then( function () { - this.wrapKb = butil.xorBuffers(this.kB, this.unwrapBKey) + this.wrapKb = butil.xorBuffers(this.kB, this.unwrapBKey).toString('hex') return this.api.passwordChangeFinish(this.passwordChangeToken, this.authPW, this.wrapKb, headers, sessionToken) }.bind(this) ) @@ -312,7 +312,7 @@ module.exports = config => { this.keyFetchToken = null this.kA = keys.kA this.wrapKb = keys.wrapKb - this.kB = keys.kB = butil.xorBuffers(this.wrapKb, this.unwrapBKey) + this.kB = keys.kB = butil.xorBuffers(this.wrapKb, this.unwrapBKey).toString('hex') return keys }.bind(this), function (err) { diff --git a/test/local/crypto/butil.js b/test/local/crypto/butil.js index 9d504d1d..44355cf9 100644 --- a/test/local/crypto/butil.js +++ b/test/local/crypto/butil.js @@ -51,56 +51,4 @@ describe('butil', () => { }) - describe('.bufferize', () => { - it( - 'should bufferize hex-looking values', - () => { - const argument = { foo: 'bar', baz: 'f00d' } - const result = butil.bufferize(argument) - assert.notEqual(result, argument) - assert.equal(Object.keys(result).length, Object.keys(argument).length) - assert.equal(typeof result.foo, 'string') - assert.equal(result.foo, argument.foo) - assert.ok(Buffer.isBuffer(result.baz)) - assert.equal(result.baz.length, 2) - assert.equal(result.baz[0], 0xf0) - assert.equal(result.baz[1], 0x0d) - } - ) - - it( - 'should convert in-place', - () => { - const argument = { foo: 'beef', bar: 'baz' } - const result = butil.bufferize(argument, { inplace: true }) - assert.equal(result, argument) - assert.equal(Object.keys(result).length, 2) - assert.ok(Buffer.isBuffer(result.foo)) - assert.equal(result.foo.length, 2) - assert.equal(result.foo[0], 0xbe) - assert.equal(result.foo[1], 0xef) - assert.equal(typeof result.bar, 'string') - assert.equal(result.bar, 'baz') - } - ) - - it( - 'should ignore exceptions', - () => { - const argument = { foo: 'bar', baz: 'f00d', qux: 'beef' } - const result = butil.bufferize(argument, { ignore: [ 'baz' ] }) - assert.notEqual(argument, result) - assert.equal(Object.keys(result).length, Object.keys(argument).length) - assert.equal(typeof result.foo, 'string') - assert.equal(result.foo, argument.foo) - assert.equal(typeof result.baz, 'string') - assert.equal(result.baz, argument.baz) - assert.ok(Buffer.isBuffer(result.qux)) - assert.equal(result.qux.length, 2) - assert.equal(result.qux[0], 0xbe) - assert.equal(result.qux[1], 0xef) - } - ) - }) - }) diff --git a/test/local/crypto/random.js b/test/local/crypto/random.js new file mode 100644 index 00000000..1978b13d --- /dev/null +++ b/test/local/crypto/random.js @@ -0,0 +1,77 @@ +/* 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' + +const assert = require('insist') + +const random = require('../../../lib/crypto/random') + +describe('random', () => { + + it('should generate random bytes', () => { + return random(16) + .then(bytes => { + assert(Buffer.isBuffer(bytes)) + assert.equal(bytes.length, 16) + + return random(32) + }) + .then(bytes => { + assert(Buffer.isBuffer(bytes)) + assert.equal(bytes.length, 32) + }) + }) + + it('should generate several random bytes buffers', () => { + return random(16, 8) + .then(bufs => { + assert.equal(bufs.length, 2) + + const a = bufs[0] + const b = bufs[1] + + assert(Buffer.isBuffer(a)) + assert.equal(a.length, 16) + + assert(Buffer.isBuffer(b)) + assert.equal(b.length, 8) + }) + }) + + describe('hex', () => { + it('should generate a random hex string', () => { + return random.hex(16) + .then(str => { + assert.equal(typeof str, 'string') + assert(/^[0-9a-f]+$/g.test(str)) + assert.equal(str.length, 32) + + return random.hex(32) + }) + .then(str => { + assert.equal(typeof str, 'string') + assert.equal(str.length, 64) + }) + }) + + it('should generate several random hex strings', () => { + return random.hex(16, 8) + .then(strs => { + assert.equal(strs.length, 2) + + const a = strs[0] + const b = strs[1] + + assert.equal(typeof a, 'string') + assert(/^[0-9a-f]+$/g.test(a)) + assert.equal(a.length, 32) + + assert.equal(typeof b, 'string') + assert(/^[0-9a-f]+$/g.test(b)) + assert.equal(b.length, 16) + }) + }) + }) +}) diff --git a/test/local/devices.js b/test/local/devices.js index ec155089..3d32d75e 100644 --- a/test/local/devices.js +++ b/test/local/devices.js @@ -24,7 +24,7 @@ describe('devices', () => { beforeEach(() => { log = mocks.spyLog() deviceCreatedAt = Date.now() - deviceId = crypto.randomBytes(16) + deviceId = crypto.randomBytes(16).toString('hex') device = { name: 'foo', type: 'bar' @@ -60,7 +60,7 @@ describe('devices', () => { log: log }) sessionToken = { - tokenId: crypto.randomBytes(16), + tokenId: crypto.randomBytes(16).toString('hex'), uid: uuid.v4('binary'), tokenVerified: true } @@ -92,8 +92,8 @@ describe('devices', () => { event: 'device.created', service: undefined, userAgent: 'test user-agent', - uid: sessionToken.uid.toString('hex'), - device_id: deviceId.toString('hex'), + uid: sessionToken.uid, + device_id: deviceId, is_placeholder: false }, 'event data was correct') @@ -117,7 +117,7 @@ describe('devices', () => { assert.equal(args.length, 3, 'push.notifyDeviceConnected was passed three arguments') assert.equal(args[0], sessionToken.uid, 'first argument was uid') assert.equal(args[1], device.name, 'second arguent was device name') - assert.equal(args[2], deviceId.toString('hex'), 'third argument was device id') + assert.equal(args[2], deviceId, 'third argument was device id') }) }) @@ -189,8 +189,8 @@ describe('devices', () => { event: 'device.updated', service: undefined, userAgent: 'test user-agent', - uid: sessionToken.uid.toString('hex'), - device_id: deviceId.toString('hex'), + uid: sessionToken.uid, + device_id: deviceId, is_placeholder: false }, 'event data was correct') diff --git a/test/local/features.js b/test/local/features.js index b45999f8..63d28df1 100644 --- a/test/local/features.js +++ b/test/local/features.js @@ -71,7 +71,7 @@ describe('features', () => { it( 'isSampledUser', () => { - let uid = Buffer.alloc(32, 0xff) + let uid = Array(64).fill('f').join('') let sampleRate = 1 hashResult = Array(40).fill('f').join('') diff --git a/test/local/log.js b/test/local/log.js index f50ff73f..bc59ec98 100644 --- a/test/local/log.js +++ b/test/local/log.js @@ -21,7 +21,7 @@ var mocks = { }) } mocks.mozlog.config = sinon.spy() -const log = proxyquire('../../lib/log', mocks)('foo', 'bar') +const log = proxyquire('../../lib/log', mocks)('foo', 'test') const emitRouteFlowEvent = sinon.spy() @@ -33,7 +33,7 @@ describe('log', () => { var args = mocks.mozlog.config.args[0] assert.equal(args.length, 1, 'mozlog.config was passed one argument') assert.equal(Object.keys(args[0]).length, 4, 'number of mozlog.config arguments was correct') - assert.equal(args[0].app, 'bar', 'app property was correct') + assert.equal(args[0].app, 'test', 'app property was correct') assert.equal(args[0].level, 'foo', 'level property was correct') assert.equal(args[0].stream, process.stderr, 'stream property was correct') diff --git a/test/local/metrics/context.js b/test/local/metrics/context.js index 7089208d..08ab5f8d 100644 --- a/test/local/metrics/context.js +++ b/test/local/metrics/context.js @@ -78,7 +78,7 @@ describe('metricsContext', () => { () => { results.set = P.resolve('wibble') const token = { - uid: Buffer.alloc(32, 'cd'), + uid: Array(64).fill('c').join(''), id: 'foo' } return metricsContext.stash.call({ @@ -107,7 +107,7 @@ describe('metricsContext', () => { metricsContext: 'bar' } }, { - uid: Buffer.alloc(32, 'cd'), + uid: Array(64).fill('c').join(''), id: 'foo' }).then(result => { assert.equal(result, undefined, 'result is undefined') @@ -157,7 +157,7 @@ describe('metricsContext', () => { return metricsContext.stash.call({ payload: {} }, { - uid: Buffer.alloc(32, 'cd'), + uid: Array(64).fill('c').join(''), id: 'foo' }).then(result => { assert.equal(result, undefined, 'result is undefined') @@ -235,7 +235,7 @@ describe('metricsContext', () => { () => { const time = Date.now() - 1 const token = { - uid: Buffer.alloc(32, '77'), + uid: Array(64).fill('7').join(''), id: 'wibble' } results.get = P.resolve({ @@ -270,7 +270,7 @@ describe('metricsContext', () => { 'metricsContext.gather with fake token', () => { const time = Date.now() - 1 - const uid = Buffer.alloc(32, '77') + const uid = Array(64).fill('7').join('') const id = 'wibble' results.get = P.resolve({ flowId: 'flowId', @@ -278,7 +278,7 @@ describe('metricsContext', () => { }) return metricsContext.gather.call({ payload: { - uid: uid.toString('hex'), + uid: uid, code: id } }, {}).then(function (result) { @@ -306,7 +306,7 @@ describe('metricsContext', () => { return metricsContext.gather.call({ auth: { credentials: { - uid: Buffer.alloc(32, 'cd') + uid: Array(64).fill('c').join('') } } }, {}).then(function (result) { @@ -355,7 +355,7 @@ describe('metricsContext', () => { return metricsContext.gather.call({ auth: { credentials: { - uid: Buffer.alloc(8, 'ff'), + uid: Array(16).fill('f').join(''), id: 'bar' } }, @@ -383,7 +383,7 @@ describe('metricsContext', () => { return metricsContext.gather.call({ auth: { credentials: { - uid: Buffer.alloc(8, 'ff'), + uid: Array(16).fill('f').join(''), id: 'bar' } } @@ -402,7 +402,7 @@ describe('metricsContext', () => { 'metricsContext.clear with token', () => { const token = { - uid: Buffer.alloc(32, '77'), + uid: Array(64).fill('7').join(''), id: 'wibble' } return metricsContext.clear.call({ @@ -420,11 +420,11 @@ describe('metricsContext', () => { it( 'metricsContext.clear with fake token', () => { - const uid = Buffer.alloc(32, '66') + const uid = Array(64).fill('6').join('') const id = 'blee' return metricsContext.clear.call({ payload: { - uid: uid.toString('hex'), + uid: uid, code: id } }).then(() => { @@ -449,7 +449,7 @@ describe('metricsContext', () => { 'metricsContext.clear with memcached error', () => { const token = { - uid: Buffer.alloc(32, '77'), + uid: Array(64).fill('7').join(''), id: 'wibble' } results.del = P.reject(new Error('blee')) diff --git a/test/local/metrics/events.js b/test/local/metrics/events.js index a5674e1e..64a0b939 100644 --- a/test/local/metrics/events.js +++ b/test/local/metrics/events.js @@ -144,7 +144,7 @@ describe('metrics/events', () => { const metricsContext = mocks.mockMetricsContext() const request = mocks.mockRequest({ credentials: { - uid: Buffer.from('deadbeef', 'hex') + uid: 'deadbeef' }, metricsContext, payload: { @@ -289,7 +289,7 @@ describe('metrics/events', () => { } } }) - return events.emit.call(request, 'account.reminder', { uid: Buffer.from('deadbeef', 'hex') }) + return events.emit.call(request, 'account.reminder', { uid: 'deadbeef' }) .then(() => { assert.equal(metricsContext.gather.callCount, 1, 'metricsContext.gather was called once') diff --git a/test/local/push.js b/test/local/push.js index 9ad738aa..9ddeea28 100644 --- a/test/local/push.js +++ b/test/local/push.js @@ -16,7 +16,7 @@ var path = require('path') const P = require(`${ROOT_DIR}/lib/promise`) const mocks = require('../mocks') const mockLog = mocks.mockLog -var mockUid = Buffer.from('foo') +var mockUid = 'deadbeef' var mockConfig = {} const PUSH_PAYLOADS_SCHEMA_PATH = `${ROOT_DIR}/docs/pushpayloads.schema.json` @@ -746,7 +746,7 @@ describe('push', () => { version: 1, command: 'fxaccounts:account_destroyed', data: { - uid: mockUid.toString('hex') + uid: mockUid } } return push.notifyAccountDestroyed(mockUid, mockDevices).catch(function (err) { diff --git a/test/local/routes/account.js b/test/local/routes/account.js index aae949b4..10c5ea96 100644 --- a/test/local/routes/account.js +++ b/test/local/routes/account.js @@ -19,6 +19,10 @@ var log = require('../../../lib/log') var TEST_EMAIL = 'foo@gmail.com' +function hexString(bytes) { + return crypto.randomBytes(bytes).toString('hex') +} + var makeRoutes = function (options, requireMocks) { options = options || {} @@ -90,7 +94,7 @@ describe('/account/reset', function () { log: mockLog, metricsContext: mockMetricsContext, payload: { - authPW: crypto.randomBytes(32).toString('hex'), + authPW: hexString(32), sessionToken: true, metricsContext: { flowBeginTime: Date.now(), @@ -101,14 +105,14 @@ describe('/account/reset', function () { keys: 'true' } }) - const keyFetchTokenId = crypto.randomBytes(16) - const sessionTokenId = crypto.randomBytes(16) + const keyFetchTokenId = hexString(16) + const sessionTokenId = hexString(16) const mockDB = mocks.mockDB({ uid: uid, email: TEST_EMAIL, keyFetchTokenId: keyFetchTokenId, sessionTokenId: sessionTokenId, - wrapWrapKb: crypto.randomBytes(32) + wrapWrapKb: hexString(32) }) var mockCustoms = mocks.mockCustoms() var mockPush = mocks.mockPush() @@ -142,7 +146,7 @@ describe('/account/reset', function () { event: 'account.reset', service: undefined, userAgent: 'test user-agent', - uid: uid.toString('hex') + uid: uid }, 'event data was correct') assert.equal(mockDB.securityEvent.callCount, 1, 'db.securityEvent was called') @@ -195,7 +199,7 @@ describe('/account/create', () => { metricsContext: mockMetricsContext, payload: { email: TEST_EMAIL, - authPW: crypto.randomBytes(32).toString('hex'), + authPW: hexString(32), service: 'sync', metricsContext: { flowBeginTime: Date.now(), @@ -207,9 +211,9 @@ describe('/account/create', () => { } }) var clientAddress = mockRequest.app.clientAddress - var emailCode = crypto.randomBytes(16) - var keyFetchTokenId = crypto.randomBytes(16) - var sessionTokenId = crypto.randomBytes(16) + var emailCode = hexString(16) + var keyFetchTokenId = hexString(16) + var sessionTokenId = hexString(16) var uid = uuid.v4('binary') var mockDB = mocks.mockDB({ email: TEST_EMAIL, @@ -277,7 +281,7 @@ describe('/account/create', () => { event: 'account.created', service: 'sync', userAgent: 'test user-agent', - uid: uid.toString('hex') + uid: uid }, 'event data was correct') assert.equal(mockLog.flowEvent.callCount, 1, 'log.flowEvent was called once') @@ -290,7 +294,7 @@ describe('/account/create', () => { flow_id: 'F1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF1031DF103', locale: 'en-GB', time: now, - uid: uid.toString('hex'), + uid: uid, userAgent: 'test user-agent' }, 'flow event data was correct') @@ -307,7 +311,7 @@ describe('/account/create', () => { args = mockMetricsContext.stash.args[1] assert.equal(args.length, 1, 'metricsContext.stash was passed one argument second time') - assert.equal(args[0].id, emailCode.toString('hex'), 'argument was synthesized token') + assert.equal(args[0].id, emailCode, 'argument was synthesized token') assert.deepEqual(args[0].uid, uid, 'token.uid was correct') assert.equal(mockMetricsContext.stash.thisValues[1], mockRequest, 'this was request') @@ -369,7 +373,7 @@ describe('/account/login', function () { log: mockLog, metricsContext: mockMetricsContext, payload: { - authPW: crypto.randomBytes(32).toString('hex'), + authPW: hexString(32), email: TEST_EMAIL, service: 'sync', reason: 'signin', @@ -386,7 +390,7 @@ describe('/account/login', function () { log: mockLog, metricsContext: mockMetricsContext, payload: { - authPW: crypto.randomBytes(32).toString('hex'), + authPW: hexString(32), email: 'test@mozilla.com', service: 'dcdb5ae7add825d2', reason: 'signin', @@ -402,7 +406,7 @@ describe('/account/login', function () { log: mockLog, query: {}, payload: { - authPW: crypto.randomBytes(32).toString('hex'), + authPW: hexString(32), email: TEST_EMAIL, unblockCode: 'ABCD1234', service: 'dcdb5ae7add825d2', @@ -414,8 +418,8 @@ describe('/account/login', function () { } } }) - var keyFetchTokenId = crypto.randomBytes(16) - var sessionTokenId = crypto.randomBytes(16) + var keyFetchTokenId = hexString(16) + var sessionTokenId = hexString(16) var uid = uuid.v4('binary') var mockDB = mocks.mockDB({ email: TEST_EMAIL, @@ -495,7 +499,7 @@ describe('/account/login', function () { event: 'account.login', service: 'sync', userAgent: 'test user-agent', - uid: uid.toString('hex') + uid: uid }, 'event data was correct') assert.equal(mockLog.flowEvent.callCount, 2, 'log.flowEvent was called twice') @@ -508,7 +512,7 @@ describe('/account/login', function () { flowCompleteSignal: 'account.signed', locale: 'en-US', time: now, - uid: uid.toString('hex'), + uid: uid, userAgent: 'test user-agent' }, 'first flow event was correct') args = mockLog.flowEvent.args[1] @@ -571,20 +575,20 @@ describe('/account/login', function () { describe('sign-in unverified account', function () { it('sends email code', function () { - var emailCode = crypto.randomBytes(16) + var emailCode = hexString(16) mockDB.emailRecord = function () { return P.resolve({ - authSalt: crypto.randomBytes(32), - data: crypto.randomBytes(32), + authSalt: hexString(32), + data: hexString(32), email: TEST_EMAIL, emailVerified: false, emailCode: emailCode, - kA: crypto.randomBytes(32), + kA: hexString(32), lastAuthAt: function () { return Date.now() }, uid: uid, - wrapWrapKb: crypto.randomBytes(32) + wrapWrapKb: hexString(32) }) } @@ -612,16 +616,16 @@ describe('/account/login', function () { mockDB.emailRecord = function () { return P.resolve({ - authSalt: crypto.randomBytes(32), - data: crypto.randomBytes(32), + authSalt: hexString(32), + data: hexString(32), email: TEST_EMAIL, emailVerified: true, - kA: crypto.randomBytes(32), + kA: hexString(32), lastAuthAt: function () { return Date.now() }, uid: uid, - wrapWrapKb: crypto.randomBytes(32) + wrapWrapKb: hexString(32) }) } }) @@ -648,16 +652,16 @@ describe('/account/login', function () { it('does not require verification when keys are not requested', function () { mockDB.emailRecord = function () { return P.resolve({ - authSalt: crypto.randomBytes(32), - data: crypto.randomBytes(32), + authSalt: hexString(32), + data: hexString(32), email: 'test@mozilla.com', emailVerified: true, - kA: crypto.randomBytes(32), + kA: hexString(32), lastAuthAt: function () { return Date.now() }, uid: uid, - wrapWrapKb: crypto.randomBytes(32) + wrapWrapKb: hexString(32) }) } @@ -684,16 +688,16 @@ describe('/account/login', function () { mockRequest.payload.email = 'test@mozilla.com' mockDB.emailRecord = function () { return P.resolve({ - authSalt: crypto.randomBytes(32), - data: crypto.randomBytes(32), + authSalt: hexString(32), + data: hexString(32), email: mockRequest.payload.email, emailVerified: false, - kA: crypto.randomBytes(32), + kA: hexString(32), lastAuthAt: function () { return Date.now() }, uid: uid, - wrapWrapKb: crypto.randomBytes(32) + wrapWrapKb: hexString(32) }) } @@ -720,17 +724,17 @@ describe('/account/login', function () { mockDB.emailRecord = function () { return P.resolve({ - authSalt: crypto.randomBytes(32), + authSalt: hexString(32), createdAt: Date.now() - accountCreatedSince, - data: crypto.randomBytes(32), + data: hexString(32), email: mockRequest.payload.email, emailVerified: true, - kA: crypto.randomBytes(32), + kA: hexString(32), lastAuthAt: function () { return Date.now() }, uid: uid, - wrapWrapKb: crypto.randomBytes(32) + wrapWrapKb: hexString(32) }) } @@ -869,7 +873,7 @@ describe('/account/login', function () { assert.equal(!! record, true, 'log.info was called for Account.history') assert.equal(record.op, 'Account.history.verified') - assert.equal(record.uid, uid.toString('hex')) + assert.equal(record.uid, uid) assert.equal(record.events, 1) assert.equal(record.recency, 'day') }) @@ -895,7 +899,7 @@ describe('/account/login', function () { assert.equal(!! record, true, 'log.info was called for Account.history') assert.equal(record.op, 'Account.history.unverified') - assert.equal(record.uid, uid.toString('hex')) + assert.equal(record.uid, uid) assert.equal(record.events, 1) }) }) @@ -1068,14 +1072,14 @@ describe('/account/login', function () { }) describe('/account/keys', function () { - var keyFetchTokenId = crypto.randomBytes(16) + var keyFetchTokenId = hexString(16) var uid = uuid.v4('binary') const mockLog = mocks.spyLog() const mockRequest = mocks.mockRequest({ credentials: { emailVerified: true, - id: keyFetchTokenId.toString('hex'), - keyBundle: crypto.randomBytes(16), + id: keyFetchTokenId, + keyBundle: hexString(16), tokenId: keyFetchTokenId, tokenVerificationId: undefined, tokenVerified: true, @@ -1092,7 +1096,7 @@ describe('/account/keys', function () { it('verified token', function () { return runTest(route, mockRequest, function (response) { - assert.deepEqual(response, {bundle: mockRequest.auth.credentials.keyBundle.toString('hex')}, 'response was correct') + assert.deepEqual(response, {bundle: mockRequest.auth.credentials.keyBundle}, 'response was correct') assert.equal(mockDB.deleteKeyFetchToken.callCount, 1, 'db.deleteKeyFetchToken was called once') var args = mockDB.deleteKeyFetchToken.args[0] @@ -1106,7 +1110,7 @@ describe('/account/keys', function () { event: 'account.keyfetch', service: undefined, userAgent: 'test user-agent', - uid: uid.toString('hex') + uid: uid }, 'event data was correct') }) .then(function () { @@ -1116,7 +1120,7 @@ describe('/account/keys', function () { }) it('unverified token', function () { - mockRequest.auth.credentials.tokenVerificationId = crypto.randomBytes(16) + mockRequest.auth.credentials.tokenVerificationId = hexString(16) mockRequest.auth.credentials.tokenVerified = false return runTest(route, mockRequest).then(() => assert.ok(false), response => { assert.equal(response.errno, 104, 'correct errno for unverified account') @@ -1189,7 +1193,7 @@ describe('/account/destroy', function () { event: 'account.deleted', service: undefined, userAgent: 'test user-agent', - uid: uid.toString('hex') + uid: uid }, 'event data was correct') }) }) @@ -1226,8 +1230,8 @@ describe('/account/sessions', function () { var mockRequest = mocks.mockRequest({ credentials: { - uid: crypto.randomBytes(16), - tokenId: crypto.randomBytes(16) + uid: hexString(16), + tokenId: hexString(16) }, payload: {} }) diff --git a/test/local/routes/account_devices.js b/test/local/routes/account_devices.js index 7e0f6341..844d7ae6 100644 --- a/test/local/routes/account_devices.js +++ b/test/local/routes/account_devices.js @@ -78,8 +78,8 @@ function runTest (route, request, assertions) { describe('/account/device', function () { var config = {} - var uid = uuid.v4('binary') - var deviceId = crypto.randomBytes(16) + var uid = uuid.v4('binary').toString('hex') + var deviceId = crypto.randomBytes(16).toString('hex') var mockRequest = mocks.mockRequest({ credentials: { deviceCallbackPublicKey: '', @@ -87,7 +87,7 @@ describe('/account/device', function () { deviceId: deviceId, deviceName: 'my awesome device', deviceType: 'desktop', - tokenId: crypto.randomBytes(16), + tokenId: crypto.randomBytes(16).toString('hex'), uid: uid }, payload: { @@ -115,7 +115,7 @@ describe('/account/device', function () { }) it('different data', function () { - mockRequest.auth.credentials.deviceId = crypto.randomBytes(16) + mockRequest.auth.credentials.deviceId = crypto.randomBytes(16).toString('hex') var payload = mockRequest.payload payload.name = 'my even awesomer device' payload.type = 'phone' @@ -164,8 +164,8 @@ describe('/account/device', function () { describe('/account/devices/notify', function () { var config = {} - var uid = uuid.v4('binary') - var deviceId = crypto.randomBytes(16) + var uid = uuid.v4('binary').toString('hex') + var deviceId = crypto.randomBytes(16).toString('hex') var mockLog = mocks.spyLog() var mockRequest = mocks.mockRequest({ log: mockLog, @@ -396,7 +396,7 @@ describe('/account/devices/notify', function () { describe('/account/device/destroy', function () { it('should work', () => { - var uid = uuid.v4('binary') + var uid = uuid.v4('binary').toString('hex') var deviceId = crypto.randomBytes(16).toString('hex') var mockLog = mocks.spyLog() var mockDB = mocks.mockDB() @@ -452,17 +452,17 @@ describe('/account/devices', function () { it('should return the devices list', () => { var mockRequest = mocks.mockRequest({ credentials: { - uid: crypto.randomBytes(16), - tokenId: crypto.randomBytes(16) + uid: crypto.randomBytes(16).toString('hex'), + tokenId: crypto.randomBytes(16).toString('hex') }, payload: {} }) - var unnamedDevice = { sessionToken: crypto.randomBytes(16) } + var unnamedDevice = { sessionToken: crypto.randomBytes(16).toString('hex') } var mockDB = mocks.mockDB({ devices: [ { name: 'current session', type: 'mobile', sessionToken: mockRequest.auth.credentials.tokenId }, - { name: 'has no type', sessionToken: crypto.randomBytes(16) }, - { name: 'has device type', sessionToken: crypto.randomBytes(16), uaDeviceType: 'wibble' }, + { name: 'has no type', sessionToken: crypto.randomBytes(16).toString('hex') }, + { name: 'has device type', sessionToken: crypto.randomBytes(16).toString('hex'), uaDeviceType: 'wibble' }, unnamedDevice ] }) diff --git a/test/local/routes/password.js b/test/local/routes/password.js index 5a3e99a2..b8db67d2 100644 --- a/test/local/routes/password.js +++ b/test/local/routes/password.js @@ -61,11 +61,11 @@ describe('/password', () => { '/forgot/send_code', () => { var mockCustoms = mocks.mockCustoms() - var uid = uuid.v4('binary') + var uid = uuid.v4('binary').toString('hex') var mockDB = mocks.mockDB({ email: TEST_EMAIL, passCode: 'foo', - passwordForgotTokenId: crypto.randomBytes(16), + passwordForgotTokenId: crypto.randomBytes(16).toString('hex'), uid: uid }) var mockMailer = mocks.mockMailer() @@ -130,7 +130,7 @@ describe('/password', () => { '/forgot/resend_code', () => { var mockCustoms = mocks.mockCustoms() - var uid = uuid.v4('binary') + var uid = uuid.v4('binary').toString('hex') var mockDB = mocks.mockDB() var mockMailer = mocks.mockMailer() var mockMetricsContext = mocks.mockMetricsContext() @@ -157,7 +157,7 @@ describe('/password', () => { var mockRequest = mocks.mockRequest({ credentials: { - data: crypto.randomBytes(16), + data: crypto.randomBytes(16).toString('hex'), email: TEST_EMAIL, passCode: Buffer('abcdef', 'hex'), ttl: function () { return 17 }, @@ -190,15 +190,15 @@ describe('/password', () => { '/forgot/verify_code', () => { var mockCustoms = mocks.mockCustoms() - var uid = uuid.v4('binary') + var uid = uuid.v4('binary').toString('hex') var accountResetToken = { - data: crypto.randomBytes(16) + data: crypto.randomBytes(16).toString('hex') } var mockDB = mocks.mockDB({ accountResetToken: accountResetToken, email: TEST_EMAIL, passCode: 'abcdef', - passwordForgotTokenId: crypto.randomBytes(16), + passwordForgotTokenId: crypto.randomBytes(16).toString('hex'), uid: uid }) var mockMailer = mocks.mockMailer() @@ -264,7 +264,7 @@ describe('/password', () => { it( 'smoke', () => { - var uid = uuid.v4('binary') + var uid = uuid.v4('binary').toString('hex') var mockDB = mocks.mockDB({ email: TEST_EMAIL, uid: uid @@ -324,7 +324,7 @@ describe('/password', () => { it( 'succeeds even if notification blocked', () => { - var uid = uuid.v4('binary') + var uid = uuid.v4('binary').toString('hex') var mockDB = mocks.mockDB({ email: TEST_EMAIL, uid: uid diff --git a/test/local/routes/sign.js b/test/local/routes/sign.js index 8617dd9b..0d19a942 100644 --- a/test/local/routes/sign.js +++ b/test/local/routes/sign.js @@ -12,7 +12,7 @@ var mocks = require('../../mocks') var P = require('../../../lib/promise') describe('/certificate/sign', () => { - var deviceId = crypto.randomBytes(16) + var deviceId = crypto.randomBytes(16).toString('hex') var mockDevices = mocks.mockDevices({ deviceId: deviceId }) @@ -24,12 +24,12 @@ describe('/certificate/sign', () => { return Date.now() }, locale: 'en', - tokenId: crypto.randomBytes(16), + tokenId: crypto.randomBytes(16).toString('hex'), uaBrowser: 'Firefox', uaBrowserVersion: '55', uaOS: 'Windows', uaOSVersion: '10', - uid: uuid.v4('binary') + uid: uuid.v4('binary').toString('hex') }, log: mockLog, payload: { @@ -112,7 +112,7 @@ describe('/certificate/sign', () => { it('with deviceId', () => { mockRequest.query.service = 'sync' - mockRequest.auth.credentials.deviceId = crypto.randomBytes(16) + mockRequest.auth.credentials.deviceId = crypto.randomBytes(16).toString('hex') return runTest({ devices: mockDevices, diff --git a/test/local/routes/signin-codes.js b/test/local/routes/signin-codes.js index 8af97914..d6d6115d 100644 --- a/test/local/routes/signin-codes.js +++ b/test/local/routes/signin-codes.js @@ -45,8 +45,7 @@ describe('/signinCodes/consume:', () => { assert.equal(db.consumeSigninCode.callCount, 1) const args = db.consumeSigninCode.args[0] assert.equal(args.length, 1) - assert.ok(Buffer.isBuffer(args[0])) - assert.equal(args[0].toString('base64'), '++//ff0=') + assert.equal(args[0], 'fbefff7dfd') }) it('called log.flowEvent correctly', () => { diff --git a/test/local/senders/reminder.js b/test/local/senders/reminder.js index f4e38380..d8543ca3 100644 --- a/test/local/senders/reminder.js +++ b/test/local/senders/reminder.js @@ -14,8 +14,8 @@ var TEST_EMAIL = 'test@restmail.net' var TEST_ACCOUNT_RECORD = { emailVerified: false, email: TEST_EMAIL, - emailCode: Buffer.from('foo'), - uid: Buffer.from('bar'), + emailCode: 'deadbeaf', + uid: 'c0ffee', locale: 'da, en-gb;q=0.8, en;q=0.7' } var REMINDER_TYPE = 'first' @@ -51,12 +51,12 @@ it('_processReminder sends first reminder for unverified emails', function () { var mailer = new Mailer({}, {}, config.get('smtp')) sandbox.stub(mailer, 'send', function (vals) { assert.equal(vals.acceptLanguage, TEST_ACCOUNT_RECORD.locale, 'correct locale') - assert.equal(vals.uid, TEST_ACCOUNT_RECORD.uid.toString('hex'), 'correct uid') + assert.equal(vals.uid, TEST_ACCOUNT_RECORD.uid, 'correct uid') assert.equal(vals.email, TEST_ACCOUNT_RECORD.email, 'correct email') assert.equal(vals.template, 'verificationReminderFirstEmail', 'correct template') assert.equal(vals.subject, 'Hello again.', 'correct subject') - assert.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code') - assert.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link') + assert.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode, 'correct code') + assert.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode) >= 0, 'correct link') done() }) @@ -71,8 +71,8 @@ it('_processReminder sends second reminder for unverified emails', function () { var mailer = new Mailer({}, {}, config.get('smtp')) sandbox.stub(mailer, 'send', function (vals) { assert.equal(vals.template, 'verificationReminderSecondEmail', 'correct template') - assert.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode.toString('hex'), 'correct code') - assert.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode.toString('hex')) >= 0, 'correct link') + assert.equal(vals.headers['X-Verify-Code'], TEST_ACCOUNT_RECORD.emailCode, 'correct code') + assert.ok(vals.templateValues.link.indexOf(TEST_ACCOUNT_RECORD.emailCode) >= 0, 'correct link') done() }) diff --git a/test/local/tokens/key_fetch_token.js b/test/local/tokens/key_fetch_token.js index 4674fde8..f139d142 100644 --- a/test/local/tokens/key_fetch_token.js +++ b/test/local/tokens/key_fetch_token.js @@ -13,8 +13,8 @@ const KeyFetchToken = tokens.KeyFetchToken const ACCOUNT = { uid: 'xxx', - kA: Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), - wrapKb: Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex'), + kA: Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex').toString('hex'), + wrapKb: Buffer.from('0000000000000000000000000000000000000000000000000000000000000000', 'hex').toString('hex'), emailVerified: true } @@ -76,8 +76,8 @@ describe('KeyFetchToken', () => { 'should bundle / unbundle of keys', () => { let token = null - const kA = crypto.randomBytes(32) - const wrapKb = crypto.randomBytes(32) + const kA = crypto.randomBytes(32).toString('hex') + const wrapKb = crypto.randomBytes(32).toString('hex') return KeyFetchToken.create(ACCOUNT) .then( function (x) { @@ -105,8 +105,8 @@ describe('KeyFetchToken', () => { () => { let token1 = null let token2 = null - const kA = crypto.randomBytes(32) - const wrapKb = crypto.randomBytes(32) + const kA = crypto.randomBytes(32).toString('hex') + const wrapKb = crypto.randomBytes(32).toString('hex') return KeyFetchToken.create(ACCOUNT) .then( function (x) { @@ -146,10 +146,10 @@ describe('KeyFetchToken', () => { .then( function (x) { token = x - assert.equal(token.data.toString('hex'), tokenData) - assert.equal(token.id.toString('hex'), '3d0a7c02a15a62a2882f76e39b6494b500c022a8816e048625a495718998ba60') - assert.equal(token.authKey.toString('hex'), '87b8937f61d38d0e29cd2d5600b3f4da0aa48ac41de36a0efe84bb4a9872ceb7') - assert.equal(token.bundleKey.toString('hex'), '14f338a9e8c6324d9e102d4e6ee83b209796d5c74bb734a410e729e014a4a546') + assert.equal(token.data, tokenData) + assert.equal(token.id, '3d0a7c02a15a62a2882f76e39b6494b500c022a8816e048625a495718998ba60') + assert.equal(token.authKey, '87b8937f61d38d0e29cd2d5600b3f4da0aa48ac41de36a0efe84bb4a9872ceb7') + assert.equal(token.bundleKey, '14f338a9e8c6324d9e102d4e6ee83b209796d5c74bb734a410e729e014a4a546') } ) .then( diff --git a/test/mailer_helper.js b/test/mailer_helper.js index 8c955e9a..92088a54 100644 --- a/test/mailer_helper.js +++ b/test/mailer_helper.js @@ -6,12 +6,12 @@ var uuid = require('uuid') -var zeroBuffer16 = Buffer('00000000000000000000000000000000', 'hex') -var zeroBuffer32 = Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') +var zeroBuffer16 = Buffer('00000000000000000000000000000000', 'hex').toString('hex') +var zeroBuffer32 = Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex').toString('hex') function createTestAccount() { var account = { - uid: uuid.v4('binary'), + uid: uuid.v4('binary').toString('hex'), email: 'foo' + Math.random() + '@bar.com', emailCode: zeroBuffer16, emailVerified: false, diff --git a/test/mocks.js b/test/mocks.js index 30258469..0f88c244 100644 --- a/test/mocks.js +++ b/test/mocks.js @@ -208,14 +208,14 @@ function mockDB (data, errors) { }), createKeyFetchToken: sinon.spy(() => { return P.resolve({ - data: crypto.randomBytes(32), + data: crypto.randomBytes(32).toString('hex'), tokenId: data.keyFetchTokenId, uid: data.uid }) }), createPasswordForgotToken: sinon.spy(() => { return P.resolve({ - data: crypto.randomBytes(32), + data: crypto.randomBytes(32).toString('hex'), passCode: data.passCode, tokenId: data.passwordForgotTokenId, uid: data.uid, @@ -226,7 +226,7 @@ function mockDB (data, errors) { }), createSessionToken: sinon.spy(() => { return P.resolve({ - data: crypto.randomBytes(32), + data: crypto.randomBytes(32).toString('hex'), email: data.email, emailVerified: data.emailVerified, lastAuthAt: () => { @@ -257,17 +257,17 @@ function mockDB (data, errors) { return P.reject(errors.emailRecord) } return P.resolve({ - authSalt: crypto.randomBytes(32), + authSalt: crypto.randomBytes(32).toString('hex'), createdAt: data.createdAt || Date.now(), - data: crypto.randomBytes(32), + data: crypto.randomBytes(32).toString('hex'), email: data.email, emailVerified: data.emailVerified, - kA: crypto.randomBytes(32), + kA: crypto.randomBytes(32).toString('hex'), lastAuthAt: () => { return Date.now() }, uid: data.uid, - wrapWrapKb: crypto.randomBytes(32) + wrapWrapKb: crypto.randomBytes(32).toString('hex') }) }), forgotPasswordVerified: sinon.spy(() => { @@ -313,12 +313,7 @@ function mockPush (methods) { // So far every push method has a uid for first argument, let's keep it simple. PUSH_METHOD_NAMES.forEach((name) => { if (! push[name]) { - push[name] = sinon.spy(uid => { - if (! (uid instanceof Uint8Array)) { - throw new Error('The first param –uid– of ' + name + ' must be a Buffer!') - } - return P.resolve() - }) + push[name] = sinon.spy(() => P.resolve()) } }) return push @@ -330,7 +325,7 @@ function mockDevices (data) { return { upsert: sinon.spy(() => { return P.resolve({ - id: data.deviceId || crypto.randomBytes(16), + id: data.deviceId || crypto.randomBytes(16).toString('hex'), name: data.deviceName || 'mock device name', type: data.deviceType || 'desktop' }) diff --git a/test/remote/account_reset_tests.js b/test/remote/account_reset_tests.js index 0e933764..90307375 100644 --- a/test/remote/account_reset_tests.js +++ b/test/remote/account_reset_tests.js @@ -93,10 +93,10 @@ describe('remote account reset', function() { ) .then( function (keys) { - assert.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb') - assert.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset') - assert.deepEqual(kA, keys.kA, 'kA was not reset') - assert.equal(client.kB.length, 32, 'kB exists, has the right length') + assert.notEqual(wrapKb, keys.wrapKb, 'wrapKb was reset') + assert.equal(kA, keys.kA, 'kA was not reset') + assert.equal(typeof client.kB, 'string') + assert.equal(client.kB.length, 64, 'kB exists, has the right length') } ) } @@ -174,10 +174,10 @@ describe('remote account reset', function() { ) .then( function (keys) { - assert.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb') - assert.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset') - assert.deepEqual(kA, keys.kA, 'kA was not reset') - assert.equal(client.kB.length, 32, 'kB exists, has the right length') + assert.notEqual(wrapKb, keys.wrapKb, 'wrapKb was reset') + assert.equal(kA, keys.kA, 'kA was not reset') + assert.equal(typeof client.kB, 'string') + assert.equal(client.kB.length, 64, 'kB exists, has the right length') } ) } diff --git a/test/remote/db_tests.js b/test/remote/db_tests.js index 9ef4222f..58f01a20 100644 --- a/test/remote/db_tests.js +++ b/test/remote/db_tests.js @@ -32,8 +32,8 @@ const DB = require('../../lib/db')( var TOKEN_FRESHNESS_THRESHOLD = require('../../lib/tokens/session_token').TOKEN_FRESHNESS_THRESHOLD -var zeroBuffer16 = Buffer('00000000000000000000000000000000', 'hex') -var zeroBuffer32 = Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') +var zeroBuffer16 = Buffer('00000000000000000000000000000000', 'hex').toString('hex') +var zeroBuffer32 = Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex').toString('hex') let account @@ -53,7 +53,7 @@ describe('remote db', function() { beforeEach(() => { account = { - uid: uuid.v4('binary'), + uid: uuid.v4('binary').toString('hex'), email: dbServer.uniqueEmail(), emailCode: zeroBuffer16, emailVerified: false, @@ -126,8 +126,8 @@ describe('remote db', function() { .then(function(sessions) { assert.equal(sessions.length, 1, 'sessions contains one item') assert.equal(Object.keys(sessions[0]).length, 16, 'session has correct number of properties') - assert.ok(Buffer.isBuffer(sessions[0].tokenId), 'tokenId property is buffer') - assert.equal(sessions[0].uid.toString('hex'), account.uid.toString('hex'), 'uid property is correct') + assert.equal(typeof sessions[0].tokenId, 'string', 'tokenId property is not a buffer') + assert.equal(sessions[0].uid, account.uid, 'uid property is correct') assert.ok(sessions[0].createdAt >= account.createdAt, 'createdAt property seems correct') assert.equal(sessions[0].uaBrowser, 'Firefox', 'uaBrowser property is correct') assert.equal(sessions[0].uaBrowserVersion, '41', 'uaBrowserVersion property is correct') @@ -219,7 +219,7 @@ describe('remote db', function() { () => { var sessionToken var deviceInfo = { - id: crypto.randomBytes(16), + id: crypto.randomBytes(16).toString('hex'), name: '', type: 'mobile', pushCallback: 'https://foo/bar', @@ -268,7 +268,7 @@ describe('remote db', function() { }) }) .then(function (device) { - assert.ok(Buffer.isBuffer(device.id), 'device.id is set') + assert.ok(device.id, 'device.id is set') assert.ok(device.createdAt > 0, 'device.createdAt is set') assert.equal(device.name, deviceInfo.name, 'device.name is correct') assert.equal(device.type, deviceInfo.type, 'device.type is correct') @@ -292,7 +292,7 @@ describe('remote db', function() { return devices[0] }) .then(function (device) { - assert.ok(Buffer.isBuffer(device.id), 'device.id is set') + assert.ok(device.id, 'device.id is set') assert.ok(device.lastAccessTime > 0, 'device.lastAccessTime is set') assert.equal(device.name, deviceInfo.name, 'device.name is correct') assert.equal(device.type, deviceInfo.type, 'device.type is correct') @@ -658,13 +658,13 @@ describe('remote db', function() { it('signinCodes', () => { let previousCode - const flowId = crypto.randomBytes(32) + const flowId = crypto.randomBytes(32).toString('hex') // Create a signinCode without a flowId return db.createSigninCode(account.uid) .then(code => { - assert.ok(Buffer.isBuffer(code), 'db.createSigninCode should return a buffer') - assert.equal(code.length, config.signinCodeSize, 'db.createSigninCode should return the correct size code') + assert.equal(typeof code, 'string', 'db.createSigninCode should return a string') + assert.equal(Buffer.from(code, 'hex').length, config.signinCodeSize, 'db.createSigninCode should return the correct size code') previousCode = code @@ -685,9 +685,9 @@ describe('remote db', function() { return db.createSigninCode(account.uid, flowId) }) .then(code => { - assert.ok(Buffer.isBuffer(code), 'db.createSigninCode should return a buffer') - assert.equal(code.equals(previousCode), false, 'db.createSigninCode should not return a duplicate code') - assert.equal(code.length, config.signinCodeSize, 'db.createSigninCode should return the correct size code') + assert.equal(typeof code, 'string', 'db.createSigninCode should return a string') + assert.notEqual(code, previousCode, 'db.createSigninCode should not return a duplicate code') + assert.equal(Buffer.from(code, 'hex').length, config.signinCodeSize, 'db.createSigninCode should return the correct size code') // Consume both signinCodes return P.all([ @@ -700,7 +700,7 @@ describe('remote db', function() { assert.equal(results[1].email, account.email, 'db.consumeSigninCode should return the email address') if (results[1].flowId) { // This assertion is conditional so that tests pass regardless of db version - assert.equal(results[1].flowId, flowId.toString('hex'), 'db.consumeSigninCode should return the flowId') + assert.equal(results[1].flowId, flowId, 'db.consumeSigninCode should return the flowId') } // Attempt to consume a consumed signinCode diff --git a/test/remote/flow_tests.js b/test/remote/flow_tests.js index 35594729..014a315c 100644 --- a/test/remote/flow_tests.js +++ b/test/remote/flow_tests.js @@ -47,10 +47,10 @@ describe('remote flow', function() { ) .then( function (keys) { - assert.ok(Buffer.isBuffer(keys.kA), 'kA exists') - assert.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists') - assert.ok(Buffer.isBuffer(keys.kB), 'kB exists') - assert.equal(client.kB.length, 32, 'kB exists, has the right length') + assert.equal(typeof keys.kA, 'string', 'kA exists') + assert.equal(typeof keys.wrapKb, 'string', 'wrapKb exists') + assert.equal(typeof keys.kB, 'string', 'kB exists') + assert.equal(client.kB.length, 64, 'kB exists, has the right length') } ) .then( @@ -91,10 +91,10 @@ describe('remote flow', function() { ) .then( function (keys) { - assert.ok(Buffer.isBuffer(keys.kA), 'kA exists') - assert.ok(Buffer.isBuffer(keys.wrapKb), 'wrapKb exists') - assert.ok(Buffer.isBuffer(keys.kB), 'kB exists') - assert.equal(client.kB.length, 32, 'kB exists, has the right length') + assert.equal(typeof keys.kA, 'string', 'kA exists') + assert.equal(typeof keys.wrapKb, 'string', 'wrapKb exists') + assert.equal(typeof keys.kB, 'string', 'kB exists') + assert.equal(client.kB.length, 64, 'kB exists, has the right length') } ) .then( diff --git a/test/remote/mailer_db_tests.js b/test/remote/mailer_db_tests.js index a263634d..b3060cd2 100644 --- a/test/remote/mailer_db_tests.js +++ b/test/remote/mailer_db_tests.js @@ -5,8 +5,6 @@ 'use strict' const assert = require('insist') -var butil = require('../../lib/crypto/butil') -var unbuffer = butil.unbuffer var config = require('../../config').getProperties() var TestServer = require('../test_mailer_server') @@ -56,7 +54,7 @@ describe('mailer db', () => { return db.pool.put( '/account/' + accountData.uid.toString('hex'), - unbuffer(accountData) + accountData ) }) .then(function () { @@ -80,7 +78,7 @@ describe('mailer db', () => { return db.pool.put( '/account/' + accountData.uid.toString('hex'), - unbuffer(accountData) + accountData ) }) .then(function () { diff --git a/test/remote/mailer_reminder_db_tests.js b/test/remote/mailer_reminder_db_tests.js index c2bb2460..924ad977 100644 --- a/test/remote/mailer_reminder_db_tests.js +++ b/test/remote/mailer_reminder_db_tests.js @@ -6,8 +6,6 @@ const assert = require('insist') var P = require('../../lib/promise') -var butil = require('../../lib/crypto/butil') -var unbuffer = butil.unbuffer var config = require('../../config').getProperties() var TestServer = require('../test_mailer_server') var testHelper = require('../mailer_helper') @@ -44,7 +42,7 @@ describe('mailer reminder db', () => { return db.pool.put( '/account/' + accountData.uid.toString('hex'), - unbuffer(accountData) + accountData ) }) .then(function () { diff --git a/test/remote/password_forgot_tests.js b/test/remote/password_forgot_tests.js index 51dd6bb7..77ab223c 100644 --- a/test/remote/password_forgot_tests.js +++ b/test/remote/password_forgot_tests.js @@ -101,10 +101,11 @@ describe('remote password forgot', function() { ) .then( function (keys) { - assert.ok(Buffer.isBuffer(keys.wrapKb), 'yep, wrapKb') - assert.notDeepEqual(wrapKb, keys.wrapKb, 'wrapKb was reset') - assert.deepEqual(kA, keys.kA, 'kA was not reset') - assert.equal(client.kB.length, 32, 'kB exists, has the right length') + assert.equal(typeof keys.wrapKb, 'string', 'yep, wrapKb') + assert.notEqual(wrapKb, keys.wrapKb, 'wrapKb was reset') + assert.equal(kA, keys.kA, 'kA was not reset') + assert.equal(typeof client.kB, 'string') + assert.equal(client.kB.length, 64, 'kB exists, has the right length') } ) } diff --git a/test/remote/push_db_tests.js b/test/remote/push_db_tests.js index b1575ed3..005c10b4 100644 --- a/test/remote/push_db_tests.js +++ b/test/remote/push_db_tests.js @@ -21,12 +21,12 @@ const DB = require('../../lib/db')( Token ) -var zeroBuffer16 = Buffer('00000000000000000000000000000000', 'hex') -var zeroBuffer32 = Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex') +var zeroBuffer16 = Buffer('00000000000000000000000000000000', 'hex').toString('hex') +var zeroBuffer32 = Buffer('0000000000000000000000000000000000000000000000000000000000000000', 'hex').toString('hex') var SESSION_TOKEN_UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.10; rv:41.0) Gecko/20100101 Firefox/41.0' var ACCOUNT = { - uid: uuid.v4('binary'), + uid: uuid.v4('binary').toString('hex'), email: 'push' + Math.random() + '@bar.com', emailCode: zeroBuffer16, emailVerified: false, @@ -68,7 +68,7 @@ describe('remote push db', function() { () => { var sessionTokenId var deviceInfo = { - id: crypto.randomBytes(16), + id: crypto.randomBytes(16).toString('hex'), name: 'my push device', type: 'mobile', pushCallback: 'https://foo/bar', diff --git a/test/remote/signin_code_tests.js b/test/remote/signin_code_tests.js index ed42e835..7030d24e 100644 --- a/test/remote/signin_code_tests.js +++ b/test/remote/signin_code_tests.js @@ -67,7 +67,6 @@ describe('remote signinCodes', function () { }) }) .then(result => assert.deepEqual(result, { email }, '/signinCodes/consume should return the email address')) - .catch(err => assert.fail('/signinCodes/consume should succeed')) }) }) diff --git a/test/remote/verifier_upgrade_tests.js b/test/remote/verifier_upgrade_tests.js index 4738e7c8..0d3c27d1 100644 --- a/test/remote/verifier_upgrade_tests.js +++ b/test/remote/verifier_upgrade_tests.js @@ -49,7 +49,7 @@ describe('remote verifier upgrade', function() { return Client.create(config.publicUrl, email, password, { preVerified: true, keys: true }) .then( function (c) { - uid = Buffer(c.uid, 'hex') + uid = c.uid return server.stop() } )