Merge pull request #1737 from eordano/fix/passphrase
Passphrase getting generated correctly
This commit is contained in:
commit
e8a376cf31
5 changed files with 242 additions and 10 deletions
|
|
@ -1,8 +1,11 @@
|
|||
var request = require('request');
|
||||
var cryptoUtil = require('../util/crypto');
|
||||
var buffers = require('buffer');
|
||||
var querystring = require('querystring');
|
||||
var Identity = require('../models/Identity');
|
||||
|
||||
var SEPARATOR = '|';
|
||||
|
||||
function InsightStorage(config) {
|
||||
this.type = 'DB';
|
||||
this.storeUrl = config.url || 'https://test-insight.bitpay.com:443/api/email';
|
||||
|
|
@ -14,10 +17,12 @@ InsightStorage.prototype.init = function () {};
|
|||
InsightStorage.prototype.setCredentials = function(email, password, opts) {
|
||||
this.email = email;
|
||||
this.password = password;
|
||||
this._cachedKey = null;
|
||||
};
|
||||
|
||||
InsightStorage.prototype.createItem = function(name, value, callback) {
|
||||
var self = this;
|
||||
|
||||
this.getItem(name, function(err, retrieved) {
|
||||
if (err || !retrieved) {
|
||||
return self.setItem(name, value, callback);
|
||||
|
|
@ -27,12 +32,34 @@ InsightStorage.prototype.createItem = function(name, value, callback) {
|
|||
});
|
||||
};
|
||||
|
||||
function mayBeOldPassword(password) {
|
||||
// Test for base64
|
||||
return /^[a-zA-Z0-9\/=\+]+$/.test(password);
|
||||
}
|
||||
|
||||
InsightStorage.prototype.getItem = function(name, callback) {
|
||||
var key = cryptoUtil.kdf(this.password + this.email);
|
||||
var secret = cryptoUtil.kdf(key, this.password);
|
||||
var encodedEmail = encodeURIComponent(this.email);
|
||||
var retrieveUrl = this.storeUrl + '/retrieve/' + encodedEmail;
|
||||
this.request.get(retrieveUrl + '?' + querystring.encode({secret: secret, key: name}),
|
||||
var passphrase = this.getPassphrase();
|
||||
var self = this;
|
||||
|
||||
this._makeGetRequest(passphrase, name, function(err, body) {
|
||||
if (err && err.indexOf('PNOTFOUND') !== -1 && mayBeOldPassword(self.password)) {
|
||||
return self._brokenGetItem(name, callback);
|
||||
}
|
||||
return callback(err, body);
|
||||
});
|
||||
};
|
||||
|
||||
InsightStorage.prototype.getPassphrase = function() {
|
||||
return cryptoUtil.hmac(this.getKey(), this.password);
|
||||
};
|
||||
|
||||
InsightStorage.prototype._makeGetRequest = function(passphrase, key, callback) {
|
||||
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
|
||||
var retrieveUrl = this.storeUrl + '/retrieve';
|
||||
this.request.get({
|
||||
url: retrieveUrl + '?' + querystring.encode({key: key}),
|
||||
headers: {'Authorization': authHeader}
|
||||
},
|
||||
function(err, response, body) {
|
||||
if (err) {
|
||||
return callback('Connection error');
|
||||
|
|
@ -48,16 +75,69 @@ InsightStorage.prototype.getItem = function(name, callback) {
|
|||
);
|
||||
};
|
||||
|
||||
InsightStorage.prototype.setItem = function(name, value, callback) {
|
||||
InsightStorage.prototype._brokenGetItem = function(name, callback) {
|
||||
var passphrase = this._makeBrokenSecret();
|
||||
var self = this;
|
||||
this._makeGetRequest(passphrase, name, function(err, body) {
|
||||
if (!err) {
|
||||
return self._changePassphrase(function(err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
return callback(null, body);
|
||||
});
|
||||
}
|
||||
return callback(err);
|
||||
});
|
||||
};
|
||||
|
||||
InsightStorage.prototype.getKey = function() {
|
||||
if (!this._cachedKey) {
|
||||
this._cachedKey = cryptoUtil.kdf(this.password + SEPARATOR + this.email);
|
||||
}
|
||||
return this._cachedKey;
|
||||
};
|
||||
|
||||
InsightStorage.prototype._makeBrokenSecret = function() {
|
||||
var key = cryptoUtil.kdf(this.password + this.email);
|
||||
var secret = cryptoUtil.kdf(key, this.password);
|
||||
var registerUrl = this.storeUrl + '/register';
|
||||
return cryptoUtil.kdf(key, this.password);
|
||||
};
|
||||
|
||||
InsightStorage.prototype._changePassphrase = function(callback) {
|
||||
var passphrase = this._makeBrokenSecret();
|
||||
var newPassphrase = this.getPassphrase();
|
||||
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
|
||||
|
||||
var url = this.storeUrl + '/change_passphrase';
|
||||
this.request.post({
|
||||
url: url,
|
||||
headers: {'Authorization': authHeader},
|
||||
body: querystring.encode({
|
||||
newPassphrase: newPassphrase
|
||||
})
|
||||
}, function(err, response, body) {
|
||||
if (err) {
|
||||
return callback('Connection error');
|
||||
}
|
||||
if (response.statusCode === 409) {
|
||||
return callback('BADCREDENTIALS: Invalid username or password');
|
||||
}
|
||||
if (response.statusCode !== 200) {
|
||||
return callback('Unable to store data on insight');
|
||||
}
|
||||
return callback();
|
||||
});
|
||||
};
|
||||
|
||||
InsightStorage.prototype.setItem = function(name, value, callback) {
|
||||
var passphrase = this.getPassphrase();
|
||||
var authHeader = new buffers.Buffer(this.email + ':' + passphrase).toString('base64');
|
||||
var registerUrl = this.storeUrl + '/save';
|
||||
this.request.post({
|
||||
url: registerUrl,
|
||||
headers: {'Authorization': authHeader},
|
||||
body: querystring.encode({
|
||||
key: name,
|
||||
email: this.email,
|
||||
secret: secret,
|
||||
record: value
|
||||
})
|
||||
}, function(err, response, body) {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,17 @@ module.exports = {
|
|||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @param {string} data
|
||||
* @return {string} base64 encoded hmac
|
||||
*/
|
||||
hmac: function(key, data) {
|
||||
return sjcl.codec.base64.fromBits(
|
||||
new sjcl.misc.hmac(key, sjcl.hash.sha256).encrypt(data)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} password
|
||||
* @param {string} salt - base64 encoded, defaults to 'mjuBtGybi/4='
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue