From 777f17feb4f2d4756df95b492ab939973c22ee88 Mon Sep 17 00:00:00 2001 From: Manuel Araoz Date: Thu, 5 Feb 2015 14:30:50 -0300 Subject: [PATCH] remove plugins --- README.md | 8 - config/config.js | 28 +- config/routes.js | 25 - dev-util/deleteWholeProfile.js | 21 - index.js | 25 - plugins/cleaner.js | 25 - plugins/config-cleaner.js | 5 - plugins/config-credentialstore.js | 2 - plugins/config-currencyrates.js | 4 - plugins/config-emailstore.js | 9 - plugins/config-mailbox.js | 3 - plugins/config-monitor.js | 3 - plugins/config-ratelimiter.js | 3 - plugins/credentialstore.js | 160 ----- plugins/currencyRates/bitpay.js | 15 - plugins/currencyRates/bitstamp.js | 11 - plugins/currencyrates.js | 199 ------ plugins/emailTemplates/copay.html | 190 ------ plugins/emailTemplates/copay.plain | 27 - plugins/emailstore.js | 933 ----------------------------- plugins/mailbox.js | 65 -- plugins/monitor.js | 26 - plugins/publicInfo/config.js | 2 - plugins/publicInfo/publicInfo.js | 144 ----- plugins/ratelimiter.js | 35 -- test/test.CredentialStore.js | 101 ---- test/test.CurrencyRates.js | 265 -------- test/test.EmailStore.js | 683 --------------------- test/test.MessageDb.js | 133 ---- test/test.PublicProfile.js | 113 ---- test/test.socket-server.js | 30 - 31 files changed, 1 insertion(+), 3292 deletions(-) delete mode 100644 dev-util/deleteWholeProfile.js delete mode 100644 plugins/cleaner.js delete mode 100644 plugins/config-cleaner.js delete mode 100644 plugins/config-credentialstore.js delete mode 100644 plugins/config-currencyrates.js delete mode 100644 plugins/config-emailstore.js delete mode 100644 plugins/config-mailbox.js delete mode 100644 plugins/config-monitor.js delete mode 100644 plugins/config-ratelimiter.js delete mode 100644 plugins/credentialstore.js delete mode 100644 plugins/currencyRates/bitpay.js delete mode 100644 plugins/currencyRates/bitstamp.js delete mode 100644 plugins/currencyrates.js delete mode 100644 plugins/emailTemplates/copay.html delete mode 100644 plugins/emailTemplates/copay.plain delete mode 100644 plugins/emailstore.js delete mode 100644 plugins/mailbox.js delete mode 100644 plugins/monitor.js delete mode 100644 plugins/publicInfo/config.js delete mode 100644 plugins/publicInfo/publicInfo.js delete mode 100644 plugins/ratelimiter.js delete mode 100644 test/test.CredentialStore.js delete mode 100644 test/test.CurrencyRates.js delete mode 100644 test/test.EmailStore.js delete mode 100644 test/test.MessageDb.js delete mode 100644 test/test.PublicProfile.js delete mode 100644 test/test.socket-server.js diff --git a/README.md b/README.md index f3520866..161d0e28 100644 --- a/README.md +++ b/README.md @@ -73,16 +73,8 @@ INSIGHT_PORT # insight api port INSIGHT_DB # Path where to store insight's internal DB. (defaults to $HOME/.insight) INSIGHT_SAFE_CONFIRMATIONS=6 # Nr. of confirmation needed to start caching transaction information INSIGHT_IGNORE_CACHE # True to ignore cache of spents in transaction, with more than INSIGHT_SAFE_CONFIRMATIONS confirmations. This is useful for tracking double spents for old transactions. -ENABLE_MAILBOX # if "true" will enable mailbox plugin -ENABLE_CLEANER # if "true" will enable message db cleaner plugin -ENABLE_MONITOR # if "true" will enable message db monitor plugin -ENABLE_CURRENCYRATES # if "true" will enable a plugin to obtain historic conversion rates for various currencies -ENABLE_RATELIMITER # if "true" will enable the ratelimiter plugin LOGGER_LEVEL # defaults to 'info', can be 'debug','verbose','error', etc. ENABLE_HTTPS # if "true" it will server using SSL/HTTPS -ENABLE_EMAILSTORE # if "true" will enable a plugin to store data with a validated email address -INSIGHT_EMAIL_CONFIRM_HOST # Only meanfull if ENABLE_EMAILSTORE is enable. Hostname for the confirm URLs. E.g: 'https://insight.bitpay.com' - ``` Make sure that bitcoind is configured to [accept incoming connections using 'rpcallowip'](https://en.bitcoin.it/wiki/Running_Bitcoin). diff --git a/config/config.js b/config/config.js index cdae77c3..201310be 100644 --- a/config/config.js +++ b/config/config.js @@ -16,7 +16,7 @@ var version = JSON.parse(packageStr).version; function getUserHome() { - return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']; + return process.env[(process.platform === 'win32') ? 'USERPROFILE' : 'HOME']; } var home = process.env.INSIGHT_DB || (getUserHome() + '/.insight'); @@ -79,38 +79,14 @@ var bitcoindConf = { disableAgent: true }; -var enableMonitor = process.env.ENABLE_MONITOR === 'true'; -var enableCleaner = process.env.ENABLE_CLEANER === 'true'; -var enableMailbox = process.env.ENABLE_MAILBOX === 'true'; -var enableRatelimiter = process.env.ENABLE_RATELIMITER === 'true'; -var enableCredentialstore = process.env.ENABLE_CREDSTORE === 'true'; -var enableEmailstore = process.env.ENABLE_EMAILSTORE === 'true'; -var enablePublicInfo = process.env.ENABLE_PUBLICINFO === 'true'; var loggerLevel = process.env.LOGGER_LEVEL || 'info'; var enableHTTPS = process.env.ENABLE_HTTPS === 'true'; -var enableCurrencyRates = process.env.ENABLE_CURRENCYRATES === 'true'; if (!fs.existsSync(db)) { mkdirp.sync(db); } module.exports = { - enableMonitor: enableMonitor, - monitor: require('../plugins/config-monitor.js'), - enableCleaner: enableCleaner, - cleaner: require('../plugins/config-cleaner.js'), - enableMailbox: enableMailbox, - mailbox: require('../plugins/config-mailbox.js'), - enableRatelimiter: enableRatelimiter, - ratelimiter: require('../plugins/config-ratelimiter.js'), - enableCredentialstore: enableCredentialstore, - credentialstore: require('../plugins/config-credentialstore'), - enableEmailstore: enableEmailstore, - emailstore: require('../plugins/config-emailstore'), - enableCurrencyRates: enableCurrencyRates, - currencyrates: require('../plugins/config-currencyrates'), - enablePublicInfo: enablePublicInfo, - publicInfo: require('../plugins/publicInfo/config'), loggerLevel: loggerLevel, enableHTTPS: enableHTTPS, version: version, @@ -126,8 +102,6 @@ module.exports = { disableHistoricSync: false, poolMatchFile: rootPath + '/etc/minersPoolStrings.json', - // Time to refresh the currency rate. In minutes - currencyRefresh: 10, keys: { segmentio: process.env.INSIGHT_SEGMENTIO_KEY }, diff --git a/config/routes.js b/config/routes.js index bf24e006..eeedf7de 100644 --- a/config/routes.js +++ b/config/routes.js @@ -53,31 +53,6 @@ module.exports = function(app) { var currency = require('../app/controllers/currency'); app.get(apiPrefix + '/currency', currency.index); - // Email store plugin - if (config.enableEmailstore) { - var emailPlugin = require('../plugins/emailstore'); - app.post(apiPrefix + '/email/save', emailPlugin.save); - app.get(apiPrefix + '/email/retrieve', emailPlugin.retrieve); - app.post(apiPrefix + '/email/change_passphrase', emailPlugin.changePassphrase); - - app.post(apiPrefix + '/email/validate', emailPlugin.validate); - app.get(apiPrefix + '/email/validate', emailPlugin.validate); - - app.post(apiPrefix + '/email/register', emailPlugin.oldSave); - app.get(apiPrefix + '/email/retrieve/:email', emailPlugin.oldRetrieve); - - app.post(apiPrefix + '/email/delete/profile', emailPlugin.eraseProfile); - app.get(apiPrefix + '/email/delete/item', emailPlugin.erase); - - app.get(apiPrefix + '/email/resend_email', emailPlugin.resendEmail); - } - - // Currency rates plugin - if (config.enableCurrencyRates) { - var currencyRatesPlugin = require('../plugins/currencyrates'); - app.get(apiPrefix + '/rates/:code', currencyRatesPlugin.getRate); - } - // Address routes var messages = require('../app/controllers/messages'); app.get(apiPrefix + '/messages/verify', messages.verify); diff --git a/dev-util/deleteWholeProfile.js b/dev-util/deleteWholeProfile.js deleted file mode 100644 index 36893092..00000000 --- a/dev-util/deleteWholeProfile.js +++ /dev/null @@ -1,21 +0,0 @@ -#!usr/bin/env node - -var email = process.argv[2]; - -if (!email) { - console.log('\tdeleteWholeProfile.js '); - process.exit(-1); -} - -console.log('\t Deleting email:', email, process.env.INSIGHT_NETWORK); - -var p = require('../plugins/emailstore'); - -p.init({}); - -p.deleteWholeProfile(email, function(err) { - if (err) - console.log('[err:]', err); - else - console.log('done'); -}); diff --git a/index.js b/index.js index 0e6fba55..fd410fa4 100755 --- a/index.js +++ b/index.js @@ -126,31 +126,6 @@ if (peerSync) peerSync.allowReorgs = true; var ios = require('socket.io')(server, config); require('./app/controllers/socket.js').init(ios); -// plugins -if (config.enableRatelimiter) { - require('./plugins/ratelimiter').init(expressApp, config.ratelimiter); -} - -if (config.enableMailbox) { - require('./plugins/mailbox').init(ios, config.mailbox); -} - -if (config.enableCleaner) { - require('./plugins/cleaner').init(config.cleaner); -} - -if (config.enableMonitor) { - require('./plugins/monitor').init(config.monitor); -} - -if (config.enableEmailstore) { - require('./plugins/emailstore').init(config.emailstore); -} - -if (config.enableCurrencyRates) { - require('./plugins/currencyrates').init(config.currencyrates); -} - // express settings require('./config/express')(expressApp, historicSync, peerSync); require('./config/routes')(expressApp); diff --git a/plugins/cleaner.js b/plugins/cleaner.js deleted file mode 100644 index 84b5b1f7..00000000 --- a/plugins/cleaner.js +++ /dev/null @@ -1,25 +0,0 @@ -var mdb = require('../lib/MessageDb').default(); -var logger = require('../lib/logger').logger; -var preconditions = require('preconditions').singleton(); -var microtime = require('microtime'); -var cron = require('cron'); -var CronJob = cron.CronJob; -var Threshold = (process.env.CLEANER_THRESHOLD_DAYS || 30) *24*60*60; // in seconds - -module.exports.init = function(config) { - var cronTime = config.cronTime || '0 * * * *'; - logger.info('Using cleaner plugin with cronTime ' + cronTime + ' and threshold of ' + Threshold + ' seconds'); - var onTick = function() { - var limit = microtime.now() - 1000 * 1000 * Threshold; - mdb.removeUpTo(limit, function(err, n) { - if (err) logger.error(err); - else logger.info('Ran cleaner task, removed ' + n); - }); - }; - var job = new CronJob({ - cronTime: cronTime, - onTick: onTick - }); - onTick(); - job.start(); -}; diff --git a/plugins/config-cleaner.js b/plugins/config-cleaner.js deleted file mode 100644 index 1f3e1406..00000000 --- a/plugins/config-cleaner.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - - cronTime: '0 * * * *', // run each hour - -}; diff --git a/plugins/config-credentialstore.js b/plugins/config-credentialstore.js deleted file mode 100644 index 7be35b6b..00000000 --- a/plugins/config-credentialstore.js +++ /dev/null @@ -1,2 +0,0 @@ -module.exports = { -}; diff --git a/plugins/config-currencyrates.js b/plugins/config-currencyrates.js deleted file mode 100644 index 45758fd7..00000000 --- a/plugins/config-currencyrates.js +++ /dev/null @@ -1,4 +0,0 @@ -module.exports = { - fetchIntervalInMinutes: 60, - defaultSource: 'BitPay', -}; diff --git a/plugins/config-emailstore.js b/plugins/config-emailstore.js deleted file mode 100644 index 645024d7..00000000 --- a/plugins/config-emailstore.js +++ /dev/null @@ -1,9 +0,0 @@ -module.exports = { - email: { - service: 'Gmail', - auth: { - user: '', - pass: '' - } - } -}; diff --git a/plugins/config-mailbox.js b/plugins/config-mailbox.js deleted file mode 100644 index f4d62530..00000000 --- a/plugins/config-mailbox.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - -}; diff --git a/plugins/config-monitor.js b/plugins/config-monitor.js deleted file mode 100644 index 1958a96b..00000000 --- a/plugins/config-monitor.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - cronTime: '* * * * *', // run each minute -}; diff --git a/plugins/config-ratelimiter.js b/plugins/config-ratelimiter.js deleted file mode 100644 index f4d62530..00000000 --- a/plugins/config-ratelimiter.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - -}; diff --git a/plugins/credentialstore.js b/plugins/credentialstore.js deleted file mode 100644 index 5deff523..00000000 --- a/plugins/credentialstore.js +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Credentials storage service - * - * Allows users to store encrypted data on the server, useful to store the user's credentials. - * - * Steps for the user would be: - * - * 1. Choose an username - * 2. Choose a password - * 3. Create a strong key for encryption using PBKDF2 or scrypt with the username and password - * 4. Use that key to AES-CRT encrypt the private key - * 5. Take the double SHA256 hash of "salt"+"username"+"password" and use that as a secret - * 6. Send a POST request to resource /credentials with the params: - * username=johndoe - * secret=2413fb3709b05939f04cf2e92f7d0897fc2596f9ad0b8a9ea855c7bfebaae892 - * record=YjU1MTI2YTM5ZjliMTE3MGEzMmU2ZjYxZTRhNjk0YzQ1MjM1ZTVhYzExYzA1ZWNkNmZm - * NjM5NWRlNmExMTE4NzIzYzYyYWMwODU1MTdkNWMyNjRiZTVmNmJjYTMxMGQyYmFiNjc4YzdiODV - * lZjg5YWIxYzQ4YjJmY2VkYWJjMDQ2NDYzODhkODFiYTU1NjZmMzgwYzhiODdiMzlmYjQ5ZTc1Nz - * FjYzQzYjk1YTEyYWU1OGMxYmQ3OGFhOTZmNGMz - * - * To retrieve data: - * - * 1. Recover the secret from the double sha256 of the salt, username, and password - * 2. Send a GET request to resource /credentials/username?secret=...... - * 3. Decrypt the data received - */ -(function() { - -'use strict'; - -var logger = require('../lib/logger').logger, - levelup = require('levelup'), - querystring = require('querystring'); - -var storePlugin = {}; - -/** - * Constant enum with the errors that the application may return - */ -var 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' - } -}; - -var NAMESPACE = 'credentials-store-'; -var MAX_ALLOWED_STORAGE = 1024 /* no more than 1 kb */; - -/** - * Initializes the plugin - * - * @param {Express} expressApp - * @param {Object} config - */ -storePlugin.init = function(expressApp, config) { - var globalConfig = require('../config/config'); - logger.info('Using credentialstore plugin'); - - var path = globalConfig.leveldb + '/credentialstore' + (globalConfig.name ? ('-' + globalConfig.name) : ''); - storePlugin.db = config.db || globalConfig.db || levelup(path); - - expressApp.post(globalConfig.apiPrefix + '/credentials', storePlugin.post); - expressApp.get(globalConfig.apiPrefix + '/credentials/:username', storePlugin.get); -}; - -/** - * 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. - */ -var returnError = function(error, response) { - response.status(error.code).json({error: error.message}).end(); -}; - -/** - * Store a record in the database. The underlying database is merely a levelup instance (a key - * value store) that uses the username concatenated with the secret as a key to store the record. - * The request is expected to contain the parameters: - * * username - * * secret - * * record - * - * @param {Express.Request} request - * @param {Express.Response} response - */ -storePlugin.post = 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 username = params.username; - var secret = params.secret; - var record = params.record; - if (!username || !secret || !record) { - return returnError(errors.MISSING_PARAMETER, response); - } - - storePlugin.db.put(NAMESPACE + username + secret, record, function (err) { - if (err) { - return returnError({code: 500, message: err}, response); - } - response.json({success: true}).end(); - }); - }); -}; - -/** - * Retrieve a record from the database. - * - * The request is expected to contain the parameters: - * * username - * * secret - * - * @param {Express.Request} request - * @param {Express.Response} response - */ -storePlugin.get = function(request, response) { - var username = request.param('username'); - var secret = request.param('secret'); - if (!username || !secret) { - return returnError(errors.MISSING_PARAMETER, response); - } - - storePlugin.db.get(NAMESPACE + username + secret, function (err, value) { - if (err) { - if (err.notFound) { - return returnError(errors.NOT_FOUND, response); - } - return returnError({code: 500, message: err}, response); - } - response.send(value).end(); - }); -}; - -module.exports = storePlugin; - -})(); diff --git a/plugins/currencyRates/bitpay.js b/plugins/currencyRates/bitpay.js deleted file mode 100644 index fb9a4422..00000000 --- a/plugins/currencyRates/bitpay.js +++ /dev/null @@ -1,15 +0,0 @@ -var _ = require('lodash'); - -module.exports.id = 'BitPay'; -module.exports.url = 'https://bitpay.com/api/rates/'; - -module.exports.parseFn = function(raw) { - var rates = _.compact(_.map(raw, function(d) { - if (!d.code || !d.rate) return null; - return { - code: d.code, - rate: d.rate, - }; - })); - return rates; -}; diff --git a/plugins/currencyRates/bitstamp.js b/plugins/currencyRates/bitstamp.js deleted file mode 100644 index 1743c2b6..00000000 --- a/plugins/currencyRates/bitstamp.js +++ /dev/null @@ -1,11 +0,0 @@ -var _ = require('lodash'); - -module.exports.id = 'Bitstamp'; -module.exports.url = 'https://www.bitstamp.net/api/ticker/'; - -module.exports.parseFn = function(raw) { - return [{ - code: 'USD', - rate: parseFloat(raw.last) - }]; -}; diff --git a/plugins/currencyrates.js b/plugins/currencyrates.js deleted file mode 100644 index cc53eba2..00000000 --- a/plugins/currencyrates.js +++ /dev/null @@ -1,199 +0,0 @@ -(function() { - 'use strict'; - - var _ = require('lodash'); - var async = require('async'); - var levelup = require('levelup'); - var request = require('request'); - var preconditions = require('preconditions').singleton(); - - var logger = require('../lib/logger').logger; - var globalConfig = require('../config/config'); - - var currencyRatesPlugin = {}; - - function getCurrentTs() { - return Math.floor(new Date() / 1000); - }; - - function getKey(sourceId, code, ts) { - var key = sourceId + '-' + code.toUpperCase(); - if (ts) { - key += '-' + ts; - } - return key; - }; - - function returnError(error, res) { - res.status(error.code).json({ - error: error.message, - }).end(); - }; - - currencyRatesPlugin.init = function(config) { - logger.info('Using currencyrates plugin'); - - config = config || {}; - - var path = globalConfig.leveldb + '/currencyRates' + (globalConfig.name ? ('-' + globalConfig.name) : ''); - currencyRatesPlugin.db = config.db || globalConfig.db || levelup(path); - - if (_.isArray(config.sources)) { - currencyRatesPlugin.sources = config.sources; - } else { - currencyRatesPlugin.sources = [ - require('./currencyRates/bitpay'), - require('./currencyRates/bitstamp'), - ]; - } - currencyRatesPlugin.request = config.request || request; - currencyRatesPlugin.defaultSource = config.defaultSource || globalConfig.defaultSource; - - currencyRatesPlugin.initialized = true; - - var interval = config.fetchIntervalInMinutes || globalConfig.fetchIntervalInMinutes; - if (interval) { - currencyRatesPlugin._fetch(); - setInterval(function() { - currencyRatesPlugin._fetch(); - }, interval * 60 * 1000); - } - }; - - currencyRatesPlugin._retrieve = function(source, cb) { - logger.debug('Fetching data for ' + source.id); - currencyRatesPlugin.request.get({ - url: source.url, - json: true - }, function(err, res, body) { - if (err || !body) { - logger.warn('Error fetching data for ' + source.id, err); - return cb(err); - } - - logger.debug('Data for ' + source.id + ' fetched successfully'); - - if (!source.parseFn) { - return cb('No parse function for source ' + source.id); - } - var rates = source.parseFn(body); - - return cb(null, rates); - }); - }; - - currencyRatesPlugin._store = function(source, rates, cb) { - logger.debug('Storing data for ' + source.id); - var ts = getCurrentTs(); - var ops = _.map(rates, function(r) { - return { - type: 'put', - key: getKey(source.id, r.code, ts), - value: r.rate, - }; - }); - - currencyRatesPlugin.db.batch(ops, function(err) { - if (err) { - logger.warn('Error storing data for ' + source.id, err); - return cb(err); - } - logger.debug('Data for ' + source.id + ' stored successfully'); - return cb(); - }); - }; - - currencyRatesPlugin._dump = function(opts) { - var all = []; - currencyRatesPlugin.db.readStream(opts) - .on('data', console.log); - }; - - currencyRatesPlugin._fetch = function(cb) { - cb = cb || function() {}; - - preconditions.shouldNotBeFalsey(currencyRatesPlugin.initialized); - - async.each(currencyRatesPlugin.sources, function(source, cb) { - currencyRatesPlugin._retrieve(source, function(err, res) { - if (err) { - logger.warn(err); - return cb(); - } - currencyRatesPlugin._store(source, res, function(err, res) { - return cb(); - }); - }); - }, function(err) { - return cb(err); - }); - }; - - currencyRatesPlugin._getOneRate = function(sourceId, code, ts, cb) { - var result = null; - - currencyRatesPlugin.db.createValueStream({ - lte: getKey(sourceId, code, ts), - gte: getKey(sourceId, code) + '!', - reverse: true, - limit: 1, - }) - .on('data', function(data) { - var num = parseFloat(data); - result = _.isNumber(num) && !_.isNaN(num) ? num : null; - }) - .on('error', function(err) { - return cb(err); - }) - .on('end', function() { - return cb(null, result); - }); - }; - - currencyRatesPlugin._getRate = function(sourceId, code, ts, cb) { - preconditions.shouldNotBeFalsey(currencyRatesPlugin.initialized); - preconditions.shouldNotBeEmpty(code); - preconditions.shouldBeFunction(cb); - - ts = ts || getCurrentTs(); - - if (!_.isArray(ts)) { - return currencyRatesPlugin._getOneRate(sourceId, code, ts, function(err, rate) { - if (err) return cb(err); - return cb(null, { - rate: rate - }); - }); - } - - async.map(ts, function(ts, cb) { - currencyRatesPlugin._getOneRate(sourceId, code, ts, function(err, rate) { - if (err) return cb(err); - return cb(null, { - ts: parseInt(ts), - rate: rate - }); - }); - }, function(err, res) { - if (err) return cb(err); - return cb(null, res); - }); - }; - - currencyRatesPlugin.getRate = function(req, res) { - var source = req.param('source') || currencyRatesPlugin.defaultSource; - var ts = req.param('ts'); - if (_.isString(ts) && ts.indexOf(',') !== -1) { - ts = ts.split(','); - } - currencyRatesPlugin._getRate(source, req.param('code'), ts, function(err, result) { - if (err) returnError({ - code: 500, - message: err, - }); - res.json(result); - }); - }; - - module.exports = currencyRatesPlugin; -})(); diff --git a/plugins/emailTemplates/copay.html b/plugins/emailTemplates/copay.html deleted file mode 100644 index 3639b0d4..00000000 --- a/plugins/emailTemplates/copay.html +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - <%= title%> - - - - - - - - - - - - - - - -
- - - - - - - -
- - -

Hi, <%= email %>

- -

You are now using Insight to store an encrypted Copay backup. This is a free -service that we are providing that you can turn off from Copay's preferences.

- -

In order to prevent abuse, we need you to confirm that this email is valid and -that you requested this backup. Please follow this link if you agree on -backing up your Copay profile within our servers:

- -

- - Confirm your email (click here). -

-

If the above link doesn't work, head to: <%= confirm_url %>

- -

We would also like you to know that:

-
    - -
  • We only store information encrypted by your Copay app. We can't retrieve your private keys, help you remember the password, or collect any information about your wallet.
  • - -
  • In case that one of our servers is compromised, intruders may be able to brute-force their way into your private keys unless you use a strong password.
  • - -
  • Our code is open source and can be audited here: -
      -
    • https://github.com/bitpay/insight
    • -
    • https://github.com/bitpay/copay
    • -
    -
  • -
- -

Thanks!

- -

The Copay Team

- -
- - - diff --git a/plugins/emailTemplates/copay.plain b/plugins/emailTemplates/copay.plain deleted file mode 100644 index f6ee1624..00000000 --- a/plugins/emailTemplates/copay.plain +++ /dev/null @@ -1,27 +0,0 @@ -Hi, <%= email %> - -You are now using Insight to store an encrypted Copay backup. This is a free -service that we are providing that you can turn off from Copay's preferences. - -In order to prevent abuse, we need you to confirm that this email is valid and -that you requested this backup. Please follow this link if you agree on -backing up your Copay profile within our servers: - - <%= confirm_url %> - -We would also like you to take note of these: - - * We only store information encrypted by your Copay app. We can't retrieve - your private keys, help you remember the password, or collect any information - about your wallet. - - * In case of a service compromise, intruders may be able to brute-force their - way into your private keys. Please use a strong password to avoid this. - - * Our code is open source and can be audited here: - https://github.com/bitpay/insight - https://github.com/bitpay/copay - -Thanks! - -The Copay Team diff --git a/plugins/emailstore.js b/plugins/emailstore.js deleted file mode 100644 index 70a8e949..00000000 --- a/plugins/emailstore.js +++ /dev/null @@ -1,933 +0,0 @@ -/** - * GIST: https://gist.github.com/eordano/3e80ee3383554e94a08e - */ -(function() { - - '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 moment = require('moment'); - - var logger = require('../lib/logger').logger; - var globalConfig = require('../config/config'); - - 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: 'Email already confirmed or credentials 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' - }, - OVER_QUOTA: { - code: 406, - message: 'User quota exceeded', - }, - ERROR_SENDING_EMAIL: { - code: 501, - message: 'Could not send verification email', - }, - }; - - var EMAIL_TO_PASSPHRASE = 'email-to-passphrase-'; - var STORED_VALUE = 'emailstore-'; - var ITEMS_COUNT = 'itemscount-'; - var PENDING = 'pending-'; - var VALIDATED = 'validated-'; - - var SEPARATOR = '#'; - - var UNCONFIRMED_PER_ITEM_QUOTA = 1024 * 150; /* 150 kb */ - var CONFIRMED_PER_ITEM_QUOTA = 1024 * 300; /* 300 kb */ - - var UNCONFIRMED_ITEMS_LIMIT = 6; - var CONFIRMED_ITEMS_LIMIT = 11; - - var POST_LIMIT = 1024 * 300 /* Max POST 300 kb */ ; - - var valueKey = function(email, key) { - return STORED_VALUE + bitcore.util.twoSha256(email + SEPARATOR + key).toString('hex'); - }; - - - var countKey = function(email) { - return ITEMS_COUNT + bitcore.util.twoSha256(email).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' - ); - }; - - /** - * 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, callback) { - var confirmUrl = emailPlugin.makeConfirmUrl(email, secret); - - logger.debug('ConfirmUrl:',confirmUrl); - - 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); - return callback(err); - } - logger.info('Message sent: ', info ? info : ''); - return callback(err, 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.makeEmailBody = applyTemplate('textTemplate'); - emailPlugin.makeEmailHTMLBody = applyTemplate('htmlTemplate'); - - /** - * @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); - }); - }; - - - /** - * checkSizeQuota - * - * @param email - * @param size - * @param isConfirmed - * @param callback - */ - emailPlugin.checkSizeQuota = function(email, size, isConfirmed, callback) { - var err; - - if (size > (isConfirmed ? CONFIRMED_PER_ITEM_QUOTA : UNCONFIRMED_PER_ITEM_QUOTA)) - err = emailPlugin.errors.OVER_QUOTA; - - logger.info('Storage size:', size); - return callback(err); - }; - - - emailPlugin.checkAndUpdateItemCounter = function(email, isConfirmed, isAdd, callback) { - // this is a new item... Check User's Items quota. - emailPlugin.db.get(countKey(email), function(err, counter) { - if (err && !err.notFound) { - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - counter = (parseInt(counter) || 0) - - if (isAdd) { - counter++; - logger.info('User counter quota:', counter); - if (counter > (isConfirmed ? CONFIRMED_ITEMS_LIMIT : UNCONFIRMED_ITEMS_LIMIT)) { - return callback(emailPlugin.errors.OVER_QUOTA); - } - } else { - if (counter > 0) counter--; - } - - - emailPlugin.db.put(countKey(email), counter, function(err) { - if (err) { - logger.error('error saving counter'); - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(); - }); - }); - }; - - - /** - * @param {string} email - * @param {string} key - * @param {Function(err)} callback - */ - emailPlugin.checkAndUpdateItemQuota = function(email, key, isConfirmed, callback) { - - emailPlugin.db.get(valueKey(email, key), function(err) { - - //existing item? - if (!err) - return callback(); - - if (err.notFound) { - //new item - return emailPlugin.checkAndUpdateItemCounter(email, isConfirmed, 1, callback); - } else { - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - }); - }; - - - /** - * @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 || !secret) { - logger.error('error saving verification secret', email, secret, err); - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - emailPlugin.sendVerificationEmail(email, secret, function (err, res) { - if (err) { - logger.error('error sending verification email', email, secret, err); - return callback(emailPlugin.errors.ERROR_SENDING_EMAIL); - } - return 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'); - var value = { - secret: secret, - created: moment().unix(), - }; - emailPlugin.db.put(pendingKey(email), JSON.stringify(value), function(err) { - if (err) { - logger.error('error saving pending data:', email, value); - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(null, secret); - }); - } else { - return callback(err); - } - }); - }; - - /** - * @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.deleteByEmailAndKey = function deleteByEmailAndKey(email, key, callback) { - emailPlugin.db.del(valueKey(email, key), function(error) { - if (error) { - logger.error(error); - if (error.notFound) { - return callback(emailPlugin.errors.NOT_FOUND); - } - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return emailPlugin.checkAndUpdateItemCounter(email, null, null, callback); - }); - }; - - emailPlugin.deleteWholeProfile = function deleteWholeProfile(email, callback) { - async.parallel([ - - function(cb) { - emailPlugin.db.del(emailToPassphrase(email), cb); - }, - function(cb) { - emailPlugin.db.del(pendingKey(email), cb); - }, - function(cb) { - emailPlugin.db.del(validatedKey(email), cb); - } - ], function(err) { - if (err && !err.notFound) { - logger.error(err); - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(); - }); - }; - - /** - * 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 > POST_LIMIT) { - queryData = ''; - response.writeHead(413, { - 'Content-Type': 'text/plain' - }); - response.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) { - var isNewProfile = false; - var isConfirmed = true; - var errorCreating = false; - - 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); - - if (exists) { - emailPlugin.checkPassphrase(email, passphrase, function(err, match) { - if (err) return callback(err); - if (!match) return callback(emailPlugin.errors.EMAIL_TAKEN); - return callback(); - }); - } else { - isNewProfile = true; - emailPlugin.savePassphrase(email, passphrase, function(err) { - return callback(err); - }); - } - }); - }, - function(callback) { - emailPlugin.isConfirmed(email, function(err, inIsConfirmed) { - if (err) return callback(err); - isConfirmed = inIsConfirmed; - return callback(); - }); - }, - function(callback) { - emailPlugin.checkSizeQuota(email, record.length, isConfirmed, function(err) { - return callback(err); - }); - }, - function(callback) { - emailPlugin.checkAndUpdateItemQuota(email, key, isConfirmed, function(err) { - return callback(err); - }); - }, - /** - * Save the encrypted private key in the storage. - */ - function(callback) { - emailPlugin.saveEncryptedData(email, key, record, function(err) { - return callback(err); - }); - }, - /** - * Create and store the verification secret. If successful, send a verification email. - */ - function(callback) { - if (!isNewProfile || isConfirmed) return callback(); - - emailPlugin.createVerificationSecretAndSendEmail(email, function(err) { - if (err) { - errorCreating = true; - } - return callback(err); - }); - }, - ], - function(err) { - if (err) { - if (isNewProfile && !isConfirmed && errorCreating) { - emailPlugin.deleteWholeProfile(email, function() { - return emailPlugin.returnError(err, response); - }); - } - - emailPlugin.returnError(err, response); - } else { - response.json({ - success: true - }).end(); - } - }); - }; - - emailPlugin.getCredentialsFromRequest = function(request) { - var auth = request.header('authorization'); - if (!auth) { - return emailPlugin.errors.INVALID_REQUEST; - } - var authHeader = new Buffer(auth, '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 - }; - }; - - - /** - * @param {string} email - * @param {Function(err, boolean)} callback - */ - emailPlugin.isConfirmed = function(email, callback) { - emailPlugin.db.get(validatedKey(email), function(err, isConfirmed) { - if (err && err.notFound) { - return callback(null, false); - } else if (err) { - return callback(emailPlugin.errors.INTERNAL_ERROR); - } - return callback(null, !!isConfirmed); - }); - }; - - - /** - * addValidationAndQuotaHeader - * - * @param response - * @param email - * @param {Function(err, boolean)} callback - */ - emailPlugin.addValidationAndQuotaHeader = function(response, email, callback) { - emailPlugin.isConfirmed(email, function(err, isConfirmed) { - if (err) return callback(err); - - if (!isConfirmed) { - response.set('X-Email-Needs-Validation', 'true'); - } - - response.set('X-Quota-Per-Item', isConfirmed ? CONFIRMED_PER_ITEM_QUOTA : UNCONFIRMED_PER_ITEM_QUOTA); - response.set('X-Quota-Items-Limit', isConfirmed ? CONFIRMED_ITEMS_LIMIT : UNCONFIRMED_ITEMS_LIMIT); - return callback(); - }); - }; - - emailPlugin.authorizeRequest = function(request, withKey, callback) { - var credentialsResult = emailPlugin.getCredentialsFromRequest(request); - if (_.contains(emailPlugin.errors, credentialsResult)) { - return callback(credentialsResult); - } - - var email = credentialsResult.email; - var passphrase = credentialsResult.passphrase; - var key; - if (withKey) { - key = request.param('key'); - } - - if (!passphrase || !email || (withKey && !key)) { - return callback(emailPlugin.errors.MISSING_PARAMETER); - } - - emailPlugin.checkPassphrase(email, passphrase, function(err, matches) { - if (err) { - return callback(err); - } - - if (!matches) { - return callback(emailPlugin.errors.INVALID_CODE); - } - - return callback(null, email, key); - }); - }; - - emailPlugin.authorizeRequestWithoutKey = function(request, callback) { - emailPlugin.authorizeRequest(request, false, callback); - }; - - emailPlugin.authorizeRequestWithKey = function(request, callback) { - emailPlugin.authorizeRequest(request, true, callback); - }; - - /** - * Retrieve a record from the database - */ - emailPlugin.retrieve = function(request, response) { - emailPlugin.authorizeRequestWithKey(request, function(err, email, key) { - if (err) - return emailPlugin.returnError(err, response); - - emailPlugin.retrieveByEmailAndKey(email, key, function(err, value) { - if (err) - return emailPlugin.returnError(err, response); - - - emailPlugin.addValidationAndQuotaHeader(response, email, function(err) { - if (err) - return emailPlugin.returnError(err, response); - - response.send(value).end(); - }); - }); - }); - }; - - /** - * Remove a record from the database - */ - emailPlugin.erase = function(request, response) { - emailPlugin.authorizeRequestWithKey(request, function(err, email, key) { - if (err) { - return emailPlugin.returnError(err, response); - } - emailPlugin.deleteByEmailAndKey(email, key, function(err, value) { - if (err) { - return emailPlugin.returnError(err, response); - } else { - return response.json({ - success: true - }).end(); - }; - }); - }); - }; - - /** - * Remove a whole profile from the database - * - * @TODO: This looks very similar to the method above - */ - emailPlugin.eraseProfile = function(request, response) { - emailPlugin.authorizeRequestWithoutKey(request, function(err, email) { - if (err) { - return emailPlugin.returnError(err, response); - } - - emailPlugin.deleteWholeProfile(email, function(err, value) { - if (err) { - return emailPlugin.returnError(err, response); - } else { - return response.json({ - success: true - }).end(); - }; - }); - }); - }; - - emailPlugin._parseSecret = function (value) { - var obj = null; - try { - obj = JSON.parse(value); - } catch (e) {} - - if (obj && _.isObject(obj)) { - return obj.secret; - } - - return value; - }; - - emailPlugin.resendEmail = function(request, response) { - emailPlugin.authorizeRequestWithoutKey(request, function(err, email) { - if (err) { - return emailPlugin.returnError(err, response); - } - emailPlugin.db.get(pendingKey(email), function(err, value) { - if (err) { - logger.error('error retrieving secret for email', email, err); - return emailPlugin.returnError(err, response); - } - - var secret = emailPlugin._parseSecret(value); - - emailPlugin.sendVerificationEmail(email, secret, function (err) { - if (err) { - logger.error('error resending verification email', email, secret, err); - return emailPlugin.returnError(emailPlugin.errors.ERROR_SENDING_EMAIL, response); - } - return response.json({ - success: true - }).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); - } - - value = emailPlugin._parseSecret(value); - - if (value !== secret) { - return emailPlugin.returnError(emailPlugin.errors.INVALID_CODE, response); - } - - 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) { - - emailPlugin.authorizeRequestWithoutKey(request, function(err, email) { - - if (err) { - return emailPlugin.returnError(err, response); - } - - var queryData = ''; - request.on('data', function(data) { - queryData += data; - if (queryData.length > POST_LIMIT) { - 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 (!newPassphrase) { - return emailPlugin.returnError(emailPlugin.errors.INVALID_REQUEST, response); - } - emailPlugin.savePassphrase(email, newPassphrase, function(error) { - if (error) { - return emailPlugin.returnError(error, response); - } - return response.json({ - success: true - }).end(); - }); - }); - }); - }; - - - // - // Backwards compatibility - // - - emailPlugin.oldRetrieveDataByEmailAndPassphrase = 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.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.oldRetrieveDataByEmailAndPassphrase(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 > UNCONFIRMED_PER_ITEM_QUOTA) { - 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; - -})(); diff --git a/plugins/mailbox.js b/plugins/mailbox.js deleted file mode 100644 index 8619252f..00000000 --- a/plugins/mailbox.js +++ /dev/null @@ -1,65 +0,0 @@ -var microtime = require('microtime'); -var mdb = require('../lib/MessageDb').default(); -var logger = require('../lib/logger').logger; -var preconditions = require('preconditions').singleton(); - -var io; -module.exports.init = function(ext_io, config) { - logger.info('Using mailbox plugin'); - preconditions.checkArgument(ext_io); - io = ext_io; - io.sockets.on('connection', function(socket) { - // when it requests sync, send him all pending messages - socket.on('sync', function(ts) { - logger.verbose('Sync requested by ' + socket.id); - logger.debug(' from timestamp ' + ts); - var rooms = socket.rooms; - if (rooms.length !== 2) { - socket.emit('insight-error', 'Must subscribe with public key before syncing'); - return; - } - var to = rooms[1]; - var upper_ts = Math.round(microtime.now()); - logger.debug(' to timestamp ' + upper_ts); - mdb.getMessages(to, ts, upper_ts, function(err, messages) { - // TODO: return error to the user - if (err) { - logger.debug('Couldn\'t get messages on sync request: ' + err); - } - logger.verbose('\tFound ' + messages.length + ' message' + (messages.length !== 1 ? 's' : '')); - - if (messages.length) { - for (var i = 0; i < messages.length; i++) { - broadcastMessage(messages[i], socket); - } - } else { - socket.emit('no messages'); - } - }); - }); - - // when it sends a message, add it to db - socket.on('message', function(m) { - logger.debug('Message sent from ' + m.pubkey + ' to ' + m.to); - mdb.addMessage(m, function(err) { - // TODO: return error to the user - if (err) { - logger.debug('Couldn\'t add message to database: ' + err); - } - }); - }); - - }); - - mdb.on('message', broadcastMessage); - -}; - - - -var broadcastMessage = module.exports.broadcastMessage = function(message, socket) { - preconditions.checkState(io); - var s = socket || io.sockets.in(message.to); - logger.debug('sending message to ' + message.to); - s.emit('message', message); -} diff --git a/plugins/monitor.js b/plugins/monitor.js deleted file mode 100644 index e5d0ac3e..00000000 --- a/plugins/monitor.js +++ /dev/null @@ -1,26 +0,0 @@ -var mdb = require('../lib/MessageDb').default(); -var logger = require('../lib/logger').logger; -var preconditions = require('preconditions').singleton(); -var microtime = require('microtime'); -var cron = require('cron'); -var CronJob = cron.CronJob; - - -module.exports.init = function(config) { - var cronTime = config.cronTime || '0 * * * *'; - logger.info('Using monitor plugin with cronTime ' + cronTime); - var onTick = function() { - mdb.getAll(function(err, messages) { - if (err) logger.error(err); - else { - logger.info('Message db size = ' + messages.length); - } - }); - }; - var job = new CronJob({ - cronTime: cronTime, - onTick: onTick - }); - onTick(); - job.start(); -}; diff --git a/plugins/publicInfo/config.js b/plugins/publicInfo/config.js deleted file mode 100644 index 7be35b6b..00000000 --- a/plugins/publicInfo/config.js +++ /dev/null @@ -1,2 +0,0 @@ -module.exports = { -}; diff --git a/plugins/publicInfo/publicInfo.js b/plugins/publicInfo/publicInfo.js deleted file mode 100644 index ddafb034..00000000 --- a/plugins/publicInfo/publicInfo.js +++ /dev/null @@ -1,144 +0,0 @@ -/** - * Module to allow Copay users to publish public information about themselves - * - * It uses BitAuth to verify the authenticity of the request. - * - */ -(function() { - -'use strict'; - -var logger = require('../../lib/logger').logger, - levelup = require('levelup'), - bitauth = require('bitauth'), - globalConfig = require('../../config/config'), - querystring = require('querystring'); - -var publicInfo = {}; - -/** - * Constant enum with the errors that the application may return - */ -var errors = { - MISSING_PARAMETER: { - code: 400, - message: 'Missing required parameter' - }, - UNAUTHENTICATED: { - code: 401, - message: 'SIN validation error' - }, - NOT_FOUND: { - code: 404, - message: 'There\'s no record of public information for the public key requested' - } -}; - -var NAMESPACE = 'public-info-'; -var MAX_ALLOWED_STORAGE = 64 * 1024 /* no more than 64 kb of data is allowed to be stored */; - -/** - * Initializes the plugin - * - * @param {Express} expressApp - * @param {Object} config - */ -publicInfo.init = function(expressApp, config) { - logger.info('Using publicInfo plugin'); - - var path = globalConfig.leveldb + '/publicinfo' + (globalConfig.name ? ('-' + globalConfig.name) : ''); - publicInfo.db = config.db || globalConfig.db || levelup(path); - - expressApp.post(globalConfig.apiPrefix + '/public', publicInfo.post); - expressApp.get(globalConfig.apiPrefix + '/public/:sin', publicInfo.get); -}; - -/** - * 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. - */ -var returnError = function(error, response) { - response.status(error.code).json({error: error.message}).end(); -}; - -/** - * Store a record in the database. The underlying database is merely a levelup instance (a key - * value store) that uses the SIN to store the body of the message. - * - * @param {Express.Request} request - * @param {Express.Response} response - */ -publicInfo.post = function(request, response) { - - var record = ''; - request.on('data', function(data) { - record += data; - if (record.length > MAX_ALLOWED_STORAGE) { - record = ''; - response.writeHead(413, {'Content-Type': 'text/plain'}).end(); - request.connection.destroy(); - } - }).on('end', function() { - var fullUrl = request.protocol + '://' + request.get('host') + request.url; - var data = fullUrl + record; - - bitauth.verifySignature(data, request.headers['x-identity'], request.headers['x-signature'], - function(err, result) { - if(err || !result) { - return returnError(errors.UNAUTHENTICATED, response); - } - - // Get the SIN from the public key - var sin = bitauth.getSinFromPublicKey(request.headers['x-identity']); - if (!sin) { - return returnError(errors.UNAUTHENTICATED, response); - } - publicInfo.db.put(NAMESPACE + sin, record, function (err) { - if (err) { - return returnError({code: 500, message: err}, response); - } - response.json({success: true}).end(); - if (request.testCallback) { - request.testCallback(); - } - }); - } - ); - }); -}; - -/** - * Retrieve a record from the database. - * - * The request is expected to contain the parameter "sin" - * - * @param {Express.Request} request - * @param {Express.Response} response - */ -publicInfo.get = function(request, response) { - var sin = request.param('sin'); - if (!sin) { - return returnError(errors.MISSING_PARAMETER, response); - } - - publicInfo.db.get(NAMESPACE + sin, function (err, value) { - if (err) { - if (err.notFound) { - return returnError(errors.NOT_FOUND, response); - } - return returnError({code: 500, message: err}, response); - } - response.send(value).end(); - }); -}; - -module.exports = publicInfo; - -})(); diff --git a/plugins/ratelimiter.js b/plugins/ratelimiter.js deleted file mode 100644 index 6c3b2b72..00000000 --- a/plugins/ratelimiter.js +++ /dev/null @@ -1,35 +0,0 @@ -var logger = require('../lib/logger').logger; -var preconditions = require('preconditions').singleton(); - -var limiter = require('connect-ratelimit'); -var ONE_HOUR = 60 * 60 * 1000; - -module.exports.init = function(app, config) { - preconditions.checkArgument(app); - logger.info('Using ratelimiter plugin'); - - config = config || {}; - config.whitelistRPH = config.whitelistRPH || 500000; - config.normalRPH = config.normalRPH || 10000; - config.blacklistRPH = config.blacklistRPH || 0; - - app.use(limiter({ - whitelist: [], - end: true, - blacklist: [], // 'example.com' - categories: { - whitelist: { - totalRequests: config.whitelistRPH, - every: ONE_HOUR - }, - blacklist: { - totalRequests: config.blacklistRPH, - every: ONE_HOUR - }, - normal: { - totalRequests: config.normalRPH, - every: ONE_HOUR - } - } - })); -}; diff --git a/test/test.CredentialStore.js b/test/test.CredentialStore.js deleted file mode 100644 index 608453d2..00000000 --- a/test/test.CredentialStore.js +++ /dev/null @@ -1,101 +0,0 @@ -'use strict'; - -var chai = require('chai'); -var assert = require('assert'); -var sinon = require('sinon'); -var should = chai.should; -var expect = chai.expect; - -describe('credentialstore test', function() { - - var globalConfig = require('../config/config'); - var leveldb_stub = sinon.stub(); - leveldb_stub.post = sinon.stub(); - leveldb_stub.get = sinon.stub(); - var plugin = require('../plugins/credentialstore'); - var express_mock = null; - var request = null; - var response = null; - - beforeEach(function() { - - express_mock = sinon.stub(); - express_mock.post = sinon.stub(); - express_mock.get = sinon.stub(); - - plugin.init(express_mock, {db: leveldb_stub}); - - request = sinon.stub(); - request.on = sinon.stub(); - request.param = sinon.stub(); - response = sinon.stub(); - response.send = sinon.stub(); - response.status = sinon.stub(); - response.json = sinon.stub(); - response.end = sinon.stub(); - }); - - it('initializes correctly', function() { - assert(plugin.db === leveldb_stub); - assert(express_mock.post.calledWith( - globalConfig.apiPrefix + '/credentials', plugin.post - )); - assert(express_mock.get.calledWith( - globalConfig.apiPrefix + '/credentials/:username', plugin.get - )); - }); - - it('writes a message correctly', function() { - - var data = 'username=1&secret=2&record=3'; - request.on.onFirstCall().callsArgWith(1, data); - request.on.onFirstCall().returnsThis(); - request.on.onSecondCall().callsArg(1); - leveldb_stub.put = sinon.stub(); - - leveldb_stub.put.onFirstCall().callsArg(2); - response.json.returnsThis(); - - plugin.post(request, response); - - assert(leveldb_stub.put.firstCall.args[0] === 'credentials-store-12'); - assert(leveldb_stub.put.firstCall.args[1] === '3'); - assert(response.json.calledWith({success: true})); - }); - - it('retrieves a message correctly', function() { - - request.param.onFirstCall().returns('username'); - request.param.onSecondCall().returns('secret'); - - var returnValue = '!@#$%'; - leveldb_stub.get.onFirstCall().callsArgWith(1, null, returnValue); - response.send.returnsThis(); - - plugin.get(request, response); - - assert(leveldb_stub.get.firstCall.args[0] === 'credentials-store-usernamesecret'); - assert(response.send.calledWith(returnValue)); - assert(response.end.calledOnce); - }); - - it('fails with messages that are too long', function() { - - response.writeHead = sinon.stub(); - request.connection = {}; - request.connection.destroy = sinon.stub(); - var data = 'blob'; - for (var i = 0; i < 2048; i++) { - data += '----'; - } - request.on.onFirstCall().callsArgWith(1, data); - request.on.onFirstCall().returnsThis(); - response.writeHead.returnsThis(); - - plugin.post(request, response); - - assert(response.writeHead.calledWith(413, {'Content-Type': 'text/plain'})); - assert(response.end.calledOnce); - assert(request.connection.destroy.calledOnce); - }); -}); diff --git a/test/test.CurrencyRates.js b/test/test.CurrencyRates.js deleted file mode 100644 index ce225563..00000000 --- a/test/test.CurrencyRates.js +++ /dev/null @@ -1,265 +0,0 @@ -'use strict'; - -var chai = require('chai'); -var assert = require('assert'); -var sinon = require('sinon'); -var should = chai.should; -var expect = chai.expect; - -var levelup = require('levelup'); -var memdown = require('memdown'); -var logger = require('../lib/logger').logger; -logger.transports.console.level = 'non'; - -var rates = require('../plugins/currencyrates'); - -var db; - -describe('Rates service', function() { - beforeEach(function() { - db = levelup(memdown); - }); - - describe('#getRate', function() { - beforeEach(function() { - rates.init({ - db: db, - }); - }); - it('should get rate with exact ts', function(done) { - db.batch([{ - type: 'put', - key: 'bitpay-USD-10', - value: 123.45 - }, ]); - rates._getRate('bitpay', 'USD', 10, function(err, res) { - expect(err).to.not.exist; - res.rate.should.equal(123.45); - done(); - }); - }); - it('should get rate with approximate ts', function(done) { - db.batch([{ - type: 'put', - key: 'bitpay-USD-10', - value: 123.45, - }, { - type: 'put', - key: 'bitpay-USD-20', - value: 200.00, - }]); - rates._getRate('bitpay', 'USD', 25, function(err, res) { - res.rate.should.equal(200.00); - done(); - }); - }); - it('should return null when no rate found', function(done) { - db.batch([{ - type: 'put', - key: 'bitpay-USD-20', - value: 123.45, - }, { - type: 'put', - key: 'bitpay-USD-30', - value: 200.00, - }]); - rates._getRate('bitpay', 'USD', 10, function(err, res) { - expect(res.rate).to.be.null; - done(); - }); - }); - it('should get rate from specified source', function(done) { - db.batch([{ - type: 'put', - key: 'bitpay-USD-10', - value: 123.45, - }, { - type: 'put', - key: 'bitstamp-USD-10', - value: 200.00, - }]); - rates._getRate('bitpay', 'USD', 12, function(err, res) { - res.rate.should.equal(123.45); - done(); - }); - }); - it('should get rate for specified currency', function(done) { - db.batch([{ - type: 'put', - key: 'bitpay-USD-10', - value: 123.45, - }, { - type: 'put', - key: 'bitpay-EUR-10', - value: 200.00, - }]); - rates._getRate('bitpay', 'EUR', 12, function(err, res) { - res.rate.should.equal(200.00); - done(); - }); - }); - it('should get multiple rates', function(done) { - db.batch([{ - type: 'put', - key: 'bitpay-USD-10', - value: 100.00, - }, { - type: 'put', - key: 'bitpay-USD-20', - value: 200.00, - }, { - type: 'put', - key: 'bitstamp-USD-30', - value: 300.00, - }, { - type: 'put', - key: 'bitpay-USD-30', - value: 400.00, - }]); - rates._getRate('bitpay', 'USD', [10, 20, 35], function(err, res) { - expect(err).to.not.exist; - res.length.should.equal(3); - res[0].ts.should.equal(10); - res[1].ts.should.equal(20); - res[2].ts.should.equal(35); - res[0].rate.should.equal(100.00); - res[1].rate.should.equal(200.00); - res[2].rate.should.equal(400.00); - done(); - }); - }); - }); - - describe('#fetch', function() { - it('should fetch from all sources', function(done) { - var sources = []; - sources.push({ - id: 'id1', - url: 'http://dummy1', - parseFn: function(raw) { - return raw; - }, - }); - sources.push({ - id: 'id2', - url: 'http://dummy2', - parseFn: function(raw) { - return raw; - }, - }); - - var ds1 = [{ - code: 'USD', - rate: 123.45, - }, { - code: 'EUR', - rate: 200.00, - }]; - var ds2 = [{ - code: 'USD', - rate: 126.39, - }]; - - var request = sinon.stub(); - request.get = sinon.stub(); - request.get.withArgs({ - url: 'http://dummy1', - json: true - }).yields(null, null, ds1); - request.get.withArgs({ - url: 'http://dummy2', - json: true - }).yields(null, null, ds2); - - rates.init({ - db: db, - sources: sources, - request: request, - }); - - var clock = sinon.useFakeTimers(1400000000 * 1000); - - rates._fetch(function(err, res) { - clock.restore(); - - expect(err).to.not.exist; - - var result = []; - db.readStream() - .on('data', function(data) { - result.push(data); - }) - .on('close', function() { - result.length.should.equal(3); - result[0].key.should.equal('id1-EUR-1400000000'); - result[1].key.should.equal('id1-USD-1400000000'); - result[2].key.should.equal('id2-USD-1400000000'); - parseFloat(result[0].value).should.equal(200.00); - parseFloat(result[1].value).should.equal(123.45); - parseFloat(result[2].value).should.equal(126.39); - done(); - }); - }); - }); - - it('should not stop when failing to fetch source', function(done) { - var sources = []; - sources.push({ - id: 'id1', - url: 'http://dummy1', - parseFn: function(raw) { - return raw; - }, - }); - sources.push({ - id: 'id2', - url: 'http://dummy2', - parseFn: function(raw) { - return raw; - }, - }); - - var ds2 = [{ - code: 'USD', - rate: 126.39, - }]; - - var request = sinon.stub(); - request.get = sinon.stub(); - request.get.withArgs({ - url: 'http://dummy1', - json: true - }).yields('dummy error', null, null); - request.get.withArgs({ - url: 'http://dummy2', - json: true - }).yields(null, null, ds2); - - rates.init({ - db: db, - sources: sources, - request: request, - }); - - var clock = sinon.useFakeTimers(1400000000 * 1000); - - rates._fetch(function(err, res) { - clock.restore(); - - expect(err).to.not.exist; - - var result = []; - db.readStream() - .on('data', function(data) { - result.push(data); - }) - .on('close', function() { - result.length.should.equal(1); - result[0].key.should.equal('id2-USD-1400000000'); - parseFloat(result[0].value).should.equal(126.39); - done(); - }); - }); - }); - }); -}); diff --git a/test/test.EmailStore.js b/test/test.EmailStore.js deleted file mode 100644 index 16b5e2a6..00000000 --- a/test/test.EmailStore.js +++ /dev/null @@ -1,683 +0,0 @@ -'use strict'; - -var chai = require('chai'); -var assert = require('assert'); -var sinon = require('sinon'); -var crypto = require('crypto'); -var bitcore = require('bitcore'); -var logger = require('../lib/logger').logger; -var should = chai.should; -var expect = chai.expect; -var moment = require('moment'); - -logger.transports.console.level = 'non'; - -describe('emailstore test', function() { - - var globalConfig = require('../config/config'); - - // Mock components of plugin - var leveldb_stub = sinon.stub(); - leveldb_stub.put = sinon.stub(); - leveldb_stub.get = sinon.stub(); - leveldb_stub.del = sinon.stub(); - var email_stub = sinon.stub(); - email_stub.sendMail = sinon.stub().callsArg(1); - - var cryptoMock = { - randomBytes: sinon.stub() - }; - - var plugin = require('../plugins/emailstore'); - var express_mock = null; - var request = null; - var response = null; - - beforeEach(function() { - - plugin.init({ - db: leveldb_stub, - emailTransport: email_stub, - crypto: cryptoMock - }); - - request = sinon.stub(); - request.on = sinon.stub(); - request.param = sinon.stub(); - response = sinon.stub(); - response.send = sinon.stub(); - response.status = sinon.stub().returns({ - json: function() { - return { - end: function() { - } - } - } - }); - response.json = sinon.stub(); - response.end = sinon.stub(); - response.redirect = sinon.stub(); - }); - - it('initializes correctly', function() { - assert(plugin.db === leveldb_stub); - }); - - describe('database queries', function() { - - describe('exists', function() { - var fakeEmail = 'fake@email.com'; - var fakeEmailKey = 'email-to-passphrase-' + bitcore.util.twoSha256(fakeEmail).toString('hex'); - - beforeEach(function() { - leveldb_stub.get.reset(); - }); - - it('validates that an email is already registered', function(done) { - leveldb_stub.get.onFirstCall().callsArg(1); - - plugin.exists(fakeEmail, function(err, exists) { - leveldb_stub.get.firstCall.args[0].should.equal(fakeEmailKey); - exists.should.equal(true); - done(); - }); - }); - - it('returns false when an email doesn\'t exist', function(done) { - leveldb_stub.get.onFirstCall().callsArgWith(1, { - notFound: true - }); - - plugin.exists(fakeEmail, function(err, exists) { - leveldb_stub.get.firstCall.args[0].should.equal(fakeEmailKey); - exists.should.equal(false); - done(); - }); - }); - - it('returns an internal error if database query couldn\'t be made', function(done) { - leveldb_stub.get.onFirstCall().callsArgWith(1, 'error'); - plugin.exists(fakeEmail, function(err, exists) { - err.should.equal(plugin.errors.INTERNAL_ERROR); - done(); - }); - }); - }); - - describe('passphrase', function() { - var fakeEmail = 'fake@email.com'; - var fakePassphrase = 'secretPassphrase123'; - - beforeEach(function() { - leveldb_stub.get.reset(); - leveldb_stub.put.reset(); - }); - - it('returns true if passphrase matches', function(done) { - leveldb_stub.get.onFirstCall().callsArgWith(1, null, fakePassphrase); - - plugin.checkPassphrase(fakeEmail, fakePassphrase, function(err, result) { - result.should.equal(true); - done(); - }); - }); - - it('returns false if passphrsase doesn\'t match', function(done) { - leveldb_stub.get.onFirstCall().callsArgWith(1, null, 'invalid passphrase'); - - plugin.checkPassphrase(fakeEmail, fakePassphrase, function(err, result) { - result.should.equal(false); - done(); - }); - }); - - it('returns an internal error if database query couldn\'t be made', function(done) { - leveldb_stub.get.onFirstCall().callsArgWith(1, 'error'); - - plugin.checkPassphrase(fakeEmail, fakePassphrase, function(err) { - err.should.equal(plugin.errors.INTERNAL_ERROR); - done(); - }); - }); - - it('stores passphrase correctly', function(done) { - leveldb_stub.put.onFirstCall().callsArg(2); - - plugin.savePassphrase(fakeEmail, fakePassphrase, function(err) { - expect(err).to.equal(null); - done(); - }); - }); - - it('doesn\'t store the email in the key', function(done) { - leveldb_stub.put.onFirstCall().callsArg(2); - - plugin.savePassphrase(fakeEmail, fakePassphrase, function(err) { - leveldb_stub.put.firstCall.args[0].should.not.contain(fakeEmail); - done(); - }); - }); - - it('returns internal error on database error', function(done) { - leveldb_stub.put.onFirstCall().callsArgWith(2, 'error'); - - plugin.savePassphrase(fakeEmail, fakePassphrase, function(err) { - err.should.equal(plugin.errors.INTERNAL_ERROR); - done(); - }); - }); - }); - - describe('saving encrypted data', function() { - var fakeEmail = 'fake@email.com'; - var fakeKey = 'nameForData'; - var fakeRecord = 'fakeRecord'; - var expectedKey = 'emailstore-' + bitcore.util.twoSha256(fakeEmail + '#' + fakeKey).toString('hex'); - - beforeEach(function() { - leveldb_stub.get.reset(); - leveldb_stub.put.reset(); - }); - - it('saves data under the expected key', function(done) { - leveldb_stub.put.onFirstCall().callsArgWith(2); - - plugin.saveEncryptedData(fakeEmail, fakeKey, fakeRecord, function(err) { - leveldb_stub.put.firstCall.args[0].should.equal(expectedKey); - done(); - }); - }); - - it('fails with INTERNAL_ERROR on database error', function(done) { - leveldb_stub.put.onFirstCall().callsArgWith(2, 'error'); - - plugin.saveEncryptedData(fakeEmail, fakeKey, fakeRecord, function(err) { - err.should.equal(plugin.errors.INTERNAL_ERROR); - done(); - }); - }); - }); - - describe('creating verification secret', function() { - var fakeEmail = 'fake@email.com'; - var fakeRandom = 'fakerandom'; - var randomBytes = { - toString: function() { - return fakeRandom; - } - }; - - beforeEach(function() { - leveldb_stub.get.reset(); - leveldb_stub.put.reset(); - plugin.email.sendMail.reset(); - - cryptoMock.randomBytes = sinon.stub(); - cryptoMock.randomBytes.onFirstCall().returns(randomBytes); - }); - - var setupLevelDb = function() { - leveldb_stub.get.onFirstCall().callsArgWith(1, { - notFound: true - }); - leveldb_stub.put.onFirstCall().callsArg(2); - }; - - it('saves data under the expected key', function(done) { - setupLevelDb(); - var clock = sinon.useFakeTimers(); - plugin.createVerificationSecretAndSendEmail(fakeEmail, function(err) { - var arg = JSON.parse(leveldb_stub.put.firstCall.args[1]); - arg.secret.should.equal(fakeRandom); - arg.created.should.equal(moment().unix()); - clock.restore(); - done(); - }); - }); - it('sends verification email', function(done) { - setupLevelDb(); - - plugin.createVerificationSecretAndSendEmail(fakeEmail, function(err) { - plugin.email.sendMail.calledOnce.should.be.true; - done(); - }); - }); - it('returns internal error on put database error', function(done) { - leveldb_stub.get.onFirstCall().callsArgWith(1, { - notFound: true - }); - leveldb_stub.put.onFirstCall().callsArgWith(2, 'error'); - plugin.createVerificationSecretAndSendEmail(fakeEmail, function(err) { - err.should.equal(plugin.errors.INTERNAL_ERROR); - done(); - }); - }); - it('returns internal error on get database error', function(done) { - leveldb_stub.get.onFirstCall().callsArgWith(1, 'error'); - plugin.createVerificationSecretAndSendEmail(fakeEmail, function(err) { - err.should.equal(plugin.errors.INTERNAL_ERROR); - done(); - }); - }); - }); - }); - - describe('on registration', function() { - var emailParam = 'email'; - var secretParam = 'secret'; - var keyParam = 'key'; - var recordParam = 'record'; - beforeEach(function() { - var data = ('email=' + emailParam + '&secret=' + secretParam + '&record=' + recordParam + '&key=' + keyParam); - request.on.onFirstCall().callsArgWith(1, data); - request.on.onFirstCall().returnsThis(); - request.on.onSecondCall().callsArg(1); - response.json.returnsThis(); - }); - - it('should allow new registrations', function() { - var originalCredentials = plugin.getCredentialsFromRequest; - plugin.getCredentialsFromRequest = sinon.mock(); - plugin.getCredentialsFromRequest.onFirstCall().returns({ - email: emailParam, - passphrase: secretParam - }); - plugin.exists = sinon.stub(); - plugin.exists.onFirstCall().callsArgWith(1, null, false); - plugin.savePassphrase = sinon.stub(); - plugin.savePassphrase.onFirstCall().callsArg(2); - plugin.isConfirmed = sinon.stub(); - plugin.isConfirmed.onFirstCall().callsArgWith(1, null, false); - plugin.checkSizeQuota = sinon.stub(); - plugin.checkSizeQuota.onFirstCall().callsArgWith(3, null); - plugin.checkAndUpdateItemQuota = sinon.stub(); - plugin.checkAndUpdateItemQuota.onFirstCall().callsArgWith(3, null); - plugin.saveEncryptedData = sinon.stub(); - plugin.saveEncryptedData.onFirstCall().callsArg(3); - plugin.createVerificationSecretAndSendEmail = sinon.stub(); - plugin.createVerificationSecretAndSendEmail.onFirstCall().callsArg(1); - response.send.onFirstCall().returnsThis(); - - plugin.save(request, response); - - assert(plugin.exists.firstCall.args[0] === emailParam); - assert(plugin.savePassphrase.firstCall.args[0] === emailParam); - assert(plugin.savePassphrase.firstCall.args[1] === secretParam); - assert(plugin.saveEncryptedData.firstCall.args[0] === emailParam); - assert(plugin.saveEncryptedData.firstCall.args[1] === keyParam); - assert(plugin.saveEncryptedData.firstCall.args[2] === recordParam); - assert(plugin.createVerificationSecretAndSendEmail.firstCall.args[0] === emailParam); - plugin.getCredentialsFromRequest = originalCredentials; - }); - - it('should allow to overwrite data', function() { - var originalCredentials = plugin.getCredentialsFromRequest; - plugin.getCredentialsFromRequest = sinon.mock(); - plugin.getCredentialsFromRequest.onFirstCall().returns({ - email: emailParam, - passphrase: secretParam - }); - plugin.exists = sinon.stub(); - plugin.exists.onFirstCall().callsArgWith(1, null, true); - plugin.checkPassphrase = sinon.stub(); - plugin.checkPassphrase.onFirstCall().callsArgWith(2, null, true); - plugin.isConfirmed = sinon.stub(); - plugin.isConfirmed.onFirstCall().callsArgWith(1, null, false); - plugin.checkSizeQuota = sinon.stub(); - plugin.checkSizeQuota.onFirstCall().callsArgWith(3, null); - plugin.checkAndUpdateItemQuota = sinon.stub(); - plugin.checkAndUpdateItemQuota.onFirstCall().callsArgWith(3, null); - plugin.saveEncryptedData = sinon.stub(); - plugin.saveEncryptedData.onFirstCall().callsArg(3); - plugin.createVerificationSecretAndSendEmail = sinon.stub(); - response.send.onFirstCall().returnsThis(); - - plugin.save(request, response); - - assert(plugin.exists.firstCall.args[0] === emailParam); - assert(plugin.checkPassphrase.firstCall.args[0] === emailParam); - assert(plugin.checkPassphrase.firstCall.args[1] === secretParam); - assert(plugin.saveEncryptedData.firstCall.args[0] === emailParam); - assert(plugin.saveEncryptedData.firstCall.args[1] === keyParam); - assert(plugin.saveEncryptedData.firstCall.args[2] === recordParam); - plugin.createVerificationSecretAndSendEmail.called.should.be.false; - plugin.getCredentialsFromRequest = originalCredentials; - }); - - it('should delete profile on error sending verification email', function() { - var originalCredentials = plugin.getCredentialsFromRequest; - plugin.getCredentialsFromRequest = sinon.mock(); - plugin.getCredentialsFromRequest.onFirstCall().returns({ - email: emailParam, - passphrase: secretParam - }); - plugin.exists = sinon.stub(); - plugin.exists.onFirstCall().callsArgWith(1, null, false); - plugin.savePassphrase = sinon.stub(); - plugin.savePassphrase.onFirstCall().callsArg(2); - plugin.isConfirmed = sinon.stub(); - plugin.isConfirmed.onFirstCall().callsArgWith(1, null, false); - plugin.checkSizeQuota = sinon.stub(); - plugin.checkSizeQuota.onFirstCall().callsArgWith(3, null); - plugin.checkAndUpdateItemQuota = sinon.stub(); - plugin.checkAndUpdateItemQuota.onFirstCall().callsArgWith(3, null); - plugin.saveEncryptedData = sinon.stub(); - plugin.saveEncryptedData.onFirstCall().callsArg(3); - plugin.createVerificationSecretAndSendEmail = sinon.stub(); - plugin.createVerificationSecretAndSendEmail.onFirstCall().callsArgWith(1, 'error'); - var deleteWholeProfile = sinon.stub(plugin, 'deleteWholeProfile'); - deleteWholeProfile.onFirstCall().callsArg(1); - response.send.onFirstCall().returnsThis(); - - plugin.save(request, response); - - assert(plugin.exists.firstCall.args[0] === emailParam); - assert(plugin.savePassphrase.firstCall.args[0] === emailParam); - assert(plugin.savePassphrase.firstCall.args[1] === secretParam); - assert(plugin.saveEncryptedData.firstCall.args[0] === emailParam); - assert(plugin.saveEncryptedData.firstCall.args[1] === keyParam); - assert(plugin.saveEncryptedData.firstCall.args[2] === recordParam); - assert(plugin.createVerificationSecretAndSendEmail.firstCall.args[0] === emailParam); - assert(deleteWholeProfile.firstCall.args[0] === emailParam); - plugin.getCredentialsFromRequest = originalCredentials; - }); - - after(function () { - plugin.deleteWholeProfile.restore(); - }); - }); - - describe('when validating email', function() { - - var email = '1'; - var secret = '2'; - beforeEach(function() { - - request.param.onFirstCall().returns(email); - request.param.onSecondCall().returns(secret); - leveldb_stub.put = sinon.stub(); - leveldb_stub.get = sinon.stub(); - leveldb_stub.put.onFirstCall().callsArg(2); - leveldb_stub.del.onFirstCall().callsArg(1); - response.json.returnsThis(); - }); - - it('should validate correctly an email if the secret matches (secret only)', function() { - leveldb_stub.get.onFirstCall().callsArgWith(1, null, secret); - leveldb_stub.del = sinon.stub().yields(null); - response.redirect = sinon.stub(); - - plugin.validate(request, response); - - assert(response.redirect.firstCall.calledWith(plugin.redirectUrl)); - }); - - it('should validate correctly an email if the secret matches (secret + creation date)', function() { - leveldb_stub.get.onFirstCall().callsArgWith(1, null, JSON.stringify({ - secret: secret, - created: moment().unix(), - })); - leveldb_stub.del = sinon.stub().yields(null); - response.redirect = sinon.stub(); - - plugin.validate(request, response); - - assert(response.redirect.firstCall.calledWith(plugin.redirectUrl)); - }); - - it('should fail to validate an email if the secret doesn\'t match', function() { - var invalid = '3'; - leveldb_stub.get.onFirstCall().callsArgWith(1, null, invalid); - response.status.returnsThis(); - response.json.returnsThis(); - - plugin.validate(request, response); - - assert(response.status.firstCall.calledWith(plugin.errors.INVALID_CODE.code)); - assert(response.json.firstCall.calledWith({ - error: 'The provided code is invalid' - })); - assert(response.end.calledOnce); - }); - }); - - describe('resend validation email', function () { - var email = 'fake@email.com'; - var secret = '123'; - beforeEach(function() { - leveldb_stub.get.reset(); - request.param.onFirstCall().returns(email); - response.json.returnsThis(); - response.redirect = sinon.stub(); - }); - - it('should resend validation email when pending', function () { - plugin.authorizeRequestWithoutKey = sinon.stub().callsArgWith(1, null, email); - leveldb_stub.get.onFirstCall().callsArgWith(1, null, JSON.stringify({ secret: secret, created: new Date() })); - plugin.sendVerificationEmail = sinon.spy(); - plugin.resendEmail(request, response); - plugin.sendVerificationEmail.calledOnce.should.be.true; - plugin.sendVerificationEmail.calledWith(email, secret).should.be.true; - }); - - it('should resend validation email when pending (old style secret)', function () { - plugin.authorizeRequestWithoutKey = sinon.stub().callsArgWith(1, null, email); - leveldb_stub.get.onFirstCall().callsArgWith(1, null, secret); - plugin.sendVerificationEmail = sinon.spy(); - plugin.resendEmail(request, response); - plugin.sendVerificationEmail.calledOnce.should.be.true; - plugin.sendVerificationEmail.calledWith(email, secret).should.be.true; - }); - - it('should not resend when email is no longer pending', function () { - plugin.authorizeRequestWithoutKey = sinon.stub().callsArgWith(1, null, email); - leveldb_stub.get.onFirstCall().callsArgWith(1, { notFound: true }); - plugin.sendVerificationEmail = sinon.spy(); - plugin.resendEmail(request, response); - plugin.sendVerificationEmail.should.not.be.called; - }); - }); - - describe('removing items', function() { - var fakeEmail = 'fake@email.com'; - var fakeKey = 'nameForData'; - beforeEach(function() { - leveldb_stub.del = sinon.stub(); - }); - it('deletes a stored element (key)', function(done) { - leveldb_stub.del.onFirstCall().callsArg(1); - - plugin.checkAndUpdateItemCounter = sinon.stub(); - plugin.checkAndUpdateItemCounter.onFirstCall().callsArg(3); - - plugin.deleteByEmailAndKey(fakeEmail, fakeKey, function(err) { - expect(err).to.be.undefined; - done(); - }); - }); - it('returns NOT FOUND if trying to delete a stored element by key', function(done) { - leveldb_stub.del.onFirstCall().callsArgWith(1, {notFound: true}); - plugin.deleteByEmailAndKey(fakeEmail, fakeKey, function(err) { - err.should.equal(plugin.errors.NOT_FOUND); - done(); - }); - }); - it('returns INTERNAL_ERROR if an unexpected error ocurrs', function(done) { - leveldb_stub.del.onFirstCall().callsArgWith(1, {unexpected: true}); - plugin.deleteByEmailAndKey(fakeEmail, fakeKey, function(err) { - err.should.equal(plugin.errors.INTERNAL_ERROR); - done(); - }); - }); - it('can delete a whole profile (validation data and passphrase)', function(done) { - leveldb_stub.del.callsArg(1); - plugin.deleteWholeProfile(fakeEmail, function(err) { - expect(err).to.be.undefined; - leveldb_stub.del.callCount.should.equal(3); - done(); - }); - }); - it('dismisses not found errors', function(done) { - leveldb_stub.del.callsArg(1); - leveldb_stub.del.onSecondCall().callsArgWith(1, {notFound: true}); - plugin.deleteWholeProfile(fakeEmail, function(err) { - expect(err).to.be.undefined; - done(); - }); - }); - it('returns internal error if something goes awry', function(done) { - leveldb_stub.del.callsArg(1); - leveldb_stub.del.onSecondCall().callsArgWith(1, {unexpected: true}); - plugin.deleteWholeProfile(fakeEmail, function(err) { - err.should.equal(plugin.errors.INTERNAL_ERROR); - done(); - }); - }); - }); - - describe('when retrieving data', function() { - - it('should validate the secret and return the data', function() { - request.param.onFirstCall().returns('key'); - - plugin.authorizeRequestWithKey = sinon.stub().callsArgWith(1,null, 'email','key'); - plugin.retrieveByEmailAndKey = sinon.stub().yields(null, 'encrypted'); - - response.send.onFirstCall().returnsThis(); - plugin.addValidationHeader = sinon.stub().callsArg(2); - plugin.addValidationAndQuotaHeader = sinon.stub().callsArg(2); - - plugin.retrieve(request, response); - - response.send.calledOnce.should.equal(true); - - assert(plugin.retrieveByEmailAndKey.firstCall.args[0] === 'email'); - assert(plugin.retrieveByEmailAndKey.firstCall.args[1] === 'key'); - assert(response.send.firstCall.args[0] === 'encrypted'); - assert(response.end.calledOnce); - }); - }); - - - describe('authorizing requests', function() { - var originalCredentials; - beforeEach(function() { - originalCredentials = plugin.getCredentialsFromRequest; - - plugin.getCredentialsFromRequest = sinon.mock(); - plugin.getCredentialsFromRequest.onFirstCall().returns({ - email: 'email', - passphrase: 'pass' - }); - request.param.onFirstCall().returns('key'); - - request.on = sinon.stub(); - request.on.onFirstCall().callsArgWith(1, 'newPassphrase=newPassphrase'); - request.on.onFirstCall().returns(request); - request.on.onSecondCall().callsArg(1); - plugin.checkPassphrase = sinon.stub().callsArgWith(2,null, true); - - }); - - it('should authorize a request', function(done){ - plugin.authorizeRequest(request, false, function(err, email, key) { - expect(err).to.be.null; - expect(key).to.be.undefined; - email.should.be.equal('email'); - done(); - }); - }); - it('should authorize a request with key', function(done){ - plugin.getCredentialsFromRequest.onFirstCall().returns({ - email: 'email', - passphrase: 'pass', - }); - plugin.authorizeRequest(request, true, function(err, email, key) { - expect(err).to.be.null; - email.should.be.equal('email'); - key.should.be.equal('key'); - done(); - }); - }); - - it('should not authorize a request when param are missing', function(done){ - plugin.getCredentialsFromRequest.onFirstCall().returns({ - email: 'email', - }); - - plugin.authorizeRequest(request, false, function(err, email, key) { - expect(err).not.to.be.null; - expect(key).to.be.undefined; - expect(email).to.be.undefined; - done(); - }); - }); - it('should not authorize a request when param are missing (case2)', function(done){ - plugin.getCredentialsFromRequest.onFirstCall().returns({ - passphrase: 'pass' - }); - - plugin.authorizeRequest(request, false, function(err, email, key) { - expect(err).not.to.be.null; - expect(key).to.be.undefined; - expect(email).to.be.undefined; - done(); - }); - }); - it('should not authorize a request when param are missing (case3)', function(done){ - request.param.onFirstCall().returns(undefined); - plugin.getCredentialsFromRequest.onFirstCall().returns({ - email: 'email', - passphrase: 'pass' - }); - plugin.authorizeRequest(request, true, function(err, email, key) { - expect(err).not.to.be.null; - expect(key).to.be.undefined; - expect(email).to.be.undefined; - done(); - }); - }); - - - after(function() { - plugin.getCredentialsFromRequest = originalCredentials; - }); - }); - - describe('changing the user password', function() { - - - beforeEach(function() { - request.on = sinon.stub(); - request.on.onFirstCall().callsArgWith(1, 'newPassphrase=newPassphrase'); - request.on.onFirstCall().returns(request); - request.on.onSecondCall().callsArg(1); - response.status.onFirstCall().returnsThis(); - plugin.checkPassphrase = sinon.stub(); - plugin.savePassphrase = sinon.stub(); - }); - - it('should validate the previous passphrase', function() { - response.status.onFirstCall().returnsThis(); - response.json.onFirstCall().returnsThis(); - plugin.authorizeRequestWithoutKey = sinon.stub().callsArgWith(1,'error'); - - plugin.changePassphrase(request, response); - - assert(response.status.calledOnce); - assert(response.json.calledOnce); - assert(response.end.calledOnce); - }); - - it('should change the passphrase', function() { - response.json.onFirstCall().returnsThis(); - plugin.authorizeRequestWithoutKey = sinon.stub().callsArgWith(1,null, 'email'); - plugin.checkPassphrase.onFirstCall().callsArgWith(2, null); - plugin.savePassphrase.onFirstCall().callsArgWith(2, null); - - plugin.changePassphrase(request, response); - assert(response.json.calledOnce); - assert(response.end.calledOnce); - }); - }); -}); diff --git a/test/test.MessageDb.js b/test/test.MessageDb.js deleted file mode 100644 index 960fc849..00000000 --- a/test/test.MessageDb.js +++ /dev/null @@ -1,133 +0,0 @@ -'use strict'; - -var chai = require('chai'); -var should = chai.should; -var expect = chai.expect; - -var levelup = require('levelup'); -var memdown = require('memdown'); -var microtime = require('microtime'); -var MessageDb = require('../lib/MessageDb'); -var bitcore = require('bitcore'); -var SIN = bitcore.SIN; -var Key = bitcore.Key; -var AuthMessage = bitcore.AuthMessage; - -describe('MessageDb', function() { - var opts = { - name: 'test-MessageDb', - db: levelup({ - db: memdown, - sync: true, - valueEncoding: 'json' - }) - }; - it('should be able to create instance', function() { - var mdb = new MessageDb(opts); - expect(mdb).to.exist; - }); - it('should be able to create default instance', function() { - var mdb = MessageDb.default(); - expect(mdb).to.exist; - }); - var fpk = Key.generateSync(); - var tpk = Key.generateSync(); - var from = fpk.public.toString('hex'); - var to = tpk.public.toString('hex'); - var messageData = { - a: 1, - b: 2 - }; - var messageData2 = {}; - var messageData3 = ['a', 'b']; - var message = AuthMessage.encode(to, fpk, messageData); - var message2 = AuthMessage.encode(to, fpk, messageData2); - var message3 = AuthMessage.encode(to, fpk, messageData3); - it('should be able to add and read a message', function(done) { - var mdb = new MessageDb(opts); - var lower_ts = microtime.now(); - mdb.addMessage(message, function(err) { - expect(err).to.not.exist; - var upper_ts = microtime.now(); - mdb.getMessages(to, lower_ts, upper_ts, function(err, messages) { - expect(err).to.not.exist; - messages.length.should.equal(1); - messages[0].ts.should.be.below(upper_ts); - messages[0].ts.should.be.above(lower_ts); - var m = AuthMessage.decode(tpk, messages[0]).payload; - m.a.should.equal(1); - m.b.should.equal(2); - done(); - }); - }); - }); - var sharedMDB; - it('should be able to add many messages and read some', function(done) { - var mdb = new MessageDb(opts); - sharedMDB = mdb; - var lower_ts = microtime.now(); - mdb.addMessage(message, function(err) { - expect(err).to.not.exist; - mdb.addMessage(message2, function(err) { - expect(err).to.not.exist; - var upper_ts = microtime.now(); - setTimeout(function() { - mdb.addMessage(message3, function(err) { - expect(err).to.not.exist; - mdb.getMessages(to, lower_ts, upper_ts, function(err, messages) { - expect(err).to.not.exist; - messages.length.should.equal(2); - messages[0].ts.should.be.below(upper_ts); - messages[0].ts.should.be.above(lower_ts); - var m0 = AuthMessage.decode(tpk, messages[0]).payload; - JSON.stringify(m0).should.equal('{"a":1,"b":2}'); - messages[1].ts.should.be.below(upper_ts); - messages[1].ts.should.be.above(lower_ts); - var m1 = AuthMessage.decode(tpk, messages[1]).payload; - JSON.stringify(m1).should.equal('{}'); - done(); - }); - }); - }, 10); - }); - }); - }); - it('should be able to add many messages and read all', function(done) { - var mdb = sharedMDB; - mdb.getMessages(to, null, null, function(err, messages) { - expect(err).to.not.exist; - messages.length.should.equal(4); - var m0 = AuthMessage.decode(tpk, messages[0]).payload; - JSON.stringify(m0).should.equal('{"a":1,"b":2}'); - var m1 = AuthMessage.decode(tpk, messages[1]).payload; - JSON.stringify(m1).should.equal('{"a":1,"b":2}'); - var m2 = AuthMessage.decode(tpk, messages[2]).payload; - JSON.stringify(m2).should.equal('{}'); - var m3 = AuthMessage.decode(tpk, messages[3]).payload; - JSON.stringify(m3).should.equal('["a","b"]'); - done(); - }); - }); - it('should be able #removeUpTo', function(done) { - var mdb = sharedMDB; - var upper_ts = microtime.now(); - mdb.addMessage(message, function(err) { - expect(err).to.not.exist; - mdb.removeUpTo(upper_ts, function(err, n) { - expect(err).to.not.exist; - n.should.equal(4); - mdb.getAll(function(error, all) { - expect(error).to.not.exist; - all.length.should.equal(1); - done(); - }); - - }); - }); - }); - it('should be able to close instance', function() { - var mdb = new MessageDb(opts); - mdb.close(); - expect(mdb).to.exist; - }); -}); diff --git a/test/test.PublicProfile.js b/test/test.PublicProfile.js deleted file mode 100644 index 5444b2e7..00000000 --- a/test/test.PublicProfile.js +++ /dev/null @@ -1,113 +0,0 @@ -'use strict'; - -var chai = require('chai'); -var assert = require('assert'); -var sinon = require('sinon'); -var should = chai.should; -var expect = chai.expect; -var bitauth = require('bitauth'); - -describe('public profile test', function() { - - var globalConfig = require('../config/config'); - var leveldb_stub = sinon.stub(); - leveldb_stub.put = sinon.stub(); - leveldb_stub.get = sinon.stub(); - var plugin = require('../plugins/publicInfo/publicInfo.js'); - var express_mock = null; - var request = null; - var response = null; - - beforeEach(function() { - - express_mock = sinon.stub(); - express_mock.post = sinon.stub(); - express_mock.get = sinon.stub(); - - plugin.init(express_mock, {db: leveldb_stub}); - - request = sinon.stub(); - request.on = sinon.stub(); - request.param = sinon.stub(); - response = sinon.stub(); - response.send = sinon.stub(); - response.status = sinon.stub(); - response.json = sinon.stub(); - response.end = sinon.stub(); - }); - - it('initializes correctly', function() { - assert(plugin.db === leveldb_stub); - assert(express_mock.post.calledWith( - globalConfig.apiPrefix + '/public', plugin.post - )); - assert(express_mock.get.calledWith( - globalConfig.apiPrefix + '/public/:sin', plugin.get - )); - }); - - it('writes a message correctly', function(done) { - - var privateKey = bitauth.generateSin(); - var protocol = 'https'; - var dataToSign = protocol + '://hosturlSTUFF'; - var signature = bitauth.sign(dataToSign, privateKey.priv); - request.get = function() { return 'host'; }; - request.protocol = protocol; - request.url = 'url'; - request.headers = { - 'x-identity': privateKey.pub, - 'x-signature': signature - }; - request.on.onFirstCall().callsArgWith(1, 'STUFF'); - request.on.onFirstCall().returnsThis(); - request.on.onSecondCall().callsArg(1); - - leveldb_stub.put.onFirstCall().callsArg(2); - response.status.returns(response); - response.json.returns(response); - - request.testCallback = function() { - assert(leveldb_stub.put.firstCall.args[0] === 'public-info-' + privateKey.sin); - assert(leveldb_stub.put.firstCall.args[1] === 'STUFF'); - assert(response.json.calledOnce); - assert(response.end.calledOnce); - done(); - }; - - plugin.post(request, response); - }); - - it('fails if the signature is invalid', function() { - var data = 'uecord3'; - request.get = function() { return ''; }; - request.headers = {}; - request.on.onFirstCall().callsArgWith(1, data); - request.on.onFirstCall().returnsThis(); - request.on.onSecondCall().callsArg(1); - leveldb_stub.put = sinon.stub(); - - leveldb_stub.put.onFirstCall().callsArg(2); - response.json.returnsThis(); - response.status.returnsThis(); - - plugin.post(request, response); - - assert(response.end.calledOnce); - }); - - it('retrieves a message correctly', function() { - - request.param.onFirstCall().returns('SIN'); - - var returnValue = '!@#$%'; - leveldb_stub.get.onFirstCall().callsArgWith(1, null, returnValue); - response.send.returnsThis(); - - plugin.get(request, response); - - assert(leveldb_stub.get.firstCall.args[0] === 'public-info-SIN'); - assert(response.send.calledWith(returnValue)); - assert(response.end.calledOnce); - }); -}); diff --git a/test/test.socket-server.js b/test/test.socket-server.js deleted file mode 100644 index 6920889c..00000000 --- a/test/test.socket-server.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict'; - -var chai = require('chai'); -var should = chai.should; -var expect = chai.expect; -var sinon = require('sinon'); - -var socket = require('../app/controllers/socket'); -var bitcore = require('bitcore'); -var EventEmitter = require('events').EventEmitter; - -describe('socket server', function() { - it('should be able to call init with no args', function() { - socket.init.should.not.throw(); - }); - it('should register socket handlers', function() { - var io = { - sockets: new EventEmitter(), - } - socket.init(io); - - var mockSocket = {}; - mockSocket.on = sinon.spy(); - io.sockets.emit('connection', mockSocket); - mockSocket.on.calledWith('subscribe'); - mockSocket.on.calledWith('sync'); - mockSocket.on.calledWith('message'); - }); - -});