Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/nnamon/turtlecoin
Browse files Browse the repository at this point in the history
  • Loading branch information
nnamon committed Feb 2, 2018
2 parents 4d6d092 + 545105a commit b759b12
Show file tree
Hide file tree
Showing 13 changed files with 139 additions and 8 deletions.
22 changes: 20 additions & 2 deletions src/JsonRpcServer/JsonRpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,12 @@

namespace CryptoNote {

JsonRpcServer::JsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, Logging::ILogger& loggerGroup) :
JsonRpcServer::JsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, Logging::ILogger& loggerGroup, PaymentService::Configuration& config) :
HttpServer(sys, loggerGroup),
system(sys),
stopEvent(stopEvent),
logger(loggerGroup, "JsonRpcServer")
logger(loggerGroup, "JsonRpcServer"),
config(config)
{
}

Expand Down Expand Up @@ -164,6 +165,23 @@ void JsonRpcServer::makeMethodNotFoundResponse(Common::JsonValue& resp) {
resp.insert("error", error);
}

void JsonRpcServer::makeInvalidPasswordResponse(Common::JsonValue& resp) {
using Common::JsonValue;

JsonValue error(JsonValue::OBJECT);

JsonValue code;
code = static_cast<int64_t>(-32604);

JsonValue message;
message = "Invalid or no rpc password";

error.insert("code", code);
error.insert("message", message);

resp.insert("error", error);
}

void JsonRpcServer::fillJsonResponse(const Common::JsonValue& v, Common::JsonValue& resp) {
resp.insert("result", v);
}
Expand Down
5 changes: 4 additions & 1 deletion src/JsonRpcServer/JsonRpcServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "Logging/ILogger.h"
#include "Logging/LoggerRef.h"
#include "Rpc/HttpServer.h"
#include "PaymentGateService/PaymentServiceConfiguration.h"


namespace CryptoNote {
Expand All @@ -43,20 +44,22 @@ namespace CryptoNote {

class JsonRpcServer : HttpServer {
public:
JsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, Logging::ILogger& loggerGroup);
JsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, Logging::ILogger& loggerGroup, PaymentService::Configuration& config);
JsonRpcServer(const JsonRpcServer&) = delete;

void start(const std::string& bindAddress, uint16_t bindPort);

protected:
static void makeErrorResponse(const std::error_code& ec, Common::JsonValue& resp);
static void makeMethodNotFoundResponse(Common::JsonValue& resp);
static void makeInvalidPasswordResponse(Common::JsonValue& resp);
static void makeGenericErrorReponse(Common::JsonValue& resp, const char* what, int errorCode = -32001);
static void fillJsonResponse(const Common::JsonValue& v, Common::JsonValue& resp);
static void prepareJsonResponse(const Common::JsonValue& req, Common::JsonValue& resp);
static void makeJsonParsingErrorResponse(Common::JsonValue& resp);

virtual void processJsonRpcRequest(const Common::JsonValue& req, Common::JsonValue& resp) = 0;
PaymentService::Configuration& config;

private:
// HttpServer
Expand Down
23 changes: 21 additions & 2 deletions src/PaymentGate/PaymentServiceJsonRpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
#include "Serialization/JsonInputValueSerializer.h"
#include "Serialization/JsonOutputStreamSerializer.h"

#include "Rpc/JsonRpc.h"

namespace PaymentService {

PaymentServiceJsonRpcServer::PaymentServiceJsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, WalletService& service, Logging::ILogger& loggerGroup)
: JsonRpcServer(sys, stopEvent, loggerGroup)
PaymentServiceJsonRpcServer::PaymentServiceJsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, WalletService& service, Logging::ILogger& loggerGroup, PaymentService::Configuration& config)
: JsonRpcServer(sys, stopEvent, loggerGroup, config)
, service(service)
, logger(loggerGroup, "PaymentServiceJsonRpcServer")
{
Expand Down Expand Up @@ -60,6 +62,23 @@ PaymentServiceJsonRpcServer::PaymentServiceJsonRpcServer(System::Dispatcher& sys
void PaymentServiceJsonRpcServer::processJsonRpcRequest(const Common::JsonValue& req, Common::JsonValue& resp) {
try {
prepareJsonResponse(req, resp);

if (!config.legacySecurity) {
std::string clientPassword;
if (!req.contains("password")) {
makeInvalidPasswordResponse(resp);
return;
}
if (!req("password").isString()) {
makeInvalidPasswordResponse(resp);
return;
}
clientPassword = req("password").getString();
if (clientPassword != config.rpcPassword) {
makeInvalidPasswordResponse(resp);
return;
}
}

if (!req.contains("method")) {
logger(Logging::WARNING) << "Field \"method\" is not found in json request: " << req;
Expand Down
2 changes: 1 addition & 1 deletion src/PaymentGate/PaymentServiceJsonRpcServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class WalletService;

class PaymentServiceJsonRpcServer : public CryptoNote::JsonRpcServer {
public:
PaymentServiceJsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, WalletService& service, Logging::ILogger& loggerGroup);
PaymentServiceJsonRpcServer(System::Dispatcher& sys, System::Event& stopEvent, WalletService& service, Logging::ILogger& loggerGroup, PaymentService::Configuration& config);
PaymentServiceJsonRpcServer(const PaymentServiceJsonRpcServer&) = delete;

protected:
Expand Down
2 changes: 1 addition & 1 deletion src/PaymentGateService/PaymentGateService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ void PaymentGateService::runWalletService(const CryptoNote::Currency& currency,
std::cout << "Address: " << address << std::endl;
}
} else {
PaymentService::PaymentServiceJsonRpcServer rpcServer(*dispatcher, *stopEvent, *service, logger);
PaymentService::PaymentServiceJsonRpcServer rpcServer(*dispatcher, *stopEvent, *service, logger, config.gateConfiguration);
rpcServer.start(config.gateConfiguration.bindAddress, config.gateConfiguration.bindPort);

Logging::LoggerRef(logger, "PaymentGateService")(Logging::INFO, Logging::BRIGHT_WHITE) << "JSON-RPC server stopped, stopping wallet service...";
Expand Down
22 changes: 22 additions & 0 deletions src/PaymentGateService/PaymentServiceConfiguration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,16 @@ Configuration::Configuration() {
bindPort = 0;
secretViewKey = "";
secretSpendKey = "";
rpcPassword = "";
legacySecurity = false;
}

void Configuration::initOptions(boost::program_options::options_description& desc) {
desc.add_options()
("bind-address", po::value<std::string>()->default_value("127.0.0.1"), "payment service bind address")
("bind-port", po::value<uint16_t>()->default_value(8070), "payment service bind port")
("rpc-password", po::value<std::string>(), "Specify the password to access the rpc server.")
("rpc-legacy-security", "Enable legacy mode (no password for RPC). WARNING: INSECURE. USE ONLY AS A LAST RESORT.")
("container-file,w", po::value<std::string>(), "container file")
("container-password,p", po::value<std::string>(), "container password")
("generate-container,g", "generate new container file with one wallet and exit")
Expand Down Expand Up @@ -152,6 +156,24 @@ void Configuration::init(const boost::program_options::variables_map& options) {
throw ConfigurationError("container-file parameter are required");
}
}

// If generating a container skip the authentication parameters.
if (generateNewContainer) {
return;
}

// Check for the authentication parameters
if ((options.count("rpc-password") == 0) && (options.count("rpc-legacy-security") == 0)) {
throw ConfigurationError("Please specify an RPC password or use the --rpc-legacy-security flag.");
}

if (options.count("rpc-legacy-security") != 0) {
legacySecurity = true;
}
else {
rpcPassword = options["rpc-password"].as<std::string>();
}

}

} //namespace PaymentService
2 changes: 2 additions & 0 deletions src/PaymentGateService/PaymentServiceConfiguration.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ struct Configuration {

std::string bindAddress;
uint16_t bindPort;
std::string rpcPassword;

std::string containerFile;
std::string containerPassword;
Expand All @@ -53,6 +54,7 @@ struct Configuration {
bool testnet;
bool printAddresses;
bool syncFromZero;
bool legacySecurity;

size_t logLevel;
};
Expand Down
1 change: 1 addition & 0 deletions src/Rpc/JsonRpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ JsonRpcError::JsonRpcError(int c) : code(c) {
case errMethodNotFound: message = "Method not found"; break;
case errInvalidParams: message = "Invalid params"; break;
case errInternalError: message = "Internal error"; break;
case errInvalidPassword: message = "Invalid or no password supplied"; break;
default: message = "Unknown error"; break;
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/Rpc/JsonRpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const int errInvalidRequest = -32600;
const int errMethodNotFound = -32601;
const int errInvalidParams = -32602;
const int errInternalError = -32603;
const int errInvalidPassword = -32604;

class JsonRpcError: public std::exception {
public:
Expand All @@ -62,6 +63,7 @@ class JsonRpcError: public std::exception {
};

typedef boost::optional<Common::JsonValue> OptionalId;
typedef boost::optional<Common::JsonValue> OptionalPassword;

class JsonRpcRequest {
public:
Expand All @@ -84,6 +86,10 @@ class JsonRpcRequest {
if (psReq.contains("id")) {
id = psReq("id");
}

if (psReq.contains("password")) {
password = psReq("password");
}

return true;
}
Expand Down Expand Up @@ -112,6 +118,10 @@ class JsonRpcRequest {
const OptionalId& getId() const {
return id;
}

const OptionalPassword& getPassword() const {
return password;
}

std::string getBody() {
psReq.set("jsonrpc", std::string("2.0"));
Expand All @@ -123,6 +133,7 @@ class JsonRpcRequest {

Common::JsonValue psReq;
OptionalId id;
OptionalPassword password;
std::string method;
};

Expand Down
12 changes: 12 additions & 0 deletions src/SimpleWallet/SimpleWallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1329,6 +1329,18 @@ int main(int argc, char* argv[]) {

if (command_line::has_arg(vm, Tools::wallet_rpc_server::arg_rpc_bind_port)) {
//runs wallet with rpc interface

/*
If the rpc interface is run, ensure that either legacy mode or an RPC
password is set.
*/

if (!command_line::has_arg(vm, Tools::wallet_rpc_server::arg_rpc_password) &&
!command_line::has_arg(vm, Tools::wallet_rpc_server::arg_rpc_legacy_security)) {
logger(ERROR, BRIGHT_RED) << "Required RPC password is not set.";
return 1;
}

if (!command_line::has_arg(vm, arg_wallet_file)) {
logger(ERROR, BRIGHT_RED) << "Wallet file not set.";
return 1;
Expand Down
40 changes: 39 additions & 1 deletion src/Wallet/WalletRpcServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@ namespace Tools {

const command_line::arg_descriptor<uint16_t> wallet_rpc_server::arg_rpc_bind_port = { "rpc-bind-port", "Starts wallet as rpc server for wallet operations, sets bind port for server", 0, true };
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_bind_ip = { "rpc-bind-ip", "Specify ip to bind rpc server", "127.0.0.1" };
const command_line::arg_descriptor<std::string> wallet_rpc_server::arg_rpc_password = { "rpc-password", "Specify the password to access the rpc server.", "", true };
const command_line::arg_descriptor<bool> wallet_rpc_server::arg_rpc_legacy_security = { "rpc-legacy-security", "Enable legacy mode (no password for RPC). WARNING: INSECURE. USE ONLY AS A LAST RESORT.", false};
const command_line::arg_descriptor<bool> arg_allow_extended_rpc = {"allow-extended-rpc", "Allow RPC access to the wallet address and view/spend keys", false};


void wallet_rpc_server::init_options(boost::program_options::options_description& desc) {
command_line::add_arg(desc, arg_rpc_bind_ip);
command_line::add_arg(desc, arg_rpc_bind_port);
command_line::add_arg(desc, arg_rpc_password);
command_line::add_arg(desc, arg_rpc_legacy_security);
command_line::add_arg(desc, arg_allow_extended_rpc);
}
//------------------------------------------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -80,6 +85,10 @@ void wallet_rpc_server::send_stop_signal() {
bool wallet_rpc_server::handle_command_line(const boost::program_options::variables_map& vm) {
m_bind_ip = command_line::get_arg(vm, arg_rpc_bind_ip);
m_port = command_line::get_arg(vm, arg_rpc_bind_port);
m_legacy = command_line::get_arg(vm, arg_rpc_legacy_security);
if (!m_legacy) {
m_password = command_line::get_arg(vm, arg_rpc_password);
}
m_allow_extended_rpc = command_line::get_arg(vm, arg_allow_extended_rpc);
return true;
}
Expand All @@ -99,19 +108,34 @@ void wallet_rpc_server::processRequest(const CryptoNote::HttpRequest& request, C

JsonRpcRequest jsonRequest;
JsonRpcResponse jsonResponse;
std::string clientPassword;

try {
jsonRequest.parseRequest(request.getBody());
jsonResponse.setId(jsonRequest.getId());

if (!m_legacy) {
const JsonRpc::OptionalPassword& clientPasswordObject = jsonRequest.getPassword();
if (!clientPasswordObject.is_initialized()) {
throw JsonRpcError(errInvalidPassword);
}
if (!clientPasswordObject.get().isString()) {
throw JsonRpcError(errInvalidPassword);
}
clientPassword = clientPasswordObject.get().getString();
if (clientPassword != m_password) {
throw JsonRpcError(errInvalidPassword);
}
}

static std::unordered_map<std::string, JsonMemberMethod> s_methods = {
{ "getbalance", makeMemberMethod(&wallet_rpc_server::on_getbalance) },
{ "transfer", makeMemberMethod(&wallet_rpc_server::on_transfer) },
{ "store", makeMemberMethod(&wallet_rpc_server::on_store) },
{ "get_payments", makeMemberMethod(&wallet_rpc_server::on_get_payments) },
{ "get_transfers", makeMemberMethod(&wallet_rpc_server::on_get_transfers) },
{ "get_height", makeMemberMethod(&wallet_rpc_server::on_get_height) },
// below are the restricted methods, use --enable-extended-rpc
{ "transfer", makeMemberMethod(&wallet_rpc_server::on_transfer) },
{ "reset", makeMemberMethod(&wallet_rpc_server::on_reset) },
{ "stop_wallet", makeMemberMethod(&wallet_rpc_server::on_stop_wallet) },
{ "get_address", makeMemberMethod(&wallet_rpc_server::on_get_address) },
Expand Down Expand Up @@ -142,6 +166,11 @@ bool wallet_rpc_server::on_getbalance(const wallet_rpc::COMMAND_RPC_GET_BALANCE:
}
//------------------------------------------------------------------------------------------------------------------------------
bool wallet_rpc_server::on_transfer(const wallet_rpc::COMMAND_RPC_TRANSFER::request& req, wallet_rpc::COMMAND_RPC_TRANSFER::response& res) {

if(!m_allow_extended_rpc) {
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_METHOD_RESTRICTED, "Unable to invoke extended RPC method without explicit --allow-extended-rpc flag.");
}

std::vector<CryptoNote::WalletLegacyTransfer> transfers;
for (auto it = req.destinations.begin(); it != req.destinations.end(); it++) {
CryptoNote::WalletLegacyTransfer transfer;
Expand Down Expand Up @@ -311,6 +340,9 @@ bool wallet_rpc_server::on_stop_wallet(const wallet_rpc::COMMAND_RPC_STOP::reque

wallet_rpc_server::send_stop_signal();
}
else {
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_METHOD_RESTRICTED, "Unable to invoke extended RPC method without explicit --allow-extended-rpc flag.");
}
return true;

}
Expand All @@ -320,6 +352,9 @@ bool wallet_rpc_server::on_get_address(const wallet_rpc::COMMAND_RPC_GET_ADDRESS
if(m_allow_extended_rpc) {
res.address = m_wallet.getAddress();
}
else {
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_METHOD_RESTRICTED, "Unable to invoke extended RPC method without explicit --allow-extended-rpc flag.");
}
return true;

}
Expand All @@ -332,6 +367,9 @@ bool wallet_rpc_server::on_view_keys(const wallet_rpc::COMMAND_RPC_VIEW_KEYS::re
res.view_key = Common::podToHex(keys.viewSecretKey);
res.spend_key = Common::podToHex(keys.spendSecretKey);
}
else {
throw JsonRpc::JsonRpcError(WALLET_RPC_ERROR_METHOD_RESTRICTED, "Unable to invoke extended RPC method without explicit --allow-extended-rpc flag.");
}
return true;

}
Expand Down
4 changes: 4 additions & 0 deletions src/Wallet/WalletRpcServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ namespace Tools

static const command_line::arg_descriptor<uint16_t> arg_rpc_bind_port;
static const command_line::arg_descriptor<std::string> arg_rpc_bind_ip;
static const command_line::arg_descriptor<std::string> arg_rpc_password;
static const command_line::arg_descriptor<bool> arg_rpc_legacy_security;

private:

Expand All @@ -77,7 +79,9 @@ namespace Tools
CryptoNote::INode& m_node;
uint16_t m_port;
bool m_allow_extended_rpc;
bool m_legacy;
std::string m_bind_ip;
std::string m_password;
CryptoNote::Currency& m_currency;
const std::string m_walletFilename;

Expand Down
1 change: 1 addition & 0 deletions src/Wallet/WalletRpcServerErrorCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@
#define WALLET_RPC_ERROR_CODE_DAEMON_IS_BUSY -3
#define WALLET_RPC_ERROR_CODE_GENERIC_TRANSFER_ERROR -4
#define WALLET_RPC_ERROR_CODE_WRONG_PAYMENT_ID -5
#define WALLET_RPC_ERROR_METHOD_RESTRICTED -6

0 comments on commit b759b12

Please sign in to comment.