diff --git a/src/ripple_data/protocol/SerializedObject.cpp b/src/ripple_data/protocol/SerializedObject.cpp index b67cf58f0..754390634 100644 --- a/src/ripple_data/protocol/SerializedObject.cpp +++ b/src/ripple_data/protocol/SerializedObject.cpp @@ -558,7 +558,7 @@ bool STObject::clearFlag (std::uint32_t f) return true; } -bool STObject::isFlag (std::uint32_t f) +bool STObject::isFlag (std::uint32_t f) const { return (getFlags () & f) == f; } diff --git a/src/ripple_data/protocol/SerializedObject.h b/src/ripple_data/protocol/SerializedObject.h index 9362c4450..c6d6c043c 100644 --- a/src/ripple_data/protocol/SerializedObject.h +++ b/src/ripple_data/protocol/SerializedObject.h @@ -156,7 +156,7 @@ public: bool setFlag (std::uint32_t); bool clearFlag (std::uint32_t); - bool isFlag(std::uint32_t); + bool isFlag(std::uint32_t) const; std::uint32_t getFlags () const; uint256 getHash (std::uint32_t prefix) const; diff --git a/src/ripple_net/rpc/RPCCall.cpp b/src/ripple_net/rpc/RPCCall.cpp index d2ebd501c..55d357986 100644 --- a/src/ripple_net/rpc/RPCCall.cpp +++ b/src/ripple_net/rpc/RPCCall.cpp @@ -82,7 +82,7 @@ private: } else { - return RPC::make_param_error (std::string ("Invalid currency/issuer '") + + return RPC::make_param_error (std::string ("Invalid currency/issuer '") + strCurrencyIssuer + "'"); } } @@ -829,7 +829,7 @@ public: { "ripple_path_find", &RPCParser::parseRipplePathFind, 1, 2 }, { "sign", &RPCParser::parseSignSubmit, 2, 3 }, { "sms", &RPCParser::parseSMS, 1, 1 }, - { "submit", &RPCParser::parseSignSubmit, 1, 2 }, + { "submit", &RPCParser::parseSignSubmit, 1, 3 }, { "server_info", &RPCParser::parseAsIs, 0, 0 }, { "server_state", &RPCParser::parseAsIs, 0, 0 }, { "stop", &RPCParser::parseAsIs, 0, 0 }, diff --git a/src/ripple_rpc/api/ErrorCodes.h b/src/ripple_rpc/api/ErrorCodes.h index 7918ed0cc..af924c45f 100644 --- a/src/ripple_rpc/api/ErrorCodes.h +++ b/src/ripple_rpc/api/ErrorCodes.h @@ -58,6 +58,7 @@ enum error_code_i rpcACT_NOT_FOUND, rpcINSUF_FUNDS, rpcLGR_NOT_FOUND, + rpcMASTER_DISABLED, rpcNICKNAME_MISSING, rpcNO_ACCOUNT, rpcNO_PATH, diff --git a/src/ripple_rpc/impl/ErrorCodes.cpp b/src/ripple_rpc/impl/ErrorCodes.cpp index 1f5981219..db9c71ddb 100644 --- a/src/ripple_rpc/impl/ErrorCodes.cpp +++ b/src/ripple_rpc/impl/ErrorCodes.cpp @@ -52,7 +52,6 @@ public: add (rpcACT_MALFORMED, "actMalformed", "Account malformed."); add (rpcACT_NOT_FOUND, "actNotFound", "Account not found."); add (rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string."); - add (rpcHIGH_FEE, "highFee", "Current transaction fee exceeds your limit."); add (rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid."); add (rpcBAD_ISSUER, "badIssuer", "Issuer account malformed."); add (rpcBAD_MARKET, "badMarket", "No such market."); @@ -64,10 +63,11 @@ public: add (rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exist."); add (rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed."); add (rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed."); - add (rpcFORBIDDEN, "forbidden", "Bad credentials."); add (rpcFAIL_GEN_DECRYPT, "failGenDecrypt", "Failed to decrypt generator."); + add (rpcFORBIDDEN, "forbidden", "Bad credentials."); add (rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed."); add (rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed."); + add (rpcHIGH_FEE, "highFee", "Current transaction fee exceeds your limit."); add (rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed."); add (rpcINSUF_FUNDS, "insufFunds", "Insufficient funds."); add (rpcINTERNAL, "internal", "Internal error."); @@ -76,6 +76,7 @@ public: add (rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid."); add (rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed."); add (rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found."); + add (rpcMASTER_DISABLED, "masterDisabled", "Master key is disabled."); add (rpcNICKNAME_MALFORMED, "nicknameMalformed", "Nickname is malformed."); add (rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist."); add (rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname."); @@ -85,7 +86,7 @@ public: add (rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable."); add (rpcNO_EVENTS, "noEvents", "Current transport does not support events."); add (rpcNO_GEN_DECRYPT, "noGenDecrypt", "Password failed to decrypt master public generator."); - add (rpcNO_NETWORK, "noNetwork", "Network not available."); + add (rpcNO_NETWORK, "noNetwork", "Not synced to Ripple network."); add (rpcNO_PATH, "noPath", "Unable to find a ripple path."); add (rpcNO_PERMISSION, "noPermission", "You don't have permission for this command."); add (rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress."); diff --git a/src/ripple_rpc/impl/TransactionSign.cpp b/src/ripple_rpc/impl/TransactionSign.cpp index f11ce588a..10594b218 100644 --- a/src/ripple_rpc/impl/TransactionSign.cpp +++ b/src/ripple_rpc/impl/TransactionSign.cpp @@ -189,14 +189,14 @@ Json::Value transactionSign ( return RPC::make_error (rpcSRC_ACT_MALFORMED, RPC::invalid_field_message ("tx_json.Account")); - bool const bOffline ( + bool const verify = !( params.isMember ("offline") && params["offline"].asBool ()); - if (! tx_json.isMember ("Sequence") && bOffline) + if (!tx_json.isMember ("Sequence") && !verify) return RPC::missing_field_error ("tx_json.Sequence"); // Check for current ledger - if (!bOffline && !getConfig ().RUN_STANDALONE && + if (verify && !getConfig ().RUN_STANDALONE && (getApp().getLedgerMaster().getValidatedLedgerAge() > 120)) return rpcError (rpcNO_CURRENT); @@ -205,11 +205,11 @@ Json::Value transactionSign ( return rpcError(rpcTOO_BUSY); Ledger::pointer lSnapshot = netOps.getCurrentLedger (); - AccountState::pointer asSrc = bOffline + AccountState::pointer asSrc = !verify ? AccountState::pointer () // Don't look up address if offline. : netOps.getAccountState (lSnapshot, raSrcAddressID); - if (!bOffline && !asSrc) + if (verify && !asSrc) { // If not offline and did not find account, error. WriteLog (lsDEBUG, RPCHandler) << boost::str (boost::format ("transactionSign: Failed to find source account in current ledger: %s") @@ -311,9 +311,10 @@ Json::Value transactionSign ( if (!tx_json.isMember ("Sequence")) { - if (bOffline) + if (!verify) { // If offline, Sequence is mandatory. + // TODO: duplicates logic above. return rpcError (rpcINVALID_PARAMS); } else @@ -324,7 +325,7 @@ Json::Value transactionSign ( if (!tx_json.isMember ("Flags")) tx_json["Flags"] = tfFullyCanonicalSig; - if (!bOffline) + if (verify) { SLE::pointer sleAccountRoot = netOps.getSLEi (lSnapshot, Ledger::getAccountRootIndex (raSrcAddressID.getAccountID ())); @@ -344,41 +345,35 @@ Json::Value transactionSign ( RippleAddress naMasterGenerator = RippleAddress::createGeneratorPublic ( naSecret); - // Find the index of Account from the master generator, so we can generate - // the public and private keys. - RippleAddress naMasterAccountPublic; - unsigned int iIndex = 0; - bool bFound = false; - - // Don't look at ledger entries to determine if the account exists. - // Don't want to leak to thin server that these accounts are related. - while (!bFound && iIndex != getConfig ().ACCOUNT_PROBE_MAX) + if (verify) { - naMasterAccountPublic.setAccountPublic (naMasterGenerator, iIndex); + auto masterAccountPublic = RippleAddress::createAccountPublic ( + naMasterGenerator, 0); + auto account = masterAccountPublic.getAccountID(); + auto const& sle = asSrc->peekSLE(); WriteLog (lsWARNING, RPCHandler) << - "authorize: " << iIndex << - " : " << naMasterAccountPublic.humanAccountID () << - " : " << raSrcAddressID.humanAccountID (); - - bFound = raSrcAddressID.getAccountID () == naMasterAccountPublic.getAccountID (); - - if (!bFound) - ++iIndex; - } - - if (!bFound) - { - return rpcError (rpcBAD_SECRET); + "verify: " << masterAccountPublic.humanAccountID () << + " : " << raSrcAddressID.humanAccountID (); + if (raSrcAddressID.getAccountID () == account) + { + if (sle.isFlag(lsfDisableMaster)) + return rpcError (rpcMASTER_DISABLED); + } + else if (!sle.isFieldPresent(sfRegularKey) || + account != sle.getFieldAccount160 (sfRegularKey)) + { + return rpcError (rpcBAD_SECRET); + } } // Use the generator to determine the associated public and private keys. RippleAddress naGenerator = RippleAddress::createGeneratorPublic ( naSecret); RippleAddress naAccountPublic = RippleAddress::createAccountPublic ( - naGenerator, iIndex); + naGenerator, 0); RippleAddress naAccountPrivate = RippleAddress::createAccountPrivate ( - naGenerator, naSecret, iIndex); + naGenerator, naSecret, 0); if (bHaveAuthKey // The generated pair must match authorized... @@ -386,6 +381,7 @@ Json::Value transactionSign ( // ... or the master key must have been used. && raSrcAddressID.getAccountID () != naAccountPublic.getAccountID ()) { + // TODO: we can't ever get here! // Log::out() << "iIndex: " << iIndex; // Log::out() << "sfAuthorizedKey: " << strHex(asSrc->getAuthorizedKey().getAccountID()); // Log::out() << "naAccountPublic: " << strHex(naAccountPublic.getAccountID());