Clean up and secure subscribe books.

This commit is contained in:
Arthur Britto
2013-03-12 12:53:06 -07:00
parent ae26c6cc59
commit 04a825298e
2 changed files with 44 additions and 31 deletions

View File

@@ -1307,6 +1307,9 @@ std::vector< std::pair<uint32, uint256> > Ledger::getLedgerHashes()
return ret;
}
// XRP to XRP not allowed.
// Currencies must have appropriate issuer.
// Currencies or accounts must differ.
bool Ledger::isValidBook(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID)
{
@@ -1346,9 +1349,6 @@ bool Ledger::isValidBook(const uint160& uTakerPaysCurrency, const uint160& uTake
uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uTakerPaysIssuerID,
const uint160& uTakerGetsCurrency, const uint160& uTakerGetsIssuerID)
{
bool bInNative = uTakerPaysCurrency.isZero();
bool bOutNative = uTakerGetsCurrency.isZero();
Serializer s(82);
s.add16(spaceBookDir); // 2
@@ -1366,10 +1366,7 @@ uint256 Ledger::getBookBase(const uint160& uTakerPaysCurrency, const uint160& uT
% RippleAddress::createHumanAccountID(uTakerGetsIssuerID)
% uBaseIndex.ToString());
assert(!bInNative || !bOutNative); // XRP to XRP not allowed.
assert(bInNative == uTakerPaysIssuerID.isZero()); // Make sure issuer is specified as needed.
assert(bOutNative == uTakerGetsIssuerID.isZero()); // Make sure issuer is specified as needed.
assert(uTakerPaysCurrency != uTakerGetsCurrency || uTakerPaysIssuerID != uTakerGetsIssuerID); // Currencies or accounts must differ.
assert(isValidBook(uTakerPaysCurrency, uTakerPaysIssuerID, uTakerGetsCurrency, uTakerGetsIssuerID));
return uBaseIndex;
}

View File

@@ -2642,11 +2642,11 @@ Json::Value RPCHandler::doSubscribe(Json::Value jvRequest, int& cost)
std::string strUsername = jvRequest.isMember("url_username") ? jvRequest["url_username"].asString() : "";
std::string strPassword = jvRequest.isMember("url_password") ? jvRequest["url_password"].asString() : "";
// DEPRICATED
// DEPRECATED
if (jvRequest.isMember("username"))
strUsername = jvRequest["username"].asString();
// DEPRICATED
// DEPRECATED
if (jvRequest.isMember("password"))
strPassword = jvRequest["password"].asString();
@@ -2753,12 +2753,25 @@ Json::Value RPCHandler::doSubscribe(Json::Value jvRequest, int& cost)
}
if (jvRequest.isMember("books"))
{ // FIXME: This can crash the server if the parameters to things like getBookPage are invalid
{
for (Json::Value::iterator it = jvRequest["books"].begin(); it != jvRequest["books"].end(); it++)
{
uint160 uTakerPaysCurrencyID;
uint160 uTakerPaysIssuerID;
Json::Value jvTakerPays = (*it)["taker_pays"];
Json::Value& jvSubRequest = *it;
uint160 uTakerPaysCurrencyID;
uint160 uTakerPaysIssuerID;
uint160 uTakerGetsCurrencyID;
uint160 uTakerGetsIssuerID;
bool bBoth = (jvSubRequest.isMember("both") && jvSubRequest["both"].asBool())
|| (jvSubRequest.isMember("both_sides") && jvSubRequest["both_sides"].asBool()); // DEPRECATED
bool bSnapshot = (jvSubRequest.isMember("snapshot") && jvSubRequest["snapshot"].asBool())
|| (jvSubRequest.isMember("start_now") && jvSubRequest["start_now"].asBool()); // DEPRECATED
if (!jvSubRequest.isMember("taker_pays") || !jvSubRequest.isMember("taker_gets"))
return rpcError(rpcINVALID_PARAMS);
Json::Value jvTakerPays = jvSubRequest["taker_pays"];
Json::Value jvTakerGets = jvSubRequest["taker_gets"];
// Parse mandatory currency.
if (!jvTakerPays.isMember("currency")
@@ -2781,10 +2794,6 @@ Json::Value RPCHandler::doSubscribe(Json::Value jvRequest, int& cost)
return rpcError(rpcSRC_ISR_MALFORMED);
}
uint160 uTakerGetsCurrencyID;
uint160 uTakerGetsIssuerID;
Json::Value jvTakerGets = (*it)["taker_gets"];
// Parse mandatory currency.
if (!jvTakerGets.isMember("currency")
|| !STAmount::currencyFromString(uTakerGetsCurrencyID, jvTakerGets["currency"].asString()))
@@ -2816,38 +2825,45 @@ Json::Value RPCHandler::doSubscribe(Json::Value jvRequest, int& cost)
RippleAddress raTakerID;
if (!(*it).isMember("taker"))
if (!jvSubRequest.isMember("taker"))
{
raTakerID.setAccountID(ACCOUNT_ONE);
}
else if (!raTakerID.setAccountID((*it)["taker"].asString()))
else if (!raTakerID.setAccountID(jvSubRequest["taker"].asString()))
{
return rpcError(rpcBAD_ISSUER);
}
bool bothSides = (*it)["both_sides"].asBool();
if (!Ledger::isValidBook(uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID))
{
cLog(lsWARNING) << "Bad market: " <<
uTakerPaysCurrencyID << ":" << uTakerPaysIssuerID << " -> " <<
uTakerPaysCurrencyID << ":" << uTakerPaysIssuerID << " -> " <<
uTakerGetsCurrencyID << ":" << uTakerGetsIssuerID;
return rpcError(rpcBAD_MARKET);
}
mNetOps->subBook(ispSub, uTakerPaysCurrencyID, uTakerGetsCurrencyID, uTakerPaysIssuerID, uTakerGetsIssuerID);
if (bothSides) mNetOps->subBook(ispSub, uTakerGetsCurrencyID, uTakerPaysCurrencyID, uTakerGetsIssuerID, uTakerPaysIssuerID);
if ((*it)["state_now"].asBool())
if (bBoth) mNetOps->subBook(ispSub, uTakerGetsCurrencyID, uTakerPaysCurrencyID, uTakerGetsIssuerID, uTakerPaysIssuerID);
if (bSnapshot)
{
Ledger::pointer ledger= theApp->getLedgerMaster().getClosedLedger();
Ledger::pointer lpLedger= theApp->getLedgerMaster().getClosedLedger();
const Json::Value jvMarker = Json::Value(Json::nullValue);
mNetOps->getBookPage(ledger, uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID, raTakerID.getAccountID(), false, 0, jvMarker, jvResult);
if (bothSides)
if (bBoth)
{
Json::Value tempJson(Json::objectValue);
if (jvResult.isMember("offers")) jvResult["bids"]=jvResult["offers"];
mNetOps->getBookPage(ledger, uTakerGetsCurrencyID, uTakerGetsIssuerID, uTakerPaysCurrencyID, uTakerPaysIssuerID, raTakerID.getAccountID(), false, 0, jvMarker, tempJson);
if (tempJson.isMember("offers")) jvResult["asks"]=tempJson["offers"];
Json::Value jvBids(Json::objectValue);
Json::Value jvAsks(Json::objectValue);
mNetOps->getBookPage(lpLedger, uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID, raTakerID.getAccountID(), false, 0, jvMarker, jvBids);
if (jvBids.isMember("offers")) jvResult["bids"]=jvBids["offers"];
mNetOps->getBookPage(lpLedger, uTakerGetsCurrencyID, uTakerGetsIssuerID, uTakerPaysCurrencyID, uTakerPaysIssuerID, raTakerID.getAccountID(), false, 0, jvMarker, jvAsks);
if (jvAsks.isMember("offers")) jvResult["asks"]=jvAsks["offers"];
}
else
{
mNetOps->getBookPage(lpLedger, uTakerPaysCurrencyID, uTakerPaysIssuerID, uTakerGetsCurrencyID, uTakerGetsIssuerID, raTakerID.getAccountID(), false, 0, jvMarker, jvResult);
}
}
}