mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-01 07:55:49 +00:00
Allow channel_authorize to use Ed25519 keys
This commit is contained in:
committed by
Manoj doshi
parent
a3a9dc26b4
commit
113167acf4
@@ -717,23 +717,43 @@ private:
|
||||
return parseAccountRaw2 (jvParams, jss::destination_account);
|
||||
}
|
||||
|
||||
// channel_authorize <private_key> <channel_id> <drops>
|
||||
// channel_authorize: <private_key> [<key_type>] <channel_id> <drops>
|
||||
Json::Value parseChannelAuthorize (Json::Value const& jvParams)
|
||||
{
|
||||
Json::Value jvRequest (Json::objectValue);
|
||||
|
||||
jvRequest[jss::secret] = jvParams[0u];
|
||||
unsigned int index = 0;
|
||||
|
||||
if (jvParams.size() == 4)
|
||||
{
|
||||
jvRequest[jss::passphrase] = jvParams[index];
|
||||
index++;
|
||||
|
||||
if (!keyTypeFromString(jvParams[index].asString()))
|
||||
return rpcError (rpcBAD_KEY_TYPE);
|
||||
jvRequest[jss::key_type] = jvParams[index];
|
||||
index++;
|
||||
}
|
||||
else
|
||||
{
|
||||
jvRequest[jss::secret] = jvParams[index];
|
||||
index++;
|
||||
}
|
||||
|
||||
{
|
||||
// verify the channel id is a valid 256 bit number
|
||||
uint256 channelId;
|
||||
if (!channelId.SetHexExact (jvParams[1u].asString ()))
|
||||
if (!channelId.SetHexExact (jvParams[index].asString()))
|
||||
return rpcError (rpcCHANNEL_MALFORMED);
|
||||
jvRequest[jss::channel_id] = to_string(channelId);
|
||||
index++;
|
||||
}
|
||||
jvRequest[jss::channel_id] = jvParams[1u].asString ();
|
||||
|
||||
if (!jvParams[2u].isString() || !to_uint64(jvParams[2u].asString()))
|
||||
if (!jvParams[index].isString() || !to_uint64(jvParams[index].asString()))
|
||||
return rpcError(rpcCHANNEL_AMT_MALFORMED);
|
||||
jvRequest[jss::amount] = jvParams[2u];
|
||||
jvRequest[jss::amount] = jvParams[index];
|
||||
|
||||
// If additional parameters are appended, be sure to increment index here
|
||||
|
||||
return jvRequest;
|
||||
}
|
||||
@@ -1122,7 +1142,7 @@ public:
|
||||
{ "account_tx", &RPCParser::parseAccountTransactions, 1, 8 },
|
||||
{ "book_offers", &RPCParser::parseBookOffers, 2, 7 },
|
||||
{ "can_delete", &RPCParser::parseCanDelete, 0, 1 },
|
||||
{ "channel_authorize", &RPCParser::parseChannelAuthorize, 3, 3 },
|
||||
{ "channel_authorize", &RPCParser::parseChannelAuthorize, 3, 4 },
|
||||
{ "channel_verify", &RPCParser::parseChannelVerify, 4, 4 },
|
||||
{ "connect", &RPCParser::parseConnect, 1, 2 },
|
||||
{ "consensus_info", &RPCParser::parseAsIs, 0, 0 },
|
||||
|
||||
@@ -131,7 +131,8 @@ enum error_code_i
|
||||
rpcINTERNAL = 73, // Generic internal error.
|
||||
rpcNOT_IMPL = 74,
|
||||
rpcNOT_SUPPORTED = 75,
|
||||
rpcLAST = rpcNOT_SUPPORTED // rpcLAST should always equal the last code.
|
||||
rpcBAD_KEY_TYPE = 76,
|
||||
rpcLAST = rpcBAD_KEY_TYPE // rpcLAST should always equal the last code.
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -39,6 +39,7 @@ constexpr static ErrorInfo unorderedErrorInfos[]
|
||||
{rpcALREADY_SINGLE_SIG, "alreadySingleSig", "Already single-signed."},
|
||||
{rpcAMENDMENT_BLOCKED, "amendmentBlocked", "Amendment blocked, need upgrade."},
|
||||
{rpcATX_DEPRECATED, "deprecated", "Use the new API or specify a ledger range."},
|
||||
{rpcBAD_KEY_TYPE, "badKeyType", "Bad key type."},
|
||||
{rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid."},
|
||||
{rpcBAD_ISSUER, "badIssuer", "Issuer account malformed."},
|
||||
{rpcBAD_MARKET, "badMarket", "No such market."},
|
||||
|
||||
@@ -36,16 +36,23 @@ namespace ripple {
|
||||
|
||||
// {
|
||||
// secret_key: <signing_secret_key>
|
||||
// key_type: optional; either ed25519 or secp256k1 (default to secp256k1)
|
||||
// channel_id: 256-bit channel id
|
||||
// drops: 64-bit uint (as string)
|
||||
// }
|
||||
Json::Value doChannelAuthorize (RPC::Context& context)
|
||||
{
|
||||
auto const& params (context.params);
|
||||
for (auto const& p : {jss::secret, jss::channel_id, jss::amount})
|
||||
for (auto const& p : {jss::channel_id, jss::amount})
|
||||
if (!params.isMember (p))
|
||||
return RPC::missing_field_error (p);
|
||||
|
||||
// Compatibility if a key type isn't specified. If it is, the
|
||||
// keypairForSignature code will validate parameters and return
|
||||
// the appropriate error.
|
||||
if (!params.isMember(jss::key_type) && !params.isMember(jss::secret))
|
||||
return RPC::missing_field_error (jss::secret);
|
||||
|
||||
Json::Value result;
|
||||
auto const [pk, sk] = RPC::keypairForSignature (params, result);
|
||||
if (RPC::contains_error (result))
|
||||
|
||||
@@ -878,7 +878,8 @@ struct PayChan_test : public beast::unit_test::suite
|
||||
Env env (*this);
|
||||
auto const alice = Account ("alice");
|
||||
auto const bob = Account ("bob");
|
||||
env.fund (XRP (10000), alice, bob);
|
||||
auto const charlie = Account("charlie", KeyType::ed25519);
|
||||
env.fund (XRP (10000), alice, bob, charlie);
|
||||
auto const pk = alice.pk ();
|
||||
auto const settleDelay = 3600s;
|
||||
auto const channelFunds = XRP (1000);
|
||||
@@ -1036,6 +1037,63 @@ struct PayChan_test : public beast::unit_test::suite
|
||||
!rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
}
|
||||
{
|
||||
// Try to explicitly specify secp256k1 and Ed25519 keys:
|
||||
env (create (charlie, alice, channelFunds, settleDelay, charlie.pk()));
|
||||
env.close();
|
||||
|
||||
auto const chan = to_string (channel (*env.current (), charlie, alice));
|
||||
|
||||
std::string cpk;
|
||||
{
|
||||
auto const r =
|
||||
env.rpc ("account_channels", charlie.human (), alice.human ());
|
||||
BEAST_EXPECT (r[jss::result][jss::channels].size () == 1);
|
||||
BEAST_EXPECT (r[jss::result][jss::channels][0u][jss::channel_id] == chan);
|
||||
BEAST_EXPECT (r[jss::result][jss::validated]);
|
||||
cpk = r[jss::result][jss::channels][0u][jss::public_key].asString();
|
||||
}
|
||||
|
||||
// Try to authorize without specifying a key type, expect an error:
|
||||
auto const rs =
|
||||
env.rpc ("channel_authorize", "charlie", chan, "1000");
|
||||
auto const sig = rs[jss::result][jss::signature].asString ();
|
||||
BEAST_EXPECT (!sig.empty ());
|
||||
{
|
||||
auto const rv = env.rpc(
|
||||
"channel_verify", cpk, chan, "1000", sig);
|
||||
BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
|
||||
// Try to authorize using an unknown key type, except an error:
|
||||
auto const rs1 =
|
||||
env.rpc ("channel_authorize", "charlie", "nyx", chan, "1000");
|
||||
BEAST_EXPECT(rs1[jss::error] == "badKeyType");
|
||||
|
||||
// Try to authorize using secp256k1; the authorization _should_
|
||||
// succeed but the verification should fail:
|
||||
auto const rs2 =
|
||||
env.rpc ("channel_authorize", "charlie", "secp256k1", chan, "1000");
|
||||
auto const sig2 = rs2[jss::result][jss::signature].asString ();
|
||||
BEAST_EXPECT (!sig2.empty ());
|
||||
{
|
||||
auto const rv = env.rpc(
|
||||
"channel_verify", cpk, chan, "1000", sig2);
|
||||
BEAST_EXPECT(!rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
|
||||
// Try to authorize using Ed25519; expect success:
|
||||
auto const rs3 =
|
||||
env.rpc ("channel_authorize", "charlie", "ed25519", chan, "1000");
|
||||
auto const sig3 = rs3[jss::result][jss::signature].asString ();
|
||||
BEAST_EXPECT (!sig3.empty ());
|
||||
{
|
||||
auto const rv = env.rpc(
|
||||
"channel_verify", cpk, chan, "1000", sig3);
|
||||
BEAST_EXPECT(rv[jss::result][jss::signature_verified].asBool());
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// send malformed amounts rpc requests
|
||||
auto rs = env.rpc("channel_authorize", "alice", chan1Str, "1000x");
|
||||
@@ -1044,6 +1102,81 @@ struct PayChan_test : public beast::unit_test::suite
|
||||
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
|
||||
rs = env.rpc("channel_authorize", "alice", chan1Str, "x");
|
||||
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
|
||||
{
|
||||
// Missing channel_id
|
||||
Json::Value args {Json::objectValue};
|
||||
args[jss::amount] = "2000";
|
||||
args[jss::key_type] = "secp256k1";
|
||||
args[jss::passphrase] = "passphrase_can_be_anything";
|
||||
rs = env.rpc ("json",
|
||||
"channel_authorize", args.toStyledString())[jss::result];
|
||||
BEAST_EXPECT(rs[jss::error] == "invalidParams");
|
||||
}
|
||||
{
|
||||
// Missing amount
|
||||
Json::Value args {Json::objectValue};
|
||||
args[jss::channel_id] = chan1Str;
|
||||
args[jss::key_type] = "secp256k1";
|
||||
args[jss::passphrase] = "passphrase_can_be_anything";
|
||||
rs = env.rpc ("json",
|
||||
"channel_authorize", args.toStyledString())[jss::result];
|
||||
BEAST_EXPECT(rs[jss::error] == "invalidParams");
|
||||
}
|
||||
{
|
||||
// Missing key_type and no secret.
|
||||
Json::Value args {Json::objectValue};
|
||||
args[jss::amount] = "2000";
|
||||
args[jss::channel_id] = chan1Str;
|
||||
args[jss::passphrase] = "passphrase_can_be_anything";
|
||||
rs = env.rpc ("json",
|
||||
"channel_authorize", args.toStyledString())[jss::result];
|
||||
BEAST_EXPECT(rs[jss::error] == "invalidParams");
|
||||
}
|
||||
{
|
||||
// Both passphrase and seed specified.
|
||||
Json::Value args {Json::objectValue};
|
||||
args[jss::amount] = "2000";
|
||||
args[jss::channel_id] = chan1Str;
|
||||
args[jss::key_type] = "secp256k1";
|
||||
args[jss::passphrase] = "passphrase_can_be_anything";
|
||||
args[jss::seed] = "seed can be anything";
|
||||
rs = env.rpc ("json",
|
||||
"channel_authorize", args.toStyledString())[jss::result];
|
||||
BEAST_EXPECT(rs[jss::error] == "invalidParams");
|
||||
}
|
||||
{
|
||||
// channel_id is not exact hex.
|
||||
Json::Value args {Json::objectValue};
|
||||
args[jss::amount] = "2000";
|
||||
args[jss::channel_id] = chan1Str + "1";
|
||||
args[jss::key_type] = "secp256k1";
|
||||
args[jss::passphrase] = "passphrase_can_be_anything";
|
||||
rs = env.rpc ("json",
|
||||
"channel_authorize", args.toStyledString())[jss::result];
|
||||
BEAST_EXPECT(rs[jss::error] == "channelMalformed");
|
||||
}
|
||||
{
|
||||
//amount is not a string
|
||||
Json::Value args {Json::objectValue};
|
||||
args[jss::amount] = 2000;
|
||||
args[jss::channel_id] = chan1Str;
|
||||
args[jss::key_type] = "secp256k1";
|
||||
args[jss::passphrase] = "passphrase_can_be_anything";
|
||||
rs = env.rpc ("json",
|
||||
"channel_authorize", args.toStyledString())[jss::result];
|
||||
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
|
||||
}
|
||||
{
|
||||
// Amount is not a decimal string.
|
||||
Json::Value args {Json::objectValue};
|
||||
args[jss::amount] = "TwoThousand";
|
||||
args[jss::channel_id] = chan1Str;
|
||||
args[jss::key_type] = "secp256k1";
|
||||
args[jss::passphrase] = "passphrase_can_be_anything";
|
||||
rs = env.rpc ("json",
|
||||
"channel_authorize", args.toStyledString())[jss::result];
|
||||
BEAST_EXPECT(rs[jss::error] == "channelAmtMalformed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2222,10 +2222,11 @@ static RPCCallTestData const rpcCallTestArray [] =
|
||||
"channel_authorize: too many arguments.", __LINE__,
|
||||
{
|
||||
"channel_authorize",
|
||||
"secret_can_be_anything",
|
||||
"secp256k1",
|
||||
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF",
|
||||
"2000",
|
||||
"whatever"
|
||||
"whatever",
|
||||
"whenever"
|
||||
},
|
||||
RPCCallTestData::no_exception,
|
||||
R"({
|
||||
@@ -2239,6 +2240,27 @@ static RPCCallTestData const rpcCallTestArray [] =
|
||||
]
|
||||
})"
|
||||
},
|
||||
{
|
||||
"channel_authorize: bad key type.", __LINE__,
|
||||
{
|
||||
"channel_authorize",
|
||||
"secp257k1",
|
||||
"0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF",
|
||||
"2000",
|
||||
"whatever"
|
||||
},
|
||||
RPCCallTestData::no_exception,
|
||||
R"({
|
||||
"method" : "channel_authorize",
|
||||
"params" : [
|
||||
{
|
||||
"error" : "badKeyType",
|
||||
"error_code" : 1,
|
||||
"error_message" : "Bad key type."
|
||||
}
|
||||
]
|
||||
})"
|
||||
},
|
||||
{
|
||||
"channel_authorize: channel_id too short.", __LINE__,
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user