From 37248a2c27bf81d8244d1b85c7f60208c8eb5607 Mon Sep 17 00:00:00 2001 From: Matias Alejo Garcia Date: Wed, 12 Nov 2014 11:38:45 -0300 Subject: [PATCH] reformat according to jshint --- plugins/emailstore.js | 1110 +++++++++++++++++++++-------------------- 1 file changed, 567 insertions(+), 543 deletions(-) diff --git a/plugins/emailstore.js b/plugins/emailstore.js index 6fe7cdf9..2aec6bdd 100644 --- a/plugins/emailstore.js +++ b/plugins/emailstore.js @@ -1,591 +1,615 @@ /** * GIST: https://gist.github.com/eordano/3e80ee3383554e94a08e */ -(function () { +(function() { -'use strict'; + 'use strict'; -var _ = require('lodash'); -var async = require('async'); -var bitcore = require('bitcore'); -var crypto = require('crypto'); -var fs = require('fs'); -var levelup = require('levelup'); -var nodemailer = require('nodemailer'); -var querystring = require('querystring'); + var _ = require('lodash'); + var async = require('async'); + var bitcore = require('bitcore'); + var crypto = require('crypto'); + var fs = require('fs'); + var levelup = require('levelup'); + var nodemailer = require('nodemailer'); + var querystring = require('querystring'); -var logger = require('../lib/logger').logger; -var globalConfig = require('../config/config'); + var logger = require('../lib/logger').logger; + var globalConfig = require('../config/config'); -var emailPlugin = {}; + var emailPlugin = {}; -/** - * Constant enum with the errors that the application may return - */ -emailPlugin.errors = { - MISSING_PARAMETER: { - code: 400, - message: 'Missing required parameter' - }, - INVALID_REQUEST: { - code: 400, - message: 'Invalid request parameter' - }, - NOT_FOUND: { - code: 404, - message: 'Credentials were not found' - }, - INTERNAL_ERROR: { - code: 500, - message: 'Unable to save to database' - }, - EMAIL_TAKEN: { - code: 409, - message: 'That email is already registered' - }, - INVALID_CODE: { - code: 403, - message: 'The provided code is invalid' - } -}; - -var EMAIL_TO_PASSPHRASE = 'email-to-passphrase-'; -var STORED_VALUE = 'emailstore-'; -var PENDING = 'pending-'; -var VALIDATED = 'validated-'; - -var SEPARATOR = '#'; -var MAX_ALLOWED_STORAGE = 1024 * 100 /* no more than 100 kb */; - -var valueKey = function(email, key) { - return STORED_VALUE + bitcore.util.twoSha256(email + SEPARATOR + key).toString('hex'); -}; - -var pendingKey = function(email) { - return PENDING + email; -}; - -var validatedKey = function(email) { - return VALIDATED + bitcore.util.twoSha256(email).toString('hex'); -}; - -var emailToPassphrase = function(email) { - return EMAIL_TO_PASSPHRASE + bitcore.util.twoSha256(email).toString('hex'); -}; - -/** - * Initializes the plugin - * - * @param {Object} config - */ -emailPlugin.init = function (config) { - logger.info('Using emailstore plugin'); - - var path = globalConfig.leveldb + '/emailstore' + (globalConfig.name ? ('-' + globalConfig.name) : ''); - emailPlugin.db = config.db || globalConfig.db || levelup(path); - - emailPlugin.email = config.emailTransport || nodemailer.createTransport(config.email); - - emailPlugin.textTemplate = config.textTemplate || 'copay.plain'; - emailPlugin.htmlTemplate = config.htmlTemplate || 'copay.html'; - - emailPlugin.crypto = config.crypto || crypto; - - emailPlugin.confirmUrl = ( - process.env.INSIGHT_EMAIL_CONFIRM_HOST - || config.confirmUrl - || 'https://insight.bitpay.com' - ) + globalConfig.apiPrefix + '/email/validate'; - - emailPlugin.redirectUrl = ( - config.redirectUrl - || 'https://copay.io/in/app?confirmed=true' - ); -}; - -/** - * Helper function that ends a requests showing the user an error. The response body will be a JSON - * encoded object with only one property with key "error" and value error.message, one of - * the parameters of the function - * - * @param {Object} error - The error that caused the request to be terminated - * @param {number} error.code - the HTTP code to return - * @param {string} error.message - the message to send in the body - * @param {Express.Response} response - the express.js response. the methods status, json, and end - * will be called, terminating the request. - */ -emailPlugin.returnError = function (error, response) { - response.status(error.code).json({error: error.message}).end(); -}; - -/** - * Helper that sends a verification email. - * - * @param {string} email - the user's email - * @param {string} secret - the verification secret - */ -emailPlugin.sendVerificationEmail = function (email, secret) { - var confirmUrl = emailPlugin.makeConfirmUrl(email, secret); - async.series([ - function(callback) { - emailPlugin.makeEmailBody({ - email: email, - confirm_url: confirmUrl - }, callback); + /** + * Constant enum with the errors that the application may return + */ + emailPlugin.errors = { + MISSING_PARAMETER: { + code: 400, + message: 'Missing required parameter' }, - function(callback) { - emailPlugin.makeEmailHTMLBody({ - email: email, - confirm_url: confirmUrl, - title: 'Your wallet backup needs confirmation' - }, callback); + INVALID_REQUEST: { + code: 400, + message: 'Invalid request parameter' + }, + NOT_FOUND: { + code: 404, + message: 'Credentials were not found' + }, + INTERNAL_ERROR: { + code: 500, + message: 'Unable to save to database' + }, + EMAIL_TAKEN: { + code: 409, + message: 'That email is already registered' + }, + INVALID_CODE: { + code: 403, + message: 'The provided code is invalid' } - ], function(err, results) { - var emailBody = results[0]; - var emailBodyHTML = results[1]; - var mailOptions = { + }; + + var EMAIL_TO_PASSPHRASE = 'email-to-passphrase-'; + var STORED_VALUE = 'emailstore-'; + var PENDING = 'pending-'; + var VALIDATED = 'validated-'; + + var SEPARATOR = '#'; + var MAX_ALLOWED_STORAGE = 1024 * 100 /* no more than 100 kb */ ; + + var valueKey = function(email, key) { + return STORED_VALUE + bitcore.util.twoSha256(email + SEPARATOR + key).toString('hex'); + }; + + var pendingKey = function(email) { + return PENDING + email; + }; + + var validatedKey = function(email) { + return VALIDATED + bitcore.util.twoSha256(email).toString('hex'); + }; + + var emailToPassphrase = function(email) { + return EMAIL_TO_PASSPHRASE + bitcore.util.twoSha256(email).toString('hex'); + }; + + /** + * Initializes the plugin + * + * @param {Object} config + */ + emailPlugin.init = function(config) { + logger.info('Using emailstore plugin'); + + var path = globalConfig.leveldb + '/emailstore' + (globalConfig.name ? ('-' + globalConfig.name) : ''); + emailPlugin.db = config.db || globalConfig.db || levelup(path); + + emailPlugin.email = config.emailTransport || nodemailer.createTransport(config.email); + + emailPlugin.textTemplate = config.textTemplate || 'copay.plain'; + emailPlugin.htmlTemplate = config.htmlTemplate || 'copay.html'; + + emailPlugin.crypto = config.crypto || crypto; + + emailPlugin.confirmUrl = ( + process.env.INSIGHT_EMAIL_CONFIRM_HOST || config.confirmUrl || 'https://insight.bitpay.com' + ) + globalConfig.apiPrefix + '/email/validate'; + + emailPlugin.redirectUrl = ( + config.redirectUrl || 'https://copay.io/in/app?confirmed=true' + ); + }; + + /** + * Helper function that ends a requests showing the user an error. The response body will be a JSON + * encoded object with only one property with key "error" and value error.message, one of + * the parameters of the function + * + * @param {Object} error - The error that caused the request to be terminated + * @param {number} error.code - the HTTP code to return + * @param {string} error.message - the message to send in the body + * @param {Express.Response} response - the express.js response. the methods status, json, and end + * will be called, terminating the request. + */ + emailPlugin.returnError = function(error, response) { + response.status(error.code).json({ + error: error.message + }).end(); + }; + + /** + * Helper that sends a verification email. + * + * @param {string} email - the user's email + * @param {string} secret - the verification secret + */ + emailPlugin.sendVerificationEmail = function(email, secret) { + var confirmUrl = emailPlugin.makeConfirmUrl(email, secret); + async.series([ + + function(callback) { + emailPlugin.makeEmailBody({ + email: email, + confirm_url: confirmUrl + }, callback); + }, + function(callback) { + emailPlugin.makeEmailHTMLBody({ + email: email, + confirm_url: confirmUrl, + title: 'Your wallet backup needs confirmation' + }, callback); + } + ], function(err, results) { + var emailBody = results[0]; + var emailBodyHTML = results[1]; + var mailOptions = { from: 'copay@copay.io', to: email, subject: '[Copay] Your wallet backup needs confirmation', text: emailBody, html: emailBodyHTML - }; + }; - // send mail with defined transport object - emailPlugin.email.sendMail(mailOptions, function (err, info) { - if (err) { - logger.error('An error occurred when trying to send email to ' + email, err); - } else { - logger.info('Message sent: ', info ? info : ''); - } + // send mail with defined transport object + emailPlugin.email.sendMail(mailOptions, function(err, info) { + if (err) { + logger.error('An error occurred when trying to send email to ' + email, err); + } else { + logger.info('Message sent: ', info ? info : ''); + } + }); }); - }); -}; + }; -emailPlugin.makeConfirmUrl = function(email, secret) { - return emailPlugin.confirmUrl + ( - '?email=' + encodeURIComponent(email) + '&verification_code='+secret - ); -}; - -/** - * Returns a function that reads an underscore template and uses the `opts` param - * to build an email body - */ -var applyTemplate = function(templateFilename) { - return function(opts, callback) { - fs.readFile(__dirname + '/emailTemplates/' + emailPlugin[templateFilename], - function(err, template) { - return callback(err, _.template(template, opts)); - } + emailPlugin.makeConfirmUrl = function(email, secret) { + return emailPlugin.confirmUrl + ( + '?email=' + encodeURIComponent(email) + '&verification_code=' + secret ); }; -}; -emailPlugin.makeEmailBody = applyTemplate('textTemplate'); -emailPlugin.makeEmailHTMLBody = applyTemplate('htmlTemplate'); + /** + * Returns a function that reads an underscore template and uses the `opts` param + * to build an email body + */ + var applyTemplate = function(templateFilename) { + return function(opts, callback) { + fs.readFile(__dirname + '/emailTemplates/' + emailPlugin[templateFilename], + function(err, template) { + return callback(err, _.template(template, opts)); + } + ); + }; + }; -/** - * @param {string} email - * @param {Function(err, boolean)} callback - */ -emailPlugin.exists = function(email, callback) { - emailPlugin.db.get(emailToPassphrase(email), function(err, value) { - if (err && err.notFound) { - return callback(null, false); - } else if (err) { - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(null, true); - }); -}; + emailPlugin.makeEmailBody = applyTemplate('textTemplate'); + emailPlugin.makeEmailHTMLBody = applyTemplate('htmlTemplate'); -/** - * @param {string} email - * @param {string} passphrase - * @param {Function(err, boolean)} callback - */ -emailPlugin.checkPassphrase = function(email, passphrase, callback) { - emailPlugin.db.get(emailToPassphrase(email), function(err, retrievedPassphrase) { - if (err) { - if (err.notFound) { + /** + * @param {string} email + * @param {Function(err, boolean)} callback + */ + emailPlugin.exists = function(email, callback) { + emailPlugin.db.get(emailToPassphrase(email), function(err, value) { + if (err && err.notFound) { + return callback(null, false); + } else if (err) { + return callback(emailPlugin.errors.INTERNAL_ERROR); + } + return callback(null, true); + }); + }; + + /** + * @param {string} email + * @param {string} passphrase + * @param {Function(err, boolean)} callback + */ + emailPlugin.checkPassphrase = function(email, passphrase, callback) { + emailPlugin.db.get(emailToPassphrase(email), function(err, retrievedPassphrase) { + if (err) { + if (err.notFound) { + return callback(emailPlugin.errors.INVALID_CODE); + } + logger.error('error checking passphrase', email, err); + return callback(emailPlugin.errors.INTERNAL_ERROR); + } + return callback(err, passphrase === retrievedPassphrase); + }); + }; + + + /** + * @param {string} email + * @param {string} passphrase + * @param {Function(err)} callback + */ + emailPlugin.savePassphrase = function(email, passphrase, callback) { + emailPlugin.db.put(emailToPassphrase(email), passphrase, function(err) { + if (err) { + logger.error('error saving passphrase', err); + return callback(emailPlugin.errors.INTERNAL_ERROR); + } + return callback(null); + }); + }; + + /** + * @param {string} email + * @param {string} key + * @param {string} record + * @param {Function(err)} callback + */ + emailPlugin.saveEncryptedData = function(email, key, record, callback) { + emailPlugin.db.put(valueKey(email, key), record, function(err) { + if (err) { + logger.error('error saving encrypted data', email, key, record, err); + return callback(emailPlugin.errors.INTERNAL_ERROR); + } + return callback(); + }); + }; + + emailPlugin.createVerificationSecretAndSendEmail = function(email, callback) { + emailPlugin.createVerificationSecret(email, function(err, secret) { + if (err) { + logger.error('error saving verification secret', email, secret, err); + return callback(emailPlugin.errors.INTERNAL_ERROR); + } + if (secret) { + emailPlugin.sendVerificationEmail(email, secret); + } + callback(); + }); + }; + + /** + * Creates and stores a verification secret in the database. + * + * @param {string} email - the user's email + * @param {Function} callback - will be called with params (err, secret) + */ + emailPlugin.createVerificationSecret = function(email, callback) { + emailPlugin.db.get(pendingKey(email), function(err, value) { + if (err && err.notFound) { + var secret = emailPlugin.crypto.randomBytes(16).toString('hex'); + emailPlugin.db.put(pendingKey(email), secret, function(err) { + if (err) { + logger.error('error saving pending data:', email, secret); + return callback(emailPlugin.errors.INTERNAL_ERROR); + } + return callback(null, secret); + }); + } else { + return callback(); + } + }); + }; + + /** + * @param {string} email + * @param {Function(err)} callback + */ + emailPlugin.retrieveByEmailAndKey = function(email, key, callback) { + emailPlugin.db.get(valueKey(email, key), function(error, value) { + if (error) { + if (error.notFound) { + return callback(emailPlugin.errors.NOT_FOUND); + } + return callback(emailPlugin.errors.INTERNAL_ERROR); + } + return callback(null, value); + }); + }; + + emailPlugin.retrieveDataByEmailAndPassphrase = function(email, key, passphrase, callback) { + emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { + if (err) { + return callback(err); + } + if (matches) { + return emailPlugin.retrieveByEmailAndKey(email, key, callback); + } else { return callback(emailPlugin.errors.INVALID_CODE); } - logger.error('error checking passphrase', email, err); - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(err, passphrase === retrievedPassphrase); - }); -}; + }); + }; + /** + * Store a record in the database. The underlying database is merely a levelup instance (a key + * value store) that uses the email concatenated with the secret as a key to store the record. + * The request is expected to contain the parameters: + * * email + * * secret + * * record + * + * @param {Express.Request} request + * @param {Express.Response} response + */ + emailPlugin.save = function(request, response) { -/** - * @param {string} email - * @param {string} passphrase - * @param {Function(err)} callback - */ -emailPlugin.savePassphrase = function(email, passphrase, callback) { - emailPlugin.db.put(emailToPassphrase(email), passphrase, function(err) { - if (err) { - logger.error('error saving passphrase', err); - return callback(emailPlugin.errors.INTERNAL_ERROR); + var queryData = ''; + var credentials = emailPlugin.getCredentialsFromRequest(request); + if (credentials.code) { + return emailPlugin.returnError(credentials, response); } - return callback(null); - }); -}; + var email = credentials.email; + var passphrase = credentials.passphrase; -/** - * @param {string} email - * @param {string} key - * @param {string} record - * @param {Function(err)} callback - */ -emailPlugin.saveEncryptedData = function(email, key, record, callback) { - emailPlugin.db.put(valueKey(email, key), record, function(err) { - if (err) { - logger.error('error saving encrypted data', email, key, record, err); - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(); - }); -}; - -emailPlugin.createVerificationSecretAndSendEmail = function (email, callback) { - emailPlugin.createVerificationSecret(email, function(err, secret) { - if (err) { - logger.error('error saving verification secret', email, secret, err); - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - if (secret) { - emailPlugin.sendVerificationEmail(email, secret); - } - callback(); - }); -}; - -/** - * Creates and stores a verification secret in the database. - * - * @param {string} email - the user's email - * @param {Function} callback - will be called with params (err, secret) - */ -emailPlugin.createVerificationSecret = function (email, callback) { - emailPlugin.db.get(pendingKey(email), function(err, value) { - if (err && err.notFound) { - var secret = emailPlugin.crypto.randomBytes(16).toString('hex'); - emailPlugin.db.put(pendingKey(email), secret, function (err) { - if (err) { - logger.error('error saving pending data:', email, secret); - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(null, secret); - }); - } else { - return callback(); - } - }); -}; - -/** - * @param {string} email - * @param {Function(err)} callback - */ -emailPlugin.retrieveByEmailAndKey = function(email, key, callback) { - emailPlugin.db.get(valueKey(email, key), function(error, value) { - if (error) { - if (error.notFound) { - return callback(emailPlugin.errors.NOT_FOUND); + request.on('data', function(data) { + queryData += data; + if (queryData.length > MAX_ALLOWED_STORAGE) { + queryData = ''; + response.writeHead(413, { + 'Content-Type': 'text/plain' + }).end(); + request.connection.destroy(); + } + }).on('end', function() { + var params = querystring.parse(queryData); + var key = params.key; + var record = params.record; + if (!email || !passphrase || !record || !key) { + return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); } - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(null, value); - }); -}; -emailPlugin.retrieveDataByEmailAndPassphrase = function(email, key, passphrase, callback) { - emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { - if (err) { - return callback(err); - } - if (matches) { - return emailPlugin.retrieveByEmailAndKey(email, key, callback); - } else { - return callback(emailPlugin.errors.INVALID_CODE); - } - }); -}; + emailPlugin.processPost(request, response, email, key, passphrase, record); + }); + }; -/** - * Store a record in the database. The underlying database is merely a levelup instance (a key - * value store) that uses the email concatenated with the secret as a key to store the record. - * The request is expected to contain the parameters: - * * email - * * secret - * * record - * - * @param {Express.Request} request - * @param {Express.Response} response - */ -emailPlugin.save = function (request, response) { - - var queryData = ''; - var credentials = emailPlugin.getCredentialsFromRequest(request); - if (credentials.code) { - return emailPlugin.returnError(credentials, response); - } - var email = credentials.email; - var passphrase = credentials.passphrase; - - request.on('data', function (data) { - queryData += data; - if (queryData.length > MAX_ALLOWED_STORAGE) { - queryData = ''; - response.writeHead(413, {'Content-Type': 'text/plain'}).end(); - request.connection.destroy(); - } - }).on('end', function () { - var params = querystring.parse(queryData); - var key = params.key; - var record = params.record; - if (!email || !passphrase || !record || !key) { - return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); - } - - emailPlugin.processPost(request, response, email, key, passphrase, record); - }); -}; - -emailPlugin.processPost = function(request, response, email, key, passphrase, record) { - async.series([ - /** - * Try to fetch this user's email. If it exists, check the secret is the same. - */ - function (callback) { - emailPlugin.exists(email, function(err, exists) { - if (err) { - return callback(err); - } else if (exists) { - emailPlugin.checkPassphrase(email, passphrase, function(err, match) { - if (err) { - return callback(err); - } - if (match) { + emailPlugin.processPost = function(request, response, email, key, passphrase, record) { + async.series([ + /** + * Try to fetch this user's email. If it exists, check the secret is the same. + */ + function(callback) { + emailPlugin.exists(email, function(err, exists) { + if (err) { + return callback(err); + } else if (exists) { + emailPlugin.checkPassphrase(email, passphrase, function(err, match) { + if (err) { + return callback(err); + } + if (match) { + return callback(); + } else { + return callback(emailPlugin.errors.EMAIL_TAKEN); + } + }); + } else { + emailPlugin.savePassphrase(email, passphrase, function(err) { + if (err) { + return callback(err); + } return callback(); - } else { - return callback(emailPlugin.errors.EMAIL_TAKEN); - } - }); - } else { - emailPlugin.savePassphrase(email, passphrase, function(err) { - if (err) { - return callback(err); - } - return callback(); - }); - } - }); - }, - /** - * Save the encrypted private key in the storage. - */ - function (callback) { - emailPlugin.saveEncryptedData(email, key, record, function(err) { - if (err) { - return callback(err); - } - return callback(); - }); - }, - /** - * Create and store the verification secret. If successful, send a verification email. - */ - function (callback) { - emailPlugin.createVerificationSecretAndSendEmail(email, function (err) { - if (err) { - callback({code: 500, message: err}); - } else { - callback(); - } - }); - } - ], function (err) { + }); + } + }); + }, + /** + * Save the encrypted private key in the storage. + */ + function(callback) { + emailPlugin.saveEncryptedData(email, key, record, function(err) { + if (err) { + return callback(err); + } + return callback(); + }); + }, + /** + * Create and store the verification secret. If successful, send a verification email. + */ + function(callback) { + emailPlugin.createVerificationSecretAndSendEmail(email, function(err) { + if (err) { + callback({ + code: 500, + message: err + }); + } else { + callback(); + } + }); + } + ], function(err) { if (err) { emailPlugin.returnError(err, response); } else { - response.json({success: true}).end(); + response.json({ + success: true + }).end(); } - } - ); -}; - - -emailPlugin.getCredentialsFromRequest = function(request) { - if (!request.header('authorization')) { - return emailPlugin.errors.INVALID_REQUEST; - } - var authHeader = new Buffer(request.header('authorization'), 'base64').toString('utf8'); - var splitIndex = authHeader.indexOf(':'); - if (splitIndex === -1) { - return emailPlugin.errors.INVALID_REQUEST; - } - var email = authHeader.substr(0, splitIndex); - var passphrase = authHeader.substr(splitIndex + 1); - - return {email: email, passphrase: passphrase}; -}; - -/** - * Retrieve a record from the database - */ -emailPlugin.retrieve = function (request, response) { - var credentialsResult = emailPlugin.getCredentialsFromRequest(request); - if (_.contains(emailPlugin.errors, credentialsResult)) { - return emailPlugin.returnError(credentialsResult); - } - var email = credentialsResult.email; - var passphrase = credentialsResult.passphrase; - - var key = request.param('key'); - if (!passphrase || !email || !key) { - return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); - } - - emailPlugin.retrieveDataByEmailAndPassphrase(email, key, passphrase, function (err, value) { - if (err) { - return emailPlugin.returnError(err, response); - } - response.send(value).end(); - }); -}; - -/** - * Marks an email as validated - * - * The two expected params are: - * * email - * * verification_code - * - * @param {Express.Request} request - * @param {Express.Response} response - */ -emailPlugin.validate = function (request, response) { - var email = request.param('email'); - var secret = request.param('verification_code'); - if (!email || !secret) { - return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); - } - - emailPlugin.db.get(pendingKey(email), function (err, value) { - if (err) { - if (err.notFound) { - return emailPlugin.returnError(emailPlugin.errors.NOT_FOUND, response); - } - return emailPlugin.returnError({code: 500, message: err}, response); - } else if (value !== secret) { - return emailPlugin.returnError(emailPlugin.errors.INVALID_CODE, response); - } else { - emailPlugin.db.put(validatedKey(email), true, function (err, value) { - if (err) { - return emailPlugin.returnError({code: 500, message: err}, response); - } else { - emailPlugin.db.del(pendingKey(email), function (err, value) { - if (err) { - return emailPlugin.returnError({code: 500, message: err}, response); - } else { - response.redirect(emailPlugin.redirectUrl); - } - }); - } - }); - } - }); -}; - -/** - * Changes an user's passphrase - * - * @param {Express.Request} request - * @param {Express.Response} response - */ -emailPlugin.changePassphrase = function (request, response) { - var credentialsResult = emailPlugin.getCredentialsFromRequest(request); - if (_.contains(emailPlugin.errors, credentialsResult)) { - return emailPlugin.returnError(credentialsResult); - } - var email = credentialsResult.email; - var passphrase = credentialsResult.passphrase; - - var queryData = ''; - request.on('data', function (data) { - queryData += data; - if (queryData.length > MAX_ALLOWED_STORAGE) { - queryData = ''; - response.writeHead(413, {'Content-Type': 'text/plain'}).end(); - request.connection.destroy(); - } - }).on('end', function () { - var params = querystring.parse(queryData); - var newPassphrase = params.newPassphrase; - if (!email || !passphrase || !newPassphrase) { - return emailPlugin.returnError(emailPlugin.errors.INVALID_REQUEST, response); - } - emailPlugin.checkPassphrase(email, passphrase, function (error) { - if (error) { - return emailPlugin.returnError(error, response); - } - emailPlugin.savePassphrase(email, newPassphrase, function (error) { - if (error) { - return emailPlugin.returnError(error, response); - } - return response.json({success: true}).end(); - }); }); - }); -}; + }; -// Backwards compatibility - -emailPlugin.oldRetrieve = function (request, response) { - var email = request.param('email'); - var key = request.param('key'); - var secret = request.param('secret'); - if (!secret) { - return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); - } - - emailPlugin.retrieveDataByEmailAndPassphrase(email, key, secret, function (err, value) { - if (err) { - return emailPlugin.returnError(err, response); + emailPlugin.getCredentialsFromRequest = function(request) { + if (!request.header('authorization')) { + return emailPlugin.errors.INVALID_REQUEST; } - response.send(value).end(); - }); -}; - -emailPlugin.oldSave = function (request, response) { - var queryData = ''; - - request.on('data', function (data) { - queryData += data; - if (queryData.length > MAX_ALLOWED_STORAGE) { - queryData = ''; - response.writeHead(413, {'Content-Type': 'text/plain'}).end(); - request.connection.destroy(); + var authHeader = new Buffer(request.header('authorization'), 'base64').toString('utf8'); + var splitIndex = authHeader.indexOf(':'); + if (splitIndex === -1) { + return emailPlugin.errors.INVALID_REQUEST; } - }).on('end', function () { - var params = querystring.parse(queryData); - var email = params.email; - var passphrase = params.secret; - var key = params.key; - var record = params.record; - if (!email || !passphrase || !record || !key) { + var email = authHeader.substr(0, splitIndex); + var passphrase = authHeader.substr(splitIndex + 1); + + return { + email: email, + passphrase: passphrase + }; + }; + + /** + * Retrieve a record from the database + */ + emailPlugin.retrieve = function(request, response) { + var credentialsResult = emailPlugin.getCredentialsFromRequest(request); + if (_.contains(emailPlugin.errors, credentialsResult)) { + return emailPlugin.returnError(credentialsResult); + } + var email = credentialsResult.email; + var passphrase = credentialsResult.passphrase; + + var key = request.param('key'); + if (!passphrase || !email || !key) { return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); } - emailPlugin.processPost(request, response, email, key, passphrase, record); - }); -}; + emailPlugin.retrieveDataByEmailAndPassphrase(email, key, passphrase, function(err, value) { + if (err) { + return emailPlugin.returnError(err, response); + } + response.send(value).end(); + }); + }; -module.exports = emailPlugin; + /** + * Marks an email as validated + * + * The two expected params are: + * * email + * * verification_code + * + * @param {Express.Request} request + * @param {Express.Response} response + */ + emailPlugin.validate = function(request, response) { + var email = request.param('email'); + var secret = request.param('verification_code'); + if (!email || !secret) { + return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); + } + + emailPlugin.db.get(pendingKey(email), function(err, value) { + if (err) { + if (err.notFound) { + return emailPlugin.returnError(emailPlugin.errors.NOT_FOUND, response); + } + return emailPlugin.returnError({ + code: 500, + message: err + }, response); + } else if (value !== secret) { + return emailPlugin.returnError(emailPlugin.errors.INVALID_CODE, response); + } else { + emailPlugin.db.put(validatedKey(email), true, function(err, value) { + if (err) { + return emailPlugin.returnError({ + code: 500, + message: err + }, response); + } else { + emailPlugin.db.del(pendingKey(email), function(err, value) { + if (err) { + return emailPlugin.returnError({ + code: 500, + message: err + }, response); + } else { + response.redirect(emailPlugin.redirectUrl); + } + }); + } + }); + } + }); + }; + + /** + * Changes an user's passphrase + * + * @param {Express.Request} request + * @param {Express.Response} response + */ + emailPlugin.changePassphrase = function(request, response) { + var credentialsResult = emailPlugin.getCredentialsFromRequest(request); + if (_.contains(emailPlugin.errors, credentialsResult)) { + return emailPlugin.returnError(credentialsResult); + } + var email = credentialsResult.email; + var passphrase = credentialsResult.passphrase; + + var queryData = ''; + request.on('data', function(data) { + queryData += data; + if (queryData.length > MAX_ALLOWED_STORAGE) { + queryData = ''; + response.writeHead(413, { + 'Content-Type': 'text/plain' + }).end(); + request.connection.destroy(); + } + }).on('end', function() { + var params = querystring.parse(queryData); + var newPassphrase = params.newPassphrase; + if (!email || !passphrase || !newPassphrase) { + return emailPlugin.returnError(emailPlugin.errors.INVALID_REQUEST, response); + } + emailPlugin.checkPassphrase(email, passphrase, function(error) { + if (error) { + return emailPlugin.returnError(error, response); + } + emailPlugin.savePassphrase(email, newPassphrase, function(error) { + if (error) { + return emailPlugin.returnError(error, response); + } + return response.json({ + success: true + }).end(); + }); + }); + }); + }; + + + // Backwards compatibility + + emailPlugin.oldRetrieve = function(request, response) { + var email = request.param('email'); + var key = request.param('key'); + var secret = request.param('secret'); + if (!secret) { + return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); + } + + emailPlugin.retrieveDataByEmailAndPassphrase(email, key, secret, function(err, value) { + if (err) { + return emailPlugin.returnError(err, response); + } + response.send(value).end(); + }); + }; + + emailPlugin.oldSave = function(request, response) { + var queryData = ''; + + request.on('data', function(data) { + queryData += data; + if (queryData.length > MAX_ALLOWED_STORAGE) { + queryData = ''; + response.writeHead(413, { + 'Content-Type': 'text/plain' + }).end(); + request.connection.destroy(); + } + }).on('end', function() { + var params = querystring.parse(queryData); + var email = params.email; + var passphrase = params.secret; + var key = params.key; + var record = params.record; + if (!email || !passphrase || !record || !key) { + return emailPlugin.returnError(emailPlugin.errors.MISSING_PARAMETER, response); + } + + emailPlugin.processPost(request, response, email, key, passphrase, record); + }); + }; + + module.exports = emailPlugin; })();