2014-10-24 08:24:44 -07:00
|
|
|
var request = require('request');
|
|
|
|
var cryptoUtil = require('../util/crypto');
|
2014-11-03 18:29:09 -08:00
|
|
|
var buffers = require('buffer');
|
2014-10-24 08:24:44 -07:00
|
|
|
var querystring = require('querystring');
|
|
|
|
var Identity = require('../models/Identity');
|
|
|
|
|
|
|
|
function InsightStorage(config) {
|
|
|
|
this.type = 'DB';
|
2014-11-01 17:34:03 -07:00
|
|
|
this.storeUrl = config.url || 'https://test-insight.bitpay.com:443/api/email';
|
2014-10-24 08:24:44 -07:00
|
|
|
this.request = config.request || request;
|
|
|
|
}
|
|
|
|
|
|
|
|
InsightStorage.prototype.init = function () {};
|
|
|
|
|
|
|
|
InsightStorage.prototype.setCredentials = function(email, password, opts) {
|
|
|
|
this.email = email;
|
|
|
|
this.password = password;
|
|
|
|
};
|
|
|
|
|
2014-10-28 11:20:43 -07:00
|
|
|
InsightStorage.prototype.createItem = function(name, value, callback) {
|
|
|
|
var self = this;
|
2014-11-03 18:29:09 -08:00
|
|
|
|
2014-10-28 11:20:43 -07:00
|
|
|
this.getItem(name, function(err, retrieved) {
|
|
|
|
if (err || !retrieved) {
|
|
|
|
return self.setItem(name, value, callback);
|
|
|
|
} else {
|
|
|
|
return callback('EEXISTS');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2014-11-03 18:29:09 -08:00
|
|
|
function mayBeOldPassword(password) {
|
|
|
|
// Test for base64
|
|
|
|
return /^[a-zA-Z0-9\/=\+]+$/.test(password);
|
|
|
|
}
|
|
|
|
|
2014-10-24 08:24:44 -07:00
|
|
|
InsightStorage.prototype.getItem = function(name, callback) {
|
2014-10-28 08:01:09 -07:00
|
|
|
var key = cryptoUtil.kdf(this.password + this.email);
|
2014-11-03 18:29:09 -08:00
|
|
|
var secret = this.makeSecret(key);
|
|
|
|
var self = this;
|
|
|
|
|
|
|
|
this._makeGetRequest(secret, name, function(err, body) {
|
|
|
|
if (err && err.indexOf('PNOTFOUND') !== -1 && mayBeOldPassword(self.password)) {
|
|
|
|
return self._brokenGetItem(key, name, callback);
|
|
|
|
}
|
|
|
|
return callback(err, body);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
InsightStorage.prototype.makeSecret = function(key) {
|
|
|
|
return cryptoUtil.kdf(key + this.password);
|
|
|
|
};
|
|
|
|
|
|
|
|
InsightStorage.prototype._makeGetRequest = function(secret, key, callback) {
|
|
|
|
var authHeader = new Buffer(this.email + ':' + secret).toString('base64');
|
|
|
|
var retrieveUrl = this.storeUrl + '/retrieve';
|
|
|
|
this.request.get({
|
|
|
|
url: retrieveUrl + '?' + querystring.encode({key: key}),
|
|
|
|
headers: {'Authorization': authHeader}
|
|
|
|
},
|
2014-10-24 08:24:44 -07:00
|
|
|
function(err, response, body) {
|
|
|
|
if (err) {
|
|
|
|
return callback('Connection error');
|
|
|
|
}
|
2014-10-31 07:24:16 -07:00
|
|
|
if (response.statusCode === 403) {
|
|
|
|
return callback('PNOTFOUND: Profile not found');
|
|
|
|
}
|
2014-10-24 08:24:44 -07:00
|
|
|
if (response.statusCode !== 200) {
|
|
|
|
return callback('Connection error');
|
|
|
|
}
|
|
|
|
return callback(null, body);
|
|
|
|
}
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
2014-11-03 18:29:09 -08:00
|
|
|
InsightStorage.prototype._brokenGetItem = function(key, name, callback) {
|
|
|
|
var secret = this._makeBrokenSecret(key);
|
|
|
|
var self = this;
|
|
|
|
this._makeGetRequest(secret, name, function(err, body) {
|
|
|
|
if (!err) {
|
|
|
|
return self._changePassword(function(err) {
|
|
|
|
if (err) {
|
|
|
|
return callback(err);
|
|
|
|
}
|
|
|
|
return callback(null, body);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return callback(err);
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
InsightStorage.prototype._makeBrokenSecret = function(key) {
|
|
|
|
return cryptoUtil.kdf(key, this.password);
|
|
|
|
};
|
|
|
|
|
|
|
|
InsightStorage.prototype._changePassword = function(callback) {
|
|
|
|
var key = cryptoUtil.kdf(this.password + this.email);
|
|
|
|
var secret = this._makeBrokenSecret(key);
|
|
|
|
var newSecret = this.makeSecret(key);
|
|
|
|
|
|
|
|
var url = this.storeUrl + '/change_passphrase';
|
|
|
|
this.request.post({
|
|
|
|
url: url,
|
|
|
|
body: querystring.encode({
|
|
|
|
email: this.email,
|
|
|
|
secret: secret,
|
|
|
|
newSecret: newSecret
|
|
|
|
})
|
|
|
|
}, 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();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2014-10-24 08:24:44 -07:00
|
|
|
InsightStorage.prototype.setItem = function(name, value, callback) {
|
2014-10-28 08:01:09 -07:00
|
|
|
var key = cryptoUtil.kdf(this.password + this.email);
|
2014-11-03 18:29:09 -08:00
|
|
|
var secret = this.makeSecret(key);
|
2014-10-24 08:24:44 -07:00
|
|
|
var registerUrl = this.storeUrl + '/register';
|
|
|
|
this.request.post({
|
|
|
|
url: registerUrl,
|
|
|
|
body: querystring.encode({
|
|
|
|
key: name,
|
|
|
|
email: this.email,
|
|
|
|
secret: secret,
|
|
|
|
record: value
|
|
|
|
})
|
|
|
|
}, function(err, response, body) {
|
|
|
|
if (err) {
|
|
|
|
return callback('Connection error');
|
|
|
|
}
|
2014-10-31 07:24:16 -07:00
|
|
|
if (response.statusCode === 409) {
|
2014-11-01 17:34:03 -07:00
|
|
|
return callback('BADCREDENTIALS: Invalid username or password');
|
2014-10-31 07:24:16 -07:00
|
|
|
}
|
2014-10-24 08:24:44 -07:00
|
|
|
if (response.statusCode !== 200) {
|
|
|
|
return callback('Unable to store data on insight');
|
|
|
|
}
|
|
|
|
return callback();
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
InsightStorage.prototype.removeItem = function(name, callback) {
|
|
|
|
this.setItem(name, '', callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
InsightStorage.prototype.clear = function(callback) {
|
|
|
|
// NOOP
|
|
|
|
callback();
|
|
|
|
};
|
|
|
|
|
|
|
|
InsightStorage.prototype.allKeys = function(callback) {
|
2014-10-29 12:21:44 -07:00
|
|
|
// TODO: compatibility with localStorage
|
|
|
|
return callback(null);
|
|
|
|
};
|
|
|
|
|
|
|
|
InsightStorage.prototype.getFirst = function(prefix, opts, callback) {
|
|
|
|
// TODO: compatibility with localStorage
|
|
|
|
return callback(null, true, true);
|
2014-10-24 08:24:44 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
module.exports = InsightStorage;
|