mirror of
https://github.com/Xahau/xahaud.git
synced 2025-11-28 22:45:49 +00:00
Allow channel_verify to specify public key in hex (RIPD-1467)
This commit is contained in:
committed by
Nikolaos D. Bougalis
parent
ad4ba44394
commit
a307d2d03f
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <BeastConfig.h>
|
||||
#include <ripple/app/main/Application.h>
|
||||
#include <ripple/basics/StringUtilities.h>
|
||||
#include <ripple/net/RPCCall.h>
|
||||
#include <ripple/net/RPCErr.h>
|
||||
#include <ripple/basics/contract.h>
|
||||
@@ -37,6 +38,7 @@
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
#include <beast/core/string.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
@@ -82,6 +84,33 @@ std::string createHTTPPost (
|
||||
return s.str ();
|
||||
}
|
||||
|
||||
static
|
||||
boost::optional<std::uint64_t>
|
||||
to_uint64(std::string const& s)
|
||||
{
|
||||
if (s.empty())
|
||||
return boost::none;
|
||||
|
||||
for (auto c : s)
|
||||
{
|
||||
if (!isdigit(c))
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::size_t pos{};
|
||||
auto const drops = std::stoul(s, &pos);
|
||||
if (s.size() != pos)
|
||||
return boost::none;
|
||||
return drops;
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
class RPCParser
|
||||
{
|
||||
private:
|
||||
@@ -680,16 +709,9 @@ private:
|
||||
}
|
||||
jvRequest[jss::channel_id] = jvParams[1u].asString ();
|
||||
|
||||
try
|
||||
{
|
||||
auto const drops = std::stoul (jvParams[2u].asString ());
|
||||
(void)drops; // just used for error checking
|
||||
jvRequest[jss::amount] = jvParams[2u];
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return rpcError (rpcCHANNEL_AMT_MALFORMED);
|
||||
}
|
||||
if (!jvParams[2u].isString() || !to_uint64(jvParams[2u].asString()))
|
||||
return rpcError(rpcCHANNEL_AMT_MALFORMED);
|
||||
jvRequest[jss::amount] = jvParams[2u];
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
@@ -699,7 +721,21 @@ private:
|
||||
{
|
||||
std::string const strPk = jvParams[0u].asString ();
|
||||
|
||||
if (!parseBase58<PublicKey> (TokenType::TOKEN_ACCOUNT_PUBLIC, strPk))
|
||||
bool const validPublicKey = [&strPk]{
|
||||
if (parseBase58<PublicKey> (TokenType::TOKEN_ACCOUNT_PUBLIC, strPk))
|
||||
return true;
|
||||
|
||||
std::pair<Blob, bool> pkHex(strUnHex (strPk));
|
||||
if (!pkHex.second)
|
||||
return false;
|
||||
|
||||
if (!publicKeyType(makeSlice(pkHex.first)))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}();
|
||||
|
||||
if (!validPublicKey)
|
||||
return rpcError (rpcPUBLIC_MALFORMED);
|
||||
|
||||
Json::Value jvRequest (Json::objectValue);
|
||||
@@ -712,16 +748,11 @@ private:
|
||||
return rpcError (rpcCHANNEL_MALFORMED);
|
||||
}
|
||||
jvRequest[jss::channel_id] = jvParams[1u].asString ();
|
||||
try
|
||||
{
|
||||
auto const drops = std::stoul (jvParams[2u].asString ());
|
||||
(void)drops; // just used for error checking
|
||||
jvRequest[jss::amount] = jvParams[2u];
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return rpcError (rpcCHANNEL_AMT_MALFORMED);
|
||||
}
|
||||
|
||||
if (!jvParams[2u].isString() || !to_uint64(jvParams[2u].asString()))
|
||||
return rpcError(rpcCHANNEL_AMT_MALFORMED);
|
||||
jvRequest[jss::amount] = jvParams[2u];
|
||||
|
||||
jvRequest[jss::signature] = jvParams[3u].asString ();
|
||||
|
||||
return jvRequest;
|
||||
|
||||
@@ -31,8 +31,37 @@
|
||||
#include <ripple/rpc/impl/RPCHelpers.h>
|
||||
#include <ripple/rpc/impl/Tuning.h>
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
static
|
||||
boost::optional<std::uint64_t>
|
||||
to_uint64(std::string const& s)
|
||||
{
|
||||
if (s.empty())
|
||||
return boost::none;
|
||||
|
||||
for (auto c : s)
|
||||
{
|
||||
if (!isdigit(c))
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
std::size_t pos{};
|
||||
auto const drops = std::stoul(s, &pos);
|
||||
if (s.size() != pos)
|
||||
return boost::none;
|
||||
return drops;
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
// {
|
||||
// secret_key: <signing_secret_key>
|
||||
// channel_id: 256-bit channel id
|
||||
@@ -54,15 +83,15 @@ Json::Value doChannelAuthorize (RPC::Context& context)
|
||||
if (!channelId.SetHexExact (params[jss::channel_id].asString ()))
|
||||
return rpcError (rpcCHANNEL_MALFORMED);
|
||||
|
||||
std::uint64_t drops = 0;
|
||||
try
|
||||
{
|
||||
drops = std::stoul (params[jss::amount].asString ());
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
boost::optional<std::uint64_t> const optDrops =
|
||||
params[jss::amount].isString()
|
||||
? to_uint64(params[jss::amount].asString())
|
||||
: boost::none;
|
||||
|
||||
if (!optDrops)
|
||||
return rpcError (rpcCHANNEL_AMT_MALFORMED);
|
||||
}
|
||||
|
||||
std::uint64_t const drops = *optDrops;
|
||||
|
||||
Serializer msg;
|
||||
serializePayChanAuthorization (msg, channelId, XRPAmount (drops));
|
||||
@@ -90,29 +119,40 @@ Json::Value doChannelVerify (RPC::Context& context)
|
||||
{
|
||||
auto const& params (context.params);
|
||||
for (auto const& p :
|
||||
{jss::public_key, jss::channel_id, jss::amount, jss::signature})
|
||||
{jss::public_key, jss::channel_id, jss::amount, jss::signature})
|
||||
if (!params.isMember (p))
|
||||
return RPC::missing_field_error (p);
|
||||
|
||||
std::string const strPk = params[jss::public_key].asString ();
|
||||
auto const pk =
|
||||
parseBase58<PublicKey> (TokenType::TOKEN_ACCOUNT_PUBLIC, strPk);
|
||||
if (!pk)
|
||||
return rpcError (rpcPUBLIC_MALFORMED);
|
||||
boost::optional<PublicKey> pk;
|
||||
{
|
||||
std::string const strPk = params[jss::public_key].asString();
|
||||
pk = parseBase58<PublicKey>(TokenType::TOKEN_ACCOUNT_PUBLIC, strPk);
|
||||
|
||||
if (!pk)
|
||||
{
|
||||
std::pair<Blob, bool> pkHex(strUnHex (strPk));
|
||||
if (!pkHex.second)
|
||||
return rpcError(rpcPUBLIC_MALFORMED);
|
||||
auto const pkType = publicKeyType(makeSlice(pkHex.first));
|
||||
if (!pkType)
|
||||
return rpcError(rpcPUBLIC_MALFORMED);
|
||||
pk.emplace(makeSlice(pkHex.first));
|
||||
}
|
||||
}
|
||||
|
||||
uint256 channelId;
|
||||
if (!channelId.SetHexExact (params[jss::channel_id].asString ()))
|
||||
return rpcError (rpcCHANNEL_MALFORMED);
|
||||
|
||||
std::uint64_t drops = 0;
|
||||
try
|
||||
{
|
||||
drops = std::stoul (params[jss::amount].asString ());
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
boost::optional<std::uint64_t> const optDrops =
|
||||
params[jss::amount].isString()
|
||||
? to_uint64(params[jss::amount].asString())
|
||||
: boost::none;
|
||||
|
||||
if (!optDrops)
|
||||
return rpcError (rpcCHANNEL_AMT_MALFORMED);
|
||||
}
|
||||
|
||||
std::uint64_t const drops = *optDrops;
|
||||
|
||||
std::pair<Blob, bool> sig(strUnHex (params[jss::signature].asString ()));
|
||||
if (!sig.second || !sig.first.size ())
|
||||
|
||||
@@ -766,15 +766,99 @@ struct PayChan_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT (r[jss::result][jss::channels][0u][jss::channel_id] == c ||
|
||||
r[jss::result][jss::channels][1u][jss::channel_id] == c);
|
||||
}
|
||||
|
||||
auto sliceToHex = [](Slice const& slice) {
|
||||
std::string s;
|
||||
s.reserve(2 * slice.size());
|
||||
for (int i = 0; i < slice.size(); ++i)
|
||||
{
|
||||
s += "0123456789ABCDEF"[((slice[i] & 0xf0) >> 4)];
|
||||
s += "0123456789ABCDEF"[((slice[i] & 0x0f) >> 0)];
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
{
|
||||
// Verify chan1 auth
|
||||
auto const rs =
|
||||
env.rpc ("channel_authorize", "alice", chan1Str, "1000");
|
||||
auto const sig = rs[jss::result][jss::signature].asString ();
|
||||
BEAST_EXPECT (!sig.empty ());
|
||||
auto const rv = env.rpc (
|
||||
"channel_verify", chan1PkStr, chan1Str, "1000", sig);
|
||||
BEAST_EXPECT (rv[jss::result][jss::signature_verified].asBool ());
|
||||
{
|
||||
auto const rv = env.rpc(
|
||||
"channel_verify", chan1PkStr, chan1Str, "1000", sig);
|
||||
BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
|
||||
{
|
||||
// use pk hex to verify
|
||||
auto const pkAsHex = sliceToHex(pk.slice());
|
||||
auto const rv = env.rpc (
|
||||
"channel_verify", pkAsHex, chan1Str, "1000", sig);
|
||||
BEAST_EXPECT (rv[jss::result][jss::signature_verified].asBool ());
|
||||
}
|
||||
{
|
||||
// malformed amount
|
||||
auto const pkAsHex = sliceToHex(pk.slice());
|
||||
auto rv =
|
||||
env.rpc("channel_verify", pkAsHex, chan1Str, "1000x", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000 ", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "x1000", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "x", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1Str, " ", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1000 1000", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "1,000", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1Str, " 1000", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1Str, "", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelAmtMalformed");
|
||||
}
|
||||
{
|
||||
// malformed channel
|
||||
auto const pkAsHex = sliceToHex(pk.slice());
|
||||
auto chan1StrBad = chan1Str;
|
||||
chan1StrBad.pop_back();
|
||||
auto rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
|
||||
rv = env.rpc ("channel_authorize", "alice", chan1StrBad, "1000");
|
||||
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
|
||||
|
||||
chan1StrBad = chan1Str;
|
||||
chan1StrBad.push_back('0');
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
|
||||
rv = env.rpc ("channel_authorize", "alice", chan1StrBad, "1000");
|
||||
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
|
||||
|
||||
chan1StrBad = chan1Str;
|
||||
chan1StrBad.back() = 'x';
|
||||
rv = env.rpc("channel_verify", pkAsHex, chan1StrBad, "1000", sig);
|
||||
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
|
||||
rv = env.rpc ("channel_authorize", "alice", chan1StrBad, "1000");
|
||||
BEAST_EXPECT(rv[jss::error] == "channelMalformed");
|
||||
}
|
||||
{
|
||||
// give an ill formed base 58 public key
|
||||
auto illFormedPk = chan1PkStr.substr(0, chan1PkStr.size() - 1);
|
||||
auto const rv = env.rpc(
|
||||
"channel_verify", illFormedPk, chan1Str, "1000", sig);
|
||||
BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
{
|
||||
// give an ill formed hex public key
|
||||
auto const pkAsHex = sliceToHex(pk.slice());
|
||||
auto illFormedPk = pkAsHex.substr(0, chan1PkStr.size() - 1);
|
||||
auto const rv = env.rpc(
|
||||
"channel_verify", illFormedPk, chan1Str, "1000", sig);
|
||||
BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
}
|
||||
{
|
||||
// Try to verify chan2 auth with chan1 key
|
||||
@@ -782,9 +866,29 @@ struct PayChan_test : public beast::unit_test::suite
|
||||
env.rpc ("channel_authorize", "alice", chan2Str, "1000");
|
||||
auto const sig = rs[jss::result][jss::signature].asString ();
|
||||
BEAST_EXPECT (!sig.empty ());
|
||||
auto const rv =
|
||||
env.rpc ("channel_verify", chan1PkStr, chan1Str, "1000", sig);
|
||||
BEAST_EXPECT (!rv[jss::result][jss::signature_verified].asBool ());
|
||||
{
|
||||
auto const rv = env.rpc(
|
||||
"channel_verify", chan1PkStr, chan1Str, "1000", sig);
|
||||
BEAST_EXPECT(
|
||||
!rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
{
|
||||
// use pk hex to verify
|
||||
auto const pkAsHex = sliceToHex(pk.slice());
|
||||
auto const rv = env.rpc(
|
||||
"channel_verify", pkAsHex, chan1Str, "1000", sig);
|
||||
BEAST_EXPECT(
|
||||
!rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
}
|
||||
{
|
||||
// send malformed amounts rpc requests
|
||||
auto rs = env.rpc("channel_authorize", "alice", chan1Str, "1000x");
|
||||
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
|
||||
rs = env.rpc("channel_authorize", "alice", chan1Str, "x1000");
|
||||
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
|
||||
rs = env.rpc("channel_authorize", "alice", chan1Str, "x");
|
||||
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user