add test
This commit is contained in:
parent
d56dcd41de
commit
196ae2a448
|
@ -62,35 +62,49 @@ function API(opts) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
API.prototype._tryToComplete = function(data, cb) {
|
API.prototype._isWalletCorrupt = function(wallet, data) {
|
||||||
var self = this;
|
|
||||||
var isCorrupted;
|
|
||||||
|
|
||||||
var url = '/v1/wallets/';
|
|
||||||
self._doGetRequest(url, data, function(err, wallet) {
|
|
||||||
if (err) return cb(err);
|
|
||||||
if (wallet.n > 0 && wallet.status === 'complete' && !data.verified) {
|
|
||||||
var pubKey = Bitcore.PrivateKey.fromString(data.walletPrivKey).toPublicKey().toString();
|
var pubKey = Bitcore.PrivateKey.fromString(data.walletPrivKey).toPublicKey().toString();
|
||||||
var fake = [];
|
var fake = [];
|
||||||
|
|
||||||
|
if (data.n != wallet.copayers.length)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
var uniq = [];
|
||||||
_.each(wallet.copayers, function(copayer) {
|
_.each(wallet.copayers, function(copayer) {
|
||||||
|
if (uniq[copayer.xPubKey]++)
|
||||||
|
return true;
|
||||||
|
|
||||||
if (!SignUtils.verify(copayer.xPubKey, copayer.xPubKeySignature, pubKey)) {
|
if (!SignUtils.verify(copayer.xPubKey, copayer.xPubKeySignature, pubKey)) {
|
||||||
fake.push(copayer);
|
fake.push(copayer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (fake.length > 0) {
|
return fake.length > 0;
|
||||||
isCorrupted = true;
|
};
|
||||||
|
|
||||||
|
|
||||||
|
API.prototype._tryToComplete = function(data, cb) {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
var url = '/v1/wallets/';
|
||||||
|
self._doGetRequest(url, data, function(err, wallet) {
|
||||||
|
if (err) return cb(err);
|
||||||
|
|
||||||
|
if (wallet.status === 'complete' && !data.verified) {
|
||||||
|
|
||||||
|
if (self._isWalletCorrupt(wallet, data)) {
|
||||||
data.verified = 'corrupt';
|
data.verified = 'corrupt';
|
||||||
} else {
|
} else {
|
||||||
data.verified = 'ok';
|
data.verified = 'ok';
|
||||||
}
|
}
|
||||||
self.storage.save(data, function(err) {
|
self.storage.save(data, function(err) {
|
||||||
if (isCorrupted) {
|
if (data.verified == 'corrupt') {
|
||||||
return cb('Some copayers in the wallet could not be verified to have known the wallet secret');
|
return cb('Some copayers in the wallet could not be verified to have known the wallet secret');
|
||||||
}
|
}
|
||||||
return cb(err, data);
|
return cb(err, data);
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
return cb('Wallet Incomplete');
|
||||||
}
|
}
|
||||||
return cb(null, data);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,11 +113,11 @@ API.prototype._tryToComplete = function(data, cb) {
|
||||||
|
|
||||||
API.prototype._loadAndCheck = function(cb) {
|
API.prototype._loadAndCheck = function(cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.storage.load(function(err, data) {
|
this.storage.load(function(err, data) {
|
||||||
if (err || !data) {
|
if (err || !data) {
|
||||||
return cb(err || 'Wallet file not found.');
|
return cb(err || 'Wallet file not found.');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.verified == 'corrupt') {
|
if (data.verified == 'corrupt') {
|
||||||
return cb('The wallet is tagged as corrupt. Some of the copayers cannot be verified to have known the wallet secret.');
|
return cb('The wallet is tagged as corrupt. Some of the copayers cannot be verified to have known the wallet secret.');
|
||||||
}
|
}
|
||||||
|
@ -131,10 +145,13 @@ API.prototype._doRequest = function(method, url, args, data, cb) {
|
||||||
body: args,
|
body: args,
|
||||||
json: true,
|
json: true,
|
||||||
};
|
};
|
||||||
log.verbose('Request Args', util.inspect(args));
|
log.verbose('Request Args', util.inspect(args, {
|
||||||
|
depth: 10
|
||||||
|
}));
|
||||||
this.request(args, function(err, res, body) {
|
this.request(args, function(err, res, body) {
|
||||||
log.verbose('Response:', err, body);
|
log.verbose(util.inspect(body, {
|
||||||
|
depth: 10
|
||||||
|
}));
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
if (res.statusCode != 200) {
|
if (res.statusCode != 200) {
|
||||||
_parseError(body);
|
_parseError(body);
|
||||||
|
@ -279,8 +296,7 @@ API.prototype.getStatus = function(cb) {
|
||||||
API.prototype.sendTxProposal = function(inArgs, cb) {
|
API.prototype.sendTxProposal = function(inArgs, cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._loadAndCheck(
|
this._loadAndCheck(function(err, data) {
|
||||||
function(err, data) {
|
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
var args = _createProposalOpts(inArgs, data.signingPrivKey);
|
var args = _createProposalOpts(inArgs, data.signingPrivKey);
|
||||||
|
@ -293,8 +309,7 @@ API.prototype.sendTxProposal = function(inArgs, cb) {
|
||||||
API.prototype.createAddress = function(cb) {
|
API.prototype.createAddress = function(cb) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._loadAndCheck(
|
this._loadAndCheck(function(err, data) {
|
||||||
function(err, data) {
|
|
||||||
if (err) return cb(err);
|
if (err) return cb(err);
|
||||||
|
|
||||||
var url = '/v1/addresses/';
|
var url = '/v1/addresses/';
|
||||||
|
|
|
@ -7,51 +7,95 @@ var should = chai.should();
|
||||||
var Client = require('../../lib/client');
|
var Client = require('../../lib/client');
|
||||||
var API = Client.API;
|
var API = Client.API;
|
||||||
var Bitcore = require('bitcore');
|
var Bitcore = require('bitcore');
|
||||||
|
var TestData = require('./clienttestdata');
|
||||||
|
|
||||||
var wallet11 = {
|
describe(' client API ', function() {
|
||||||
"m": 1,
|
|
||||||
"n": 1,
|
|
||||||
"walletPrivKey": "{\"bn\":\"6b862ffbfc90a37a2fedbbcfea91c6a4e49f49b6aaa322b6e16c46bfdbe71a38\",\"compressed\":true,\"network\":\"livenet\"}",
|
|
||||||
"network": "testnet",
|
|
||||||
"xPrivKey": "tprv8ZgxMBicQKsPeisyNJteQXZnb7CnhYc4TVAyxxicXuxMjK1rmaqVq1xnXtbSTPxUKKL9h5xJhUvw1AKfDD3i98A82eJWSYRWYjmPksewFKR",
|
|
||||||
"copayerId": "a84daa08-17b5-45ad-84cd-e275f3b07123",
|
|
||||||
"signingPrivKey": "42798f82c4ed9ace4d66335165071edf180e70bc0fc08dacb3e35185a2141d5b",
|
|
||||||
"publicKeyRing": ["tpubD6NzVbkrYhZ4YBumFxZEowDuA8iirsny2nmmFUkuxBkkZoGdPyf61Waei3tDYvVa1yqW82Xhmmd6oiibeDyM1MS3zTiky7Yg75UEV9oQhFJ"]
|
|
||||||
};
|
|
||||||
|
|
||||||
var incompleteWallet22 = {
|
|
||||||
"m": 2,
|
|
||||||
"n": 2,
|
|
||||||
"walletPrivKey": "L3XSE3KNjQM1XRP1h5yMCSKsN4hs3D6eK7Vwn5M88Bs6jpCnXR3R",
|
|
||||||
"network": "testnet",
|
|
||||||
"secret": "d9cf45a1-6793-4df4-94df-c99d2c2e1fe9:bc2488c1b83e455a4b908a0d0aeaf70351efc48fbcaa454bffefdef419a5ee6a:T",
|
|
||||||
"xPrivKey": "tprv8ZgxMBicQKsPdoC5DGtnXx7fp7YnUtGv8b7fU2oDQfDpHFQh1QCgpKc8GHpdsBN5THaHYMV5LgD5cP5NYaacGVr786p3mVLSZff9berTV8h",
|
|
||||||
"copayerId": "c3a33ca0-37cf-4e80-b745-71272683835c",
|
|
||||||
"signingPrivKey": "6e129c4996666e5ecdf78aed626c01977fa19eacce6659738ebe065f86523e9b",
|
|
||||||
"publicKeyRing": []
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
describe('client API', function() {
|
|
||||||
|
|
||||||
var client;
|
var client;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
|
||||||
var fsmock = {};;
|
var fsmock = {};;
|
||||||
fsmock.readFile = sinon.mock().yields(null, JSON.stringify(wallet11));
|
fsmock.readFile = sinon.mock().yields(null, JSON.stringify(TestData.storage.wallet11));
|
||||||
fsmock.writeFile = sinon.mock().yields();
|
fsmock.writeFile = sinon.mock().yields();
|
||||||
var storage = new Client.FileStorage({
|
var storage = new Client.FileStorage({
|
||||||
filename: 'dummy',
|
filename: 'dummy',
|
||||||
fs: fsmock,
|
fs: fsmock,
|
||||||
});
|
});
|
||||||
client = new Client({
|
client = new Client({
|
||||||
storage: storage,
|
storage: storage
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('createAddress', function() {
|
describe(' _tryToComplete ', function() {
|
||||||
it('should check address', function(done) {
|
it('should complete a wallet ', function(done) {
|
||||||
|
var request = sinon.stub();
|
||||||
|
|
||||||
|
// Wallet request
|
||||||
|
request.onCall(0).yields(null, {
|
||||||
|
statusCode: 200,
|
||||||
|
}, TestData.serverResponse.completeWallet);
|
||||||
|
request.onCall(1).yields(null, {
|
||||||
|
statusCode: 200,
|
||||||
|
}, "pepe");
|
||||||
|
|
||||||
|
client.request = request;
|
||||||
|
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
||||||
|
client.getBalance(function(err, x) {
|
||||||
|
should.not.exist(err);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
it('should complain wallet is not complete ', function(done) {
|
||||||
|
var request = sinon.stub();
|
||||||
|
|
||||||
|
// Wallet request
|
||||||
|
request.onCall(0).yields(null, {
|
||||||
|
statusCode: 200,
|
||||||
|
}, TestData.serverResponse.incompleteWallet);
|
||||||
|
|
||||||
|
client.request = request;
|
||||||
|
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
||||||
|
client.createAddress(function(err, x) {
|
||||||
|
err.should.contain('Incomplete');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
it(' should reject wallets with bad signatures', function(done) {
|
||||||
|
var request = sinon.stub();
|
||||||
|
// Wallet request
|
||||||
|
request.onCall(0).yields(null, {
|
||||||
|
statusCode: 200,
|
||||||
|
}, TestData.serverResponse.corruptWallet22);
|
||||||
|
|
||||||
|
client.request = request;
|
||||||
|
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
||||||
|
client.createAddress(function(err, x) {
|
||||||
|
err.should.contain('verified');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
it(' should reject wallets with missing signatures ', function(done) {
|
||||||
|
var request = sinon.stub();
|
||||||
|
// Wallet request
|
||||||
|
request.onCall(0).yields(null, {
|
||||||
|
statusCode: 200,
|
||||||
|
}, TestData.serverResponse.corruptWallet222);
|
||||||
|
|
||||||
|
client.request = request;
|
||||||
|
client.storage.fs.readFile = sinon.stub().yields(null, JSON.stringify(TestData.storage.incompleteWallet22));
|
||||||
|
client.createAddress(function(err, x) {
|
||||||
|
err.should.contain('verified');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
describe(' createAddress ', function() {
|
||||||
|
it(' should check address ', function(done) {
|
||||||
|
|
||||||
var response = {
|
var response = {
|
||||||
createdOn: 1424105995,
|
createdOn: 1424105995,
|
||||||
|
@ -71,7 +115,7 @@ describe('client API', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
it('should detect fake addresses', function(done) {
|
it(' should detect fake addresses ', function(done) {
|
||||||
var response = {
|
var response = {
|
||||||
createdOn: 1424105995,
|
createdOn: 1424105995,
|
||||||
address: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq',
|
address: '2N3fA6wDtnebzywPkGuNK9KkFaEzgbPRRTq',
|
||||||
|
@ -88,20 +132,5 @@ describe('client API', function() {
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should complain wallet is not complete', function(done) {
|
|
||||||
var request = sinon.mock().yields(null, {
|
|
||||||
statusCode: 200
|
|
||||||
}, {
|
|
||||||
dummy: true
|
|
||||||
});
|
|
||||||
client.request = request;
|
|
||||||
client.storage.fs.readFile = sinon.mock().yields(null, JSON.stringify(incompleteWallet22));
|
|
||||||
client.createAddress(function(err, x) {
|
|
||||||
err.should.contain('Incomplete');
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
})
|
})
|
||||||
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
var storage = {
|
||||||
|
wallet11: {
|
||||||
|
"m": 1,
|
||||||
|
"n": 1,
|
||||||
|
"walletPrivKey": "{\"bn\":\"6b862ffbfc90a37a2fedbbcfea91c6a4e49f49b6aaa322b6e16c46bfdbe71a38\",\"compressed\":true,\"network\":\"livenet\"}",
|
||||||
|
"network": "testnet",
|
||||||
|
"xPrivKey": "tprv8ZgxMBicQKsPeisyNJteQXZnb7CnhYc4TVAyxxicXuxMjK1rmaqVq1xnXtbSTPxUKKL9h5xJhUvw1AKfDD3i98A82eJWSYRWYjmPksewFKR",
|
||||||
|
"copayerId": "a84daa08-17b5-45ad-84cd-e275f3b07123",
|
||||||
|
"signingPrivKey": "42798f82c4ed9ace4d66335165071edf180e70bc0fc08dacb3e35185a2141d5b",
|
||||||
|
"publicKeyRing": ["tpubD6NzVbkrYhZ4YBumFxZEowDuA8iirsny2nmmFUkuxBkkZoGdPyf61Waei3tDYvVa1yqW82Xhmmd6oiibeDyM1MS3zTiky7Yg75UEV9oQhFJ"]
|
||||||
|
},
|
||||||
|
|
||||||
|
incompleteWallet22: {
|
||||||
|
"m": 2,
|
||||||
|
"n": 2,
|
||||||
|
"walletPrivKey":"L2Fu6TM1AqSNBaQcjgjvYjGf3EzS3MVSTwEeTw3bvy52x7ZkffWj",
|
||||||
|
"network": "testnet",
|
||||||
|
"secret": "b6f57154-0df8-4845-a61d-47ecd648c2d4:eab5a55d9214845ee8d13ea1033e42ec8d7f780ae6e521d830252a80433e91a5:T",
|
||||||
|
"xPrivKey": "tprv8ZgxMBicQKsPfFVXegcKyJjy2Y5DSrHNrtGBHG1f9pPX75QQdHwHGjWUtR7cCUXV7QcCCDon4cieHWTYscy8M7oXwF3qd3ssfBiV9M68bPB",
|
||||||
|
"copayerId": "3fc03e7a-6ebc-409b-a4b7-45b14d5a8199",
|
||||||
|
"signingPrivKey": "0d3c796fb12e387c4b5a5c566312b2b22fa0553ca041d859e3f0987215ca3a4f",
|
||||||
|
"publicKeyRing": []
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var serverResponse = {
|
||||||
|
completeWallet: {
|
||||||
|
m: 2,
|
||||||
|
n: 2,
|
||||||
|
status: 'complete',
|
||||||
|
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
|
||||||
|
],
|
||||||
|
addressIndex: 0,
|
||||||
|
copayers: [{
|
||||||
|
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
xPubKeySignature: '3045022100ef86122060bbb7681db05486f8b1ee1579c5800e8da78182a87384f05542a4cc0220215ce7ef8c484b64178779414efdf2b7033d25ed752eebf4eb3241f9fa8e6b67',
|
||||||
|
}, {
|
||||||
|
xPubKey: 'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV',
|
||||||
|
xPubKeySignature: '3044022025c93b418ebdbb66a0f2b21af709420e8ae769bf054f29aaa252cb5417c46a2302205e0c8b931324736b7eea4971a48039614e19abe26e13ab0ef1547aef92b55aab',
|
||||||
|
}],
|
||||||
|
pubKey: ' { "x": "b2903ab878ed1316f82b859e9807e23bab3d579175563e1068d2ed9c9e37873c", "y": "5f30165915557394223a58329c1527dfa0f34f483d8aed02e0638f9124dbddef", "compressed": true }',
|
||||||
|
network: 'testnet',
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
incompleteWallet: {
|
||||||
|
m: 2,
|
||||||
|
n: 2,
|
||||||
|
status: 'pending',
|
||||||
|
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
|
||||||
|
],
|
||||||
|
addressIndex: 0,
|
||||||
|
copayers: [{
|
||||||
|
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
xPubKeySignature: '3045022100ef86122060bbb7681db05486f8b1ee1579c5800e8da78182a87384f05542a4cc0220215ce7ef8c484b64178779414efdf2b7033d25ed752eebf4eb3241f9fa8e6b67',
|
||||||
|
}],
|
||||||
|
pubKey: ' { "x": "b2903ab878ed1316f82b859e9807e23bab3d579175563e1068d2ed9c9e37873c", "y": "5f30165915557394223a58329c1527dfa0f34f483d8aed02e0638f9124dbddef", "compressed": true }',
|
||||||
|
network: 'testnet',
|
||||||
|
},
|
||||||
|
|
||||||
|
corruptWallet22: {
|
||||||
|
m: 2,
|
||||||
|
n: 2,
|
||||||
|
status: 'complete',
|
||||||
|
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
|
||||||
|
],
|
||||||
|
copayers: [{
|
||||||
|
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
xPubKeySignature: '3045022100ef86122060bbb7681db05486f8b1ee1579c5800e8da78182a87384f05542a4cc0220215ce7ef8c484b64178779414efdf2b7033d25ed752eebf4eb3241f9fa8e6b67',
|
||||||
|
}, {
|
||||||
|
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
xPubKeySignature: 'bababa',
|
||||||
|
}],
|
||||||
|
},
|
||||||
|
corruptWallet222: {
|
||||||
|
m: 2,
|
||||||
|
n: 2,
|
||||||
|
status: 'complete',
|
||||||
|
publicKeyRing: ['tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
'tpubD6NzVbkrYhZ4WSuBBLyubi8DHMipbFQcZoLJHjb21gEtznCEJMJhwkvaSshHVLtq8C1uNMKD4GtADVYY6WZt1cyT218JUm3PiNKYVkMATWV'
|
||||||
|
],
|
||||||
|
copayers: [{
|
||||||
|
xPubKey: 'tpubD6NzVbkrYhZ4Y1CGuCZ88eZvhDSTjAqjotZWGXC7e4GEoyXq3SQgZK9iRz4qC2h8MrzqrYBndCMQDiaaLdqpY8ihYmJC9Msvns83jGopb3E',
|
||||||
|
}, ],
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.serverResponse = serverResponse;
|
||||||
|
module.exports.storage = storage;
|
Loading…
Reference in New Issue