Compare commits

...

28 Commits

Author SHA1 Message Date
Geert Weening
1fcfcf2392 [TASK] bump version to 0.8.3-rc1 2014-10-06 18:23:59 -07:00
Geert Weening
6311abff81 [DOC] update release notes 2014-10-06 18:23:05 -07:00
Geert Weening
ed2da57475 Merge pull request #181 from shekenahglory/feature/identity
Feature/identity
2014-10-06 18:15:38 -07:00
Matthew Fettig
778ccd4805 [TASK] vault client: tests for attestation routes and full summary 2014-10-06 18:03:52 -07:00
Matthew Fettig
327c35252f [FEATURE] vault client: update attestation and attestation summary 2014-10-03 17:17:09 -07:00
Matthew Fettig
5e7af2fba4 [TASK] switch to new attestation endpoint 2014-10-03 17:17:09 -07:00
Matthew Fettig
dce15bc579 [TASK] vault client: add parameters to attest 2014-10-03 17:17:08 -07:00
Matthew Fettig
d5e32db954 [CHORE] vault client: add type to attest parameters 2014-10-03 17:17:08 -07:00
Matthew Fettig
bdfa83592b [FEATURE] identity functions 2014-10-03 17:17:08 -07:00
wltsmrz
0dfd3a0ae0 Merge pull request #178 from ripplerm/develop
configurable maxAttempts
2014-10-01 02:07:04 -07:00
ripplerm
d107092540 configurable maxAttempts 2014-10-01 14:43:44 +08:00
wltsmrz
c2f379d3b3 Merge pull request #176 from shekenahglory/develop
[FIX] change handling of requestLedger options
2014-09-28 00:34:30 -07:00
Matthew Fettig
57b70300f5 [FIX] change handling of requestLedger options
ledger_index and ledger_hash were being set to true
instead of the specified value, and according to API
docs 'closed','validated', and 'current' can be
supplied to the ledger_index field to get the most
recent of the specified type
2014-09-26 21:41:22 -07:00
Geert Weening
eeba86f9c5 [TASK] bump version to 0.8.2 2014-09-25 10:05:57 -07:00
Geert Weening
e0d68e60ec Merge pull request #172 from booxood/modify-docs-guides-md
Update docs/GUIDES.md
2014-09-24 23:44:08 -07:00
Liucw
254248486b Update docs/GUIDES.md 2014-09-25 14:34:29 +08:00
Geert Weening
1b57cc6d35 [TASK] bump verison to 0.8.2-rc2 2014-09-22 23:59:12 -07:00
Geert Weening
77234f256d [DOC] update release notes 2014-09-22 23:58:49 -07:00
Geert Weening
795d31d2db Merge branch 'release' into develop 2014-09-22 23:50:45 -07:00
wltsmrz
f3f10fd9bd Fix requestLedger arguments 2014-09-18 02:03:29 -07:00
wltsmrz
7100b4be8d Emit server with subscription events 2014-09-18 01:41:23 -07:00
wltsmrz
b1a7200d1b Deprecate account_tx map/reduce/filter 2014-09-18 01:28:43 -07:00
Geert Weening
5d8bb541c6 [TASK] bump version to 0.8.2-rc1 2014-09-17 15:02:44 -07:00
Geert Weening
b51c59b23a [TASK] update release notes 2014-09-17 15:02:21 -07:00
wltsmrz
2cd434e861 Fix orderbook reset on reconnect 2014-09-17 13:42:24 -07:00
wltsmrz
1599eb9629 Add potential missing error handlers 2014-09-17 13:40:49 -07:00
wltsmrz
8ef7481858 Allow mixed letters and numbers in currencies 2014-09-17 13:39:49 -07:00
Geert Weening
344d478b3f [TASK] bump version to 0.8.1 2014-09-15 16:52:23 -07:00
15 changed files with 532 additions and 225 deletions

View File

@@ -1,3 +1,26 @@
##0.8.3
+ Add routes to the vault client for KYC attestations ([ed2da574](https://github.com/ripple/ripple-lib/commit/ed2da57475acf5e9d2cf3373858f4274832bd83f))
+ Configurable maxAttempts for transaction submission ([d107092](https://github.com/ripple/ripple-lib/commit/d10709254061e9e4416d2cb78b5cac1ec0d7ffa5))
+ Fix: change handling of requestLedger options ([57b7030](https://github.com/ripple/ripple-lib/commit/57b70300f5f0c7534ede118ddbb5d8762668a4f8))
##0.8.2
+ Currency: Allow mixed letters and numbers in currencies
+ Deprecate account_tx map/reduce/filter
+ Fix: correct requestLedger arguments
+ Fix: missing subscription on error events for some server methods
+ Fix: orderbook reset on reconnect
+ Fix: ripple-lib crashing. Add potential missing error handlers
##0.8.1
+ Wallet: Add Wallet class that generates wallets
@@ -10,6 +33,7 @@
+ Fix undefined fee states when connecting to a rippled that is syncing
##0.8.0
+ Orderbook: Added tracking of offer funds for determining when offers are not funded

View File

@@ -111,14 +111,14 @@ See the [wiki](https://ripple.com/wiki/JSON_Messages#subscribe) for details on s
//handle ledger
});
remote.on('transaction', function onTransacstion(transaction) {
request.on('transaction', function onTransacstion(transaction) {
//handle transaction
});
remote.request(function(err) {
request.request(function(err) {
if (err) {
} else {
}
} else {
}
});
});
```
@@ -186,14 +186,7 @@ var Amount = require('ripple-lib').Amount;
var MY_ADDRESS = 'rrrMyAddress';
var MY_SECRET = 'secret';
var BUY_AMOUNT = Amount.from_human('100XRP');
var SELL_AMOUNT = Amount.from_human('1USD');
// EXPIRATION must be a Date object, leave undefined to submit offer that won't expire
var now = new Date();
var tomorrow = new Date(now.getTime() + (24 * 60 * 60 * 1000));
var EXPIRATION = tomorrow;
var GATEWAY = 'rrrGateWay';
var remote = new Remote({ /* Remote options */ });
@@ -201,10 +194,9 @@ remote.connect(function() {
remote.setSecret(MY_ADDRESS, MY_SECRET);
var transaction = remote.createTransaction('OfferCreate', {
account: MY_ADDRESS,
buy: BUY_AMOUNT,
sell: SELL_AMOUNT,
expiration: EXPIRATION
account: MY_ADDRESS,
taker_pays: '1',
taker_gets: '1/USD/' + GATEWAY
});
transaction.submit(function(err, res) {

View File

@@ -1,6 +1,6 @@
{
"name": "ripple-lib",
"version": "0.8.1-rc3",
"version": "0.8.3-rc1",
"description": "Ripple JavaScript client library",
"files": [
"src/js/*",

View File

@@ -119,7 +119,9 @@ BlobObj.prototype.init = function(fn) {
self.revision = resp.body.revision;
self.encrypted_secret = resp.body.encrypted_secret;
self.identity_id = resp.body.identity_id;
self.missing_fields = resp.body.missing_fields;
//self.attestations = resp.body.attestation_summary;
if (!self.decrypt(resp.body.blob)) {
return fn(new Error('Error while decrypting blob'));
@@ -561,7 +563,6 @@ BlobObj.prototype.get2FA = function (fn) {
* @params {boolean} options.enabled
* @params {string} options.phone
* @params {string} options.country_code
* @params {string} options.via //sms, etc
*/
BlobObj.prototype.set2FA = function(options, fn) {
@@ -572,8 +573,7 @@ BlobObj.prototype.set2FA = function(options, fn) {
data : {
enabled : options.enabled,
phone : options.phone,
country_code : options.country_code,
via : options.via
country_code : options.country_code
}
};
@@ -1115,48 +1115,6 @@ BlobClient.recoverBlob = function (opts, fn) {
};
};
/**
* updateProfile
* update information stored outside the blob - HMAC signed
* @param {object}
* @param {string} opts.url
* @param {string} opts.username
* @param {string} opts.auth_secret
* @param {srring} opts.blob_id
* @param {object} opts.profile
* @param {string} opts.profile.phone - optional
* @param {string} opts.profile.country - optional
* @param {string} opts.profile.region - optional
* @param {string} opts.profile.city - optional
*/
BlobClient.updateProfile = function (opts, fn) {
var config = {
method: 'POST',
url: opts.url + '/v1/user/' + opts.username + '/profile',
dataType: 'json',
data: opts.profile
};
var signedRequest = new SignedRequest(config);
var signed = signedRequest.signHmac(opts.auth_secret, opts.blob_id);
request.post(signed.url)
.send(signed.data)
.end(function(err, resp) {
if (err) {
log.error('updateProfile:', err);
fn(new Error('Failed to update profile - XHR error'));
} else if (resp.body && resp.body.result === 'success') {
fn(null, resp.body);
} else if (resp.body) {
log.error('updateProfile:', resp.body);
} else {
fn(new Error('Failed to update profile'));
}
});
};
/**
* updateKeys
@@ -1320,6 +1278,7 @@ BlobClient.create = function(options, fn) {
if (err) {
fn(err);
} else if (resp.body && resp.body.result === 'success') {
blob.identity_id = resp.body.identity_id;
fn(null, blob, resp.body);
} else if (resp.body && resp.body.result === 'error') {
fn(new Error(resp.body.message));
@@ -1363,4 +1322,263 @@ BlobClient.deleteBlob = function(options, fn) {
});
};
/*** identity related functions ***/
/**
* updateProfile
* update information stored outside the blob - HMAC signed
* @param {object}
* @param {string} opts.url
* @param {string} opts.auth_secret
* @param {srring} opts.blob_id
* @param {object} opts.profile
* @param {array} opts.profile.attributes (optional, array of attribute objects)
* @param {array} opts.profile.addresses (optional, array of address objects)
*
* @param {string} attribute.id ... id of existing attribute
* @param {string} attribute.name ... attribute name i.e. ripple_address
* @param {string} attribute.type ... optional, sub-type of attribute
* @param {string} attribute.value ... value of attribute
* @param {string} attribute.domain ... corresponding domain
* @param {string} attribute.status ... “current”, “removed”, etc.
* @param {string} attribute.visibitlity ... “public”, ”private”
*/
BlobClient.updateProfile = function (opts, fn) {
var config = {
method: 'POST',
url: opts.url + '/v1/profile/',
dataType: 'json',
data: opts.profile
};
var signedRequest = new SignedRequest(config);
var signed = signedRequest.signHmac(opts.auth_secret, opts.blob_id);
request.post(signed.url)
.send(signed.data)
.end(function(err, resp) {
if (err) {
log.error('updateProfile:', err);
fn(new Error('Failed to update profile - XHR error'));
} else if (resp.body && resp.body.result === 'success') {
fn(null, resp.body);
} else if (resp.body) {
log.error('updateProfile:', resp.body);
fn(new Error('Failed to update profile'));
} else {
fn(new Error('Failed to update profile'));
}
});
};
/**
* getProfile
* @param {Object} opts
* @param {string} opts.url
* @param {string} opts.auth_secret
* @param {srring} opts.blob_id
*/
BlobClient.getProfile = function (opts, fn) {
var config = {
method: 'GET',
url: opts.url + '/v1/profile/'
};
var signedRequest = new SignedRequest(config);
var signed = signedRequest.signHmac(opts.auth_secret, opts.blob_id);
request.get(signed.url)
.send(signed.data)
.end(function(err, resp) {
if (err) {
log.error('getProfile:', err);
fn(new Error('Failed to get profile - XHR error'));
} else if (resp.body && resp.body.result === 'success') {
fn(null, resp.body);
} else if (resp.body) {
log.error('getProfile:', resp.body);
fn(new Error('Failed to get profile'));
} else {
fn(new Error('Failed to get profile'));
}
});
};
/**
* getAttestation
* @param {Object} opts
* @param {string} opts.url
* @param {string} opts.auth_secret
* @param {string} opts.blob_id
* @param {string} opts.type (email,phone,basic_identity)
* @param {object} opts.phone (required for type 'phone')
* @param {string} opts.email (required for type 'email')
*/
BlobClient.getAttestation = function (opts, fn) {
var params = { };
if (opts.phone) params.phone = opts.phone;
if (opts.email) params.email = opts.email;
var config = {
method: 'POST',
url: opts.url + '/v1/attestation/' + opts.type,
dataType: 'json',
data: params
};
var signedRequest = new SignedRequest(config);
var signed = signedRequest.signHmac(opts.auth_secret, opts.blob_id);
request.post(signed.url)
.send(signed.data)
.end(function(err, resp) {
if (err) {
log.error('attest:', err);
fn(new Error('attestation error - XHR error'));
} else if (resp.body && resp.body.result === 'success') {
if (resp.body.attestation) {
resp.body.decoded = BlobClient.parseAttestation(resp.body.attestation);
}
fn(null, resp.body);
} else if (resp.body) {
log.error('attestation:', resp.body);
fn(new Error('attestation error: ' + resp.body.message || ""));
} else {
fn(new Error('attestation error'));
}
});
};
/**
* getAttestationSummary
* @param {Object} opts
* @param {string} opts.url
* @param {string} opts.auth_secret
* @param {string} opts.blob_id
*/
BlobClient.getAttestationSummary = function (opts, fn) {
var config = {
method: 'GET',
url: opts.url + '/v1/attestation/summary',
dataType: 'json'
};
if (opts.full) config.url += '?full=true';
var signedRequest = new SignedRequest(config);
var signed = signedRequest.signHmac(opts.auth_secret, opts.blob_id);
request.get(signed.url)
.send(signed.data)
.end(function(err, resp) {
if (err) {
log.error('attest:', err);
fn(new Error('attestation error - XHR error'));
} else if (resp.body && resp.body.result === 'success') {
if (resp.body.attestation) {
resp.body.decoded = BlobClient.parseAttestation(resp.body.attestation);
}
fn(null, resp.body);
} else if (resp.body) {
log.error('attestation:', resp.body);
fn(new Error('attestation error: ' + resp.body.message || ""));
} else {
fn(new Error('attestation error'));
}
});
};
/**
* updateAttestation
* @param {Object} opts
* @param {string} opts.url
* @param {string} opts.auth_secret
* @param {string} opts.blob_id
* @param {string} opts.type (email,phone,profile,identity)
* @param {object} opts.phone (required for type 'phone')
* @param {object} opts.profile (required for type 'profile')
* @param {string} opts.email (required for type 'email')
* @param {string} opts.answers (required for type 'identity')
* @param {string} opts.token (required for completing email or phone attestations)
*/
BlobClient.updateAttestation = function (opts, fn) {
var params = { };
if (opts.phone) params.phone = opts.phone;
if (opts.profile) params.profile = opts.profile;
if (opts.email) params.email = opts.email;
if (opts.token) params.token = opts.token;
if (opts.answers) params.answers = opts.answers;
var config = {
method: 'POST',
url: opts.url + '/v1/attestation/' + opts.type + '/update',
dataType: 'json',
data: params
};
var signedRequest = new SignedRequest(config);
var signed = signedRequest.signHmac(opts.auth_secret, opts.blob_id);
request.post(signed.url)
.send(signed.data)
.end(function(err, resp) {
if (err) {
log.error('attest:', err);
fn(new Error('attestation error - XHR error'));
} else if (resp.body && resp.body.result === 'success') {
if (resp.body.attestation) {
resp.body.decoded = BlobClient.parseAttestation(resp.body.attestation);
}
fn(null, resp.body);
} else if (resp.body) {
log.error('attestation:', resp.body);
fn(new Error('attestation error: ' + resp.body.message || ""));
} else {
fn(new Error('attestation error'));
}
});
};
/**
* parseAttestation
* @param {Object} attestation
*/
BlobClient.parseAttestation = function (attestation) {
var segments = attestation.split('.');
var decoded;
// base64 decode and parse JSON
try {
decoded = {
header : JSON.parse(crypt.decodeBase64(segments[0])),
payload : JSON.parse(crypt.decodeBase64(segments[1])),
signature : segments[2]
};
} catch (e) {
console.log("invalid attestation:", e);
}
return decoded;
};
exports.BlobClient = BlobClient;

View File

@@ -322,4 +322,12 @@ Crypt.base64UrlToBase64 = function(encodedData) {
return encodedData;
};
/**
* base64 to UTF8
*/
Crypt.decodeBase64 = function (data) {
return sjcl.codec.utf8String.fromBits(sjcl.codec.base64.toBits(data));
}
exports.Crypt = Crypt;

View File

@@ -50,7 +50,7 @@ Currency.HEX_CURRENCY_BAD = '0000000000000000000000005852500000000000';
* \s*$ // end with any amount of whitespace
*
*/
Currency.prototype.human_RE = /^\s*([a-zA-Z]{3}|[0-9]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/;
Currency.prototype.human_RE = /^\s*([a-zA-Z0-9]{3})(\s*-\s*[- \w]+)?(\s*\(-?\d+\.?\d*%pa\))?\s*$/;
Currency.from_json = function(j, shouldInterpretXrpAsIou) {
if (j instanceof this) {

View File

@@ -78,19 +78,20 @@ function OrderBook(remote, getsC, getsI, paysC, paysI, key) {
});
this.on('unsubscribe', function() {
self._ownerFunds = { };
self.resetCache();
self._remote.removeListener('transaction', updateFundedAmounts);
self._remote.removeListener('transaction', updateTransferRate);
});
this._remote.on('prepare_subscribe', function() {
this._remote.once('prepare_subscribe', function() {
self.subscribe();
});
this._remote.on('disconnect', function() {
self._ownerFunds = { };
self._offerCounts = { };
self._synchronized = false;
self.resetCache();
self._remote.once('prepare_subscribe', function() {
self.subscribe();
});
});
function updateFundedAmounts(message) {
@@ -195,6 +196,16 @@ OrderBook.prototype.unsubscribe = function() {
this.emit('unsubscribe');
};
/**
* Reset cached owner funds, offer counts
*/
OrderBook.prototype.resetCache = function() {
this._ownerFunds = { };
this._offerCounts = { };
this._synchronized = false;
};
/**
* Check that the funds for offer owner have been cached
*
@@ -695,6 +706,9 @@ OrderBook.prototype.requestOffers = function(callback) {
log.info('requested offers', self._key, 'offers: ' + res.offers.length);
}
// Reset offers
self._offers = [ ];
for (var i=0, l=res.offers.length; i<l; i++) {
var offer = res.offers[i];
var fundedAmount;

View File

@@ -94,6 +94,8 @@ function Remote(opts, trace) {
this.fee_cushion = (typeof opts.fee_cushion === 'number') ? opts.fee_cushion : 1.2;
this.max_fee = (typeof opts.max_fee === 'number') ? opts.max_fee : Infinity;
this.max_attempts = (typeof opts.max_attempts === 'number') ? opts.max_attempts : 10;
this._ledger_current_index = void(0);
this._ledger_hash = void(0);
this._ledger_time = void(0);
@@ -615,16 +617,16 @@ Remote.prototype._handleMessage = function(message, server) {
switch (message.type) {
case 'ledgerClosed':
this._handleLedgerClosed(message);
this._handleLedgerClosed(message, server);
break;
case 'serverStatus':
this._handleServerStatus(message);
this._handleServerStatus(message, server);
break;
case 'transaction':
this._handleTransaction(message);
this._handleTransaction(message, server);
break;
case 'path_find':
this._handlePathFind(message);
this._handlePathFind(message, server);
break;
default:
if (this.trace) {
@@ -640,7 +642,7 @@ Remote.prototype._handleMessage = function(message, server) {
* @param {Object} message
*/
Remote.prototype._handleLedgerClosed = function(message) {
Remote.prototype._handleLedgerClosed = function(message, server) {
var self = this;
// XXX If not trusted, need to verify we consider ledger closed.
@@ -659,11 +661,11 @@ Remote.prototype._handleLedgerClosed = function(message) {
this._ledger_current_index = message.ledger_index + 1;
if (this.isConnected()) {
this.emit('ledger_closed', message);
this.emit('ledger_closed', message, server);
} else {
this.once('connect', function() {
// Delay until server is 'online'
self.emit('ledger_closed', message);
self.emit('ledger_closed', message, server);
});
}
}
@@ -675,8 +677,8 @@ Remote.prototype._handleLedgerClosed = function(message) {
* @param {Object} message
*/
Remote.prototype._handleServerStatus = function(message) {
this.emit('server_status', message);
Remote.prototype._handleServerStatus = function(message, server) {
this.emit('server_status', message, server);
};
/**
@@ -685,7 +687,7 @@ Remote.prototype._handleServerStatus = function(message) {
* @param {Object} message
*/
Remote.prototype._handleTransaction = function(message) {
Remote.prototype._handleTransaction = function(message, server) {
var self = this;
// XXX If not trusted, need proof.
@@ -732,8 +734,8 @@ Remote.prototype._handleTransaction = function(message) {
});
}
this.emit('transaction', message);
this.emit('transaction_all', message);
this.emit('transaction', message, server);
this.emit('transaction_all', message, server);
};
/**
@@ -742,7 +744,7 @@ Remote.prototype._handleTransaction = function(message) {
* @param {Object} message
*/
Remote.prototype._handlePathFind = function(message) {
Remote.prototype._handlePathFind = function(message, server) {
var self = this;
// Pass the event to the currently open PathFind object
@@ -750,7 +752,7 @@ Remote.prototype._handlePathFind = function(message) {
this._cur_path_find.notify_update(message);
}
this.emit('path_find_all', message);
this.emit('path_find_all', message, server);
};
/**
@@ -929,20 +931,19 @@ Remote.prototype.requestServerInfo = function(callback) {
* @return {Request} request
*/
Remote.prototype.requestLedger = function(ledger, options, callback) {
Remote.prototype.requestLedger = function(options, callback) {
// XXX This is a bad command. Some variants don't scale.
// XXX Require the server to be trusted.
//utils.assert(this.trusted);
var request = new Request(this, 'ledger');
if (ledger) {
// DEPRECATED: use .ledger_hash() or .ledger_index()
//console.log('request_ledger: ledger parameter is deprecated');
request.message.ledger = ledger;
}
switch (typeof options) {
case 'undefined': break;
case 'function':
callback = options;
break;
case 'object':
Object.keys(options).forEach(function(o) {
switch (o) {
@@ -952,21 +953,23 @@ Remote.prototype.requestLedger = function(ledger, options, callback) {
case 'accounts':
request.message[o] = true;
break;
case 'ledger_index':
case 'ledger_hash':
request.message[o] = options[o];
break;
case 'closed' :
case 'current' :
case 'validated' :
request.message.ledger_index = o;
break;
}
}, options);
break;
case 'function':
callback = options;
options = void(0);
break;
default:
//DEPRECATED
if (this.trace) {
log.info('request_ledger: full parameter is deprecated');
}
request.message.full = true;
request.ledgerSelect(options);
break;
}
@@ -1337,6 +1340,10 @@ Remote.prototype.requestAccountTx = function(options, callback) {
options.ledger_index_max = options.max_ledger;
}
if (options.binary && options.parseBinary === void(0)) {
options.parseBinary = true;
}
Object.keys(options).forEach(function(o) {
switch (o) {
case 'account':
@@ -1356,101 +1363,32 @@ Remote.prototype.requestAccountTx = function(options, callback) {
}
}, options);
function propertiesFilter(obj, transaction) {
var properties = Object.keys(obj);
return function(transaction) {
var result = properties.every(function(property) {
return transaction.tx[property] === obj[property];
});
return result;
};
};
function parseBinaryTransaction(transaction) {
var tx = { validated: transaction.validated };
tx.meta = new SerializedObject(transaction.meta).to_json();
tx.tx = new SerializedObject(transaction.tx_blob).to_json();
tx.tx.ledger_index = transaction.ledger_index;
tx.tx.hash = Transaction.from_json(tx.tx).hash();
return tx;
};
function accountTxFilter(fn) {
if (typeof fn !== 'function') {
throw new Error('Missing filter function');
request.once('success', function(res) {
if (options.parseBinary) {
res.transactions = res.transactions.map(Remote.parseBinaryTransaction);
}
request.emit('transactions', res);
});
var self = this;
function filterHandler() {
var listeners = self.listeners('success');
self.removeAllListeners('success');
self.once('success', function(res) {
if (options.parseBinary) {
res.transactions = res.transactions.map(parseBinaryTransaction);
}
if (fn !== Boolean) {
res.transactions = res.transactions.filter(fn);
}
if (typeof options.map === 'function') {
res.transactions = res.transactions.map(options.map);
}
if (typeof options.reduce === 'function') {
res.transactions = res.transactions.reduce(options.reduce);
}
if (typeof options.pluck === 'string') {
res = res[options.pluck];
}
listeners.forEach(function(listener) {
listener.call(self, res);
});
});
};
this.once('request', filterHandler);
return this;
};
request.filter = accountTxFilter;
if (typeof options.parseBinary !== 'boolean') {
options.parseBinary = true;
}
if (options.binary || (options.map || options.reduce)) {
options.filter = options.filter || Boolean;
}
if (options.filter) {
switch (options.filter) {
case 'inbound':
request.filter(propertiesFilter({ Destination: options.account }));
break;
case 'outbound':
request.filter(propertiesFilter({ Account: options.account }));
break;
default:
if (typeof options.filter === 'object') {
options.filter = propertiesFilter(options.filter);
}
request.filter(options.filter);
}
}
request.callback(callback);
request.callback(callback, 'transactions');
return request;
};
/**
* @param {Object} transaction
* @return {Transaction}
*/
Remote.parseBinaryTransaction = function(transaction) {
var tx = { validated: transaction.validated };
tx.meta = new SerializedObject(transaction.meta).to_json();
tx.tx = new SerializedObject(transaction.tx_blob).to_json();
tx.tx.ledger_index = transaction.ledger_index;
tx.tx.hash = Transaction.from_json(tx.tx).hash();
return tx;
};
/**
* Request the overall transaction history.
*
@@ -1589,10 +1527,14 @@ Remote.prototype.requestSubmit = function(callback) {
* @api private
*/
Remote.prototype._serverPrepareSubscribe = function(callback) {
Remote.prototype._serverPrepareSubscribe = function(server, callback) {
var self = this;
var feeds = [ 'ledger', 'server' ];
if (typeof server === 'function') {
callback = server;
}
if (this._transaction_subs) {
feeds.push('transactions');
}
@@ -1613,11 +1555,17 @@ Remote.prototype._serverPrepareSubscribe = function(callback) {
self.emit('random', utils.hexToArray(message.random));
}
self._handleLedgerClosed(message);
self._handleLedgerClosed(message, server);
self.emit('subscribed');
};
request.on('error', function(err) {
if (self.trace) {
log.info('Initial server subscribe failed', err);
}
});
request.once('success', serverSubscribed);
self.emit('prepare_subscribe', request);
@@ -2261,7 +2209,7 @@ Remote.prototype.createTransaction = function(type, options) {
*/
Remote.prototype.feeTx = function(units) {
var server = this._getServer();
var server = this.getServer();
if (!server) {
throw new Error('No connected servers');
@@ -2280,7 +2228,7 @@ Remote.prototype.feeTx = function(units) {
*/
Remote.prototype.feeTxUnit = function() {
var server = this._getServer();
var server = this.getServer();
if (!server) {
throw new Error('No connected servers');
@@ -2299,7 +2247,7 @@ Remote.prototype.feeTxUnit = function() {
*/
Remote.prototype.reserve = function(owner_count) {
var server = this._getServer();
var server = this.getServer();
if (!server) {
throw new Error('No connected servers');

View File

@@ -134,7 +134,9 @@ function Server(remote, opts) {
}
});
self._request(self._remote.requestServerInfo());
var serverInfoRequest = self._remote.requestServerInfo();
serverInfoRequest.on('error', function() { });
self._request(serverInfoRequest);
});
};
@@ -407,7 +409,7 @@ Server.prototype.connect = function() {
if (ws === self._ws) {
self.emit('socket_open');
// Subscribe to events
self._request(self._remote._serverPrepareSubscribe());
self._request(self._remote._serverPrepareSubscribe(self));
}
};

View File

@@ -20,6 +20,7 @@ function TransactionManager(account) {
this._remote = account._remote;
this._nextSequence = void(0);
this._maxFee = this._remote.max_fee;
this._maxAttempts = this._remote.max_attempts;
this._submissionTimeout = this._remote._submission_timeout;
this._pending = new PendingQueue();
@@ -344,7 +345,7 @@ TransactionManager.prototype._request = function(tx) {
var self = this;
var remote = this._remote;
if (tx.attempts > 10) {
if (tx.attempts > this._maxAttempts) {
return tx.emit('error', new RippleError('tejAttemptsExceeded'));
}

View File

@@ -575,8 +575,6 @@ VaultClient.prototype.generateDeviceID = function () {
VaultClient.prototype.resendEmail = blobClient.resendEmail;
VaultClient.prototype.updateProfile = blobClient.updateProfile;
VaultClient.prototype.recoverBlob = blobClient.recoverBlob;
VaultClient.prototype.deleteBlob = blobClient.deleteBlob;
@@ -585,5 +583,11 @@ VaultClient.prototype.requestToken = blobClient.requestToken;
VaultClient.prototype.verifyToken = blobClient.verifyToken;
VaultClient.prototype.getAttestation = blobClient.getAttestation;
VaultClient.prototype.updateAttestation = blobClient.updateAttestation;
VaultClient.prototype.getAttestationSummary = blobClient.getAttestationSummary;
//export by name
exports.VaultClient = VaultClient;

View File

@@ -292,7 +292,7 @@ describe('Amount', function() {
assert.strictEqual('0/111/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('0/111/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full());
});
it('Parse 0.0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', function () {
assert.strictEqual('0/XRP/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full());
assert.strictEqual('0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_text_full());
});
it('Parse native 0 human', function () {
assert.strictEqual('0/XRP', Amount.from_json('0').to_human_full());
@@ -337,7 +337,7 @@ describe('Amount', function() {
assert.strictEqual('0/111/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('0/111/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full());
});
it('Parse 0.0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh human', function () {
assert.strictEqual('0/XRP/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full());
assert.strictEqual('0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh', Amount.from_json('0/12D/rHb9CJAWyB4rj91VRWn96DkukG4bwdtyTh').to_human_full());
});
});
describe('Amount to_json', function() {

View File

@@ -40,8 +40,8 @@ describe('Currency', function() {
});
it('from_json("1D2").to_human()', function() {
var r = currency.from_json("1D2");
assert(!r.is_valid());
assert.strictEqual('XRP', r.to_json());
assert(r.is_valid());
assert.strictEqual('1D2', r.to_json());
});
it('from_json("XAU").to_json() hex', function() {
var r = currency.from_json("XAU");

View File

@@ -1546,7 +1546,7 @@ describe('OrderBook', function() {
]
book.once('model', function(model) {
book.on('model', function(model) {
assert.deepEqual(model, expected);
assert.strictEqual(book._synchronized, true);
done();

View File

@@ -20,6 +20,7 @@ var exampleData = {
email_token : '77825040-9096-4695-9cbc-76720f6a8649',
activateLink : 'https://staging.ripple.com/client/#/register/activate/',
device_id : "ac1b6f6dbca98190eb9687ba06f0e066",
identity_id : "17fddb71-a5c2-44ce-8b50-4b381339d4f2",
blob: {
url: 'https://id.staging.ripple.com',
id: 'ef203d3e76552c0592384f909e6f61f1d1f02f61f07643ce015d8b0c9710dd2f',
@@ -103,12 +104,29 @@ var recoverRes = {
result: 'success'
}
}
var getProfileRes = {
"result":"success",
"addresses":[],
"attributes":[{
"attribute_id":"4034e477-ffc9-48c4-bcbc-058293f081d8",
"identity_id":"17fddb71-a5c2-44ce-8b50-4b381339d4f2",
"name":"email",
"type":"default",
"domain":null,
"value":"example@example.com",
"visibility":"public",
"updated":null
}
]
};
var blob = new Blob();
blob.url = exampleData.blob.url;
blob.id = exampleData.blob.id;
blob.device_id = exampleData.device_id;
blob.key = exampleData.blob.key;
blob.identity_id = exampleData.blob.identity_id;
blob.data = exampleData.blob.data;
blob.revision = exampleData.blob.data.revision;
@@ -133,14 +151,12 @@ var mockDelete;
if (!online) {
mockRippleTxt = nock('https://ripple.com')
.persist()
.get('/ripple.txt')
.reply(200, rippleTxtRes, {
'Content-Type': 'text/plain'
});
mockRippleTxt2 = nock('https://' + exampleData.domain)
.persist()
.get('/ripple.txt')
.reply(200, rippleTxtRes, {
'Content-Type': 'text/plain'
@@ -153,21 +169,21 @@ if (!online) {
'Content-Type': 'text/plain'
});
mockRegister = nock('https://id.staging.ripple.com').persist();
mockRegister = nock('https://id.staging.ripple.com');
mockRegister.filteringPath(/(v1\/user\?signature(.+))/g, 'register/')
.post('/register/')
.reply(200, { result: 'error', message: 'User already exists' }, {
'Content-Type': 'application/json'
});
mockDelete = nock('https://id.staging.ripple.com').persist();
mockDelete = nock('https://id.staging.ripple.com');
mockDelete.filteringPath(/(v1\/user\/(.+))/g, 'delete/')
.delete('/delete/')
.reply(200, { result: 'success' }, {
'Content-Type': 'application/json'
});
mockBlob = nock('https://id.staging.ripple.com').persist();
mockBlob = nock('https://id.staging.ripple.com');
mockBlob.get('/v1/authinfo?domain=' + exampleData.domain + '&username=' + exampleData.username.toLowerCase())
.reply(200, JSON.stringify(authInfoRes.body), {
'Content-Type': 'application/json'
@@ -185,47 +201,40 @@ if (!online) {
'Content-Type': 'application/json'
});
mockRename = nock('https://id.staging.ripple.com/v1/user/').persist();
mockRename = nock('https://id.staging.ripple.com/v1/user/');
mockRename.filteringPath(/((.+)\/rename(.+))/g, 'rename/')
.post('rename/')
.reply(200, {result:'success',message:'rename'}, {
'Content-Type': 'application/json'
});
mockUpdate = nock('https://id.staging.ripple.com/v1/user/').persist();
mockUpdate.filteringPath(/((.+)\/update(.+))/g, 'update/')
mockUpdate = nock('https://id.staging.ripple.com/v1/user/');
mockUpdate.filteringPath(/((.+)\/updatekeys(.+))/g, 'update/')
.post('update/')
.reply(200, {result:'success',message:'updateKeys'}, {
'Content-Type': 'application/json'
});
mockRecover = nock('https://id.staging.ripple.com/').persist();
mockRecover = nock('https://id.staging.ripple.com/')
mockRecover.filteringPath(/((.+)user\/recov\/(.+))/g, 'recov/')
.get('recov/')
.reply(200, recoverRes.body, {
'Content-Type': 'application/json'
});
mockVerify = nock('https://id.staging.ripple.com/v1/user/').persist();
mockVerify = nock('https://id.staging.ripple.com/v1/user/');
mockVerify.filteringPath(/((.+)\/verify(.+))/g, 'verify/')
.get('verify/')
.reply(200, {result:'error', message:'invalid token'}, {
'Content-Type': 'application/json'
});
mockEmail = nock('https://id.staging.ripple.com/v1/user').persist();
mockEmail = nock('https://id.staging.ripple.com/v1/user');
mockEmail.filteringPath(/((.+)\/email(.+))/g, 'email/')
.post('email/')
.reply(200, {result:'success'}, {
'Content-Type': 'application/json'
});
mockProfile = nock('https://id.staging.ripple.com/v1/user').persist();
mockProfile.filteringPath(/((.+)\/profile(.+))/g, 'profile/')
.post('profile/')
.reply(200, {result:'success'}, {
'Content-Type': 'application/json'
});
}
describe('Ripple Txt', function () {
@@ -419,6 +428,7 @@ describe('VaultClient', function () {
});
});
/*
describe('#updateProfile', function () {
it('should update profile parameters associated with a blob', function (done) {
this.timeout(10000);
@@ -442,7 +452,7 @@ describe('VaultClient', function () {
});
});
});
*/
});
@@ -693,7 +703,93 @@ describe('Blob', function () {
});
});
});
describe('identityVault', function() {
it('#identity - Get Attestation', function (done) {
var options = {
url : blob.url,
auth_secret : blob.data.auth_secret,
blob_id : blob.id,
};
options.type = 'identity';
nock('https://id.staging.ripple.com')
.filteringPath(/(v1\/attestation\/identity(.+))/g, '')
.post('/')
.reply(200, {
result: 'success',
status: 'verified',
attestation: 'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig',
blinded:'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig'
}, {'Content-Type': 'application/json'});
client.getAttestation(options, function(err, resp) {
assert.ifError(err);
assert.strictEqual(resp.result, 'success');
assert.strictEqual(typeof resp.attestation, 'string');
assert.strictEqual(typeof resp.blinded, 'string');
assert.deepEqual(resp.decoded, {"header":{"z":"z"},"payload":{"z":"z"},"signature":"sig"})
done();
});
});
it('#identity - Update Attestation', function (done) {
var options = {
url : blob.url,
auth_secret : blob.data.auth_secret,
blob_id : blob.id,
};
options.type = 'identity';
nock('https://id.staging.ripple.com')
.filteringPath(/(v1\/attestation\/identity\/update(.+))/g, '')
.post('/')
.reply(200, {
result: 'success',
status: 'verified',
attestation: 'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig',
blinded:'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig'
}, {'Content-Type': 'application/json'});
client.updateAttestation(options, function(err, resp) {
assert.ifError(err);
assert.strictEqual(resp.result, 'success');
assert.strictEqual(typeof resp.attestation, 'string');
assert.strictEqual(typeof resp.blinded, 'string');
assert.deepEqual(resp.decoded, {"header":{"z":"z"},"payload":{"z":"z"},"signature":"sig"})
done();
});
});
it('#identity - Get Attestation Summary', function (done) {
var options = {
url : blob.url,
auth_secret : blob.data.auth_secret,
blob_id : blob.id,
};
nock('https://id.staging.ripple.com')
.filteringPath(/(v1\/attestation\/summary(.+))/g, '')
.get('/')
.reply(200, {
result: 'success',
attestation: 'eyJ6IjoieiJ9.eyJ6IjoieiJ9.sig',
}, {'Content-Type': 'application/json'});
client.getAttestationSummary(options, function(err, resp) {
assert.ifError(err);
assert.strictEqual(resp.result, 'success');
assert.strictEqual(typeof resp.attestation, 'string');
assert.deepEqual(resp.decoded, {"header":{"z":"z"},"payload":{"z":"z"},"signature":"sig"})
done();
});
});
});
//only do these offline
if (!online) {