aboutsummaryrefslogtreecommitdiff
path: root/src/rpc
diff options
context:
space:
mode:
Diffstat (limited to 'src/rpc')
-rwxr-xr-x[-rw-r--r--]src/rpc/core_rpc_server.cpp58
-rw-r--r--src/rpc/core_rpc_server.h10
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h12
-rw-r--r--src/rpc/message.cpp53
-rw-r--r--src/rpc/message_data_structs.h1
-rwxr-xr-x[-rw-r--r--]src/rpc/rpc_args.cpp18
-rwxr-xr-x[-rw-r--r--]src/rpc/rpc_args.h2
7 files changed, 111 insertions, 43 deletions
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp
index 9ecebfbfc..acc2d9865 100644..100755
--- a/src/rpc/core_rpc_server.cpp
+++ b/src/rpc/core_rpc_server.cpp
@@ -102,7 +102,7 @@ namespace cryptonote
http_login.emplace(std::move(rpc_config->login->username), std::move(rpc_config->login->password).password());
return epee::http_server_impl_base<core_rpc_server, connection_context>::init(
- std::move(port), std::move(rpc_config->bind_ip), std::move(http_login)
+ std::move(port), std::move(rpc_config->bind_ip), std::move(rpc_config->access_control_origins), std::move(http_login)
);
}
//------------------------------------------------------------------------------------------------------------------------------
@@ -491,15 +491,17 @@ namespace cryptonote
// try the pool for any missing txes
size_t found_in_pool = 0;
std::unordered_set<crypto::hash> pool_tx_hashes;
+ std::unordered_map<crypto::hash, bool> double_spend_seen;
if (!missed_txs.empty())
{
- std::list<transaction> pool_txs;
- bool r = m_core.get_pool_transactions(pool_txs);
+ std::vector<tx_info> pool_tx_info;
+ std::vector<spent_key_image_info> pool_key_image_info;
+ bool r = m_core.get_pool_transactions_and_spent_keys_info(pool_tx_info, pool_key_image_info);
if(r)
{
// sort to match original request
std::list<transaction> sorted_txs;
- std::list<cryptonote::transaction>::const_iterator i;
+ std::vector<tx_info>::const_iterator i;
for (const crypto::hash &h: vh)
{
if (std::find(missed_txs.begin(), missed_txs.end(), h) == missed_txs.end())
@@ -513,11 +515,26 @@ namespace cryptonote
sorted_txs.push_back(std::move(txs.front()));
txs.pop_front();
}
- else if ((i = std::find_if(pool_txs.begin(), pool_txs.end(), [h](cryptonote::transaction &tx) { return h == cryptonote::get_transaction_hash(tx); })) != pool_txs.end())
+ else if ((i = std::find_if(pool_tx_info.begin(), pool_tx_info.end(), [h](const tx_info &txi) { return epee::string_tools::pod_to_hex(h) == txi.id_hash; })) != pool_tx_info.end())
{
- sorted_txs.push_back(*i);
+ cryptonote::transaction tx;
+ if (!cryptonote::parse_and_validate_tx_from_blob(i->tx_blob, tx))
+ {
+ res.status = "Failed to parse and validate tx from blob";
+ return true;
+ }
+ sorted_txs.push_back(tx);
missed_txs.remove(h);
pool_tx_hashes.insert(h);
+ const std::string hash_string = epee::string_tools::pod_to_hex(h);
+ for (const auto &ti: pool_tx_info)
+ {
+ if (ti.id_hash == hash_string)
+ {
+ double_spend_seen.insert(std::make_pair(h, ti.double_spend_seen));
+ break;
+ }
+ }
++found_in_pool;
}
}
@@ -543,11 +560,21 @@ namespace cryptonote
if (e.in_pool)
{
e.block_height = e.block_timestamp = std::numeric_limits<uint64_t>::max();
+ if (double_spend_seen.find(tx_hash) != double_spend_seen.end())
+ {
+ e.double_spend_seen = double_spend_seen[tx_hash];
+ }
+ else
+ {
+ MERROR("Failed to determine double spend status for " << tx_hash);
+ e.double_spend_seen = false;
+ }
}
else
{
e.block_height = m_core.get_blockchain_storage().get_db().get_tx_block_height(tx_hash);
e.block_timestamp = m_core.get_blockchain_storage().get_db().get_block_timestamp(e.block_height);
+ e.double_spend_seen = false;
}
// fill up old style responses too, in case an old wallet asks
@@ -577,7 +604,7 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res)
+ bool core_rpc_server::on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_is_key_image_spent);
CHECK_CORE_BUSY();
@@ -610,7 +637,7 @@ namespace cryptonote
// check the pool too
std::vector<cryptonote::tx_info> txs;
std::vector<cryptonote::spent_key_image_info> ki;
- r = m_core.get_pool_transactions_and_spent_keys_info(txs, ki);
+ r = m_core.get_pool_transactions_and_spent_keys_info(txs, ki, !request_has_rpc_origin || !m_restricted);
if(!r)
{
res.status = "Failed";
@@ -866,29 +893,29 @@ namespace cryptonote
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res)
+ bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool);
CHECK_CORE_BUSY();
- m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images);
+ m_core.get_pool_transactions_and_spent_keys_info(res.transactions, res.spent_key_images, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res)
+ bool core_rpc_server::on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool_hashes);
CHECK_CORE_BUSY();
- m_core.get_pool_transaction_hashes(res.tx_hashes);
+ m_core.get_pool_transaction_hashes(res.tx_hashes, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
- bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res)
+ bool core_rpc_server::on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin)
{
PERF_TIMER(on_get_transaction_pool_stats);
CHECK_CORE_BUSY();
- m_core.get_pool_transaction_stats(res.pool_stats);
+ m_core.get_pool_transaction_stats(res.pool_stats, !request_has_rpc_origin || !m_restricted);
res.status = CORE_RPC_STATUS_OK;
return true;
}
@@ -1317,6 +1344,7 @@ namespace cryptonote
error_resp.message = "Internal error: can't produce valid response.";
return false;
}
+ res.miner_tx_hash = epee::string_tools::pod_to_hex(cryptonote::get_transaction_hash(blk.miner_tx));
for (size_t n = 0; n < blk.tx_hashes.size(); ++n)
{
res.tx_hashes.push_back(epee::string_tools::pod_to_hex(blk.tx_hashes[n]));
@@ -1882,7 +1910,7 @@ namespace cryptonote
const command_line::arg_descriptor<bool> core_rpc_server::arg_restricted_rpc = {
"restricted-rpc"
- , "Restrict RPC to view only commands"
+ , "Restrict RPC to view only commands and do not return privacy sensitive data in RPC calls"
, false
};
} // namespace cryptonote
diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h
index 73a308a72..7f252258c 100644
--- a/src/rpc/core_rpc_server.h
+++ b/src/rpc/core_rpc_server.h
@@ -122,7 +122,7 @@ namespace cryptonote
MAP_JON_RPC_WE_IF("flush_txpool", on_flush_txpool, COMMAND_RPC_FLUSH_TRANSACTION_POOL, !m_restricted)
MAP_JON_RPC_WE("get_output_histogram", on_get_output_histogram, COMMAND_RPC_GET_OUTPUT_HISTOGRAM)
MAP_JON_RPC_WE("get_version", on_get_version, COMMAND_RPC_GET_VERSION)
- MAP_JON_RPC_WE("get_coinbase_tx_sum", on_get_coinbase_tx_sum, COMMAND_RPC_GET_COINBASE_TX_SUM)
+ MAP_JON_RPC_WE_IF("get_coinbase_tx_sum", on_get_coinbase_tx_sum, COMMAND_RPC_GET_COINBASE_TX_SUM, !m_restricted)
MAP_JON_RPC_WE("get_fee_estimate", on_get_per_kb_fee_estimate, COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE)
MAP_JON_RPC_WE_IF("get_alternate_chains",on_get_alternate_chains, COMMAND_RPC_GET_ALTERNATE_CHAINS, !m_restricted)
MAP_JON_RPC_WE_IF("relay_tx", on_relay_tx, COMMAND_RPC_RELAY_TX, !m_restricted)
@@ -137,7 +137,7 @@ namespace cryptonote
bool on_get_blocks_by_height(const COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCKS_BY_HEIGHT::response& res);
bool on_get_hashes(const COMMAND_RPC_GET_HASHES_FAST::request& req, COMMAND_RPC_GET_HASHES_FAST::response& res);
bool on_get_transactions(const COMMAND_RPC_GET_TRANSACTIONS::request& req, COMMAND_RPC_GET_TRANSACTIONS::response& res);
- bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res);
+ bool on_is_key_image_spent(const COMMAND_RPC_IS_KEY_IMAGE_SPENT::request& req, COMMAND_RPC_IS_KEY_IMAGE_SPENT::response& res, bool request_has_rpc_origin = true);
bool on_get_indexes(const COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::request& req, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES::response& res);
bool on_send_raw_tx(const COMMAND_RPC_SEND_RAW_TX::request& req, COMMAND_RPC_SEND_RAW_TX::response& res);
bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res);
@@ -153,9 +153,9 @@ namespace cryptonote
bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res);
bool on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res);
bool on_set_log_categories(const COMMAND_RPC_SET_LOG_CATEGORIES::request& req, COMMAND_RPC_SET_LOG_CATEGORIES::response& res);
- bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res);
- bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res);
- bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res);
+ bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, bool request_has_rpc_origin = true);
+ bool on_get_transaction_pool_hashes(const COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_HASHES::response& res, bool request_has_rpc_origin = true);
+ bool on_get_transaction_pool_stats(const COMMAND_RPC_GET_TRANSACTION_POOL_STATS::request& req, COMMAND_RPC_GET_TRANSACTION_POOL_STATS::response& res, bool request_has_rpc_origin = true);
bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res);
bool on_get_limit(const COMMAND_RPC_GET_LIMIT::request& req, COMMAND_RPC_GET_LIMIT::response& res);
bool on_set_limit(const COMMAND_RPC_SET_LIMIT::request& req, COMMAND_RPC_SET_LIMIT::response& res);
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index ee2a79eb4..d3b4db64f 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -49,7 +49,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 1
-#define CORE_RPC_VERSION_MINOR 15
+#define CORE_RPC_VERSION_MINOR 16
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -566,6 +566,7 @@ namespace cryptonote
std::string as_hex;
std::string as_json;
bool in_pool;
+ bool double_spend_seen;
uint64_t block_height;
uint64_t block_timestamp;
std::vector<uint64_t> output_indices;
@@ -575,6 +576,7 @@ namespace cryptonote
KV_SERIALIZE(as_hex)
KV_SERIALIZE(as_json)
KV_SERIALIZE(in_pool)
+ KV_SERIALIZE(double_spend_seen)
KV_SERIALIZE(block_height)
KV_SERIALIZE(block_timestamp)
KV_SERIALIZE(output_indices)
@@ -1217,12 +1219,14 @@ namespace cryptonote
{
std::string status;
block_header_response block_header;
+ std::string miner_tx_hash;
std::vector<std::string> tx_hashes;
std::string blob;
std::string json;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(block_header)
+ KV_SERIALIZE(miner_tx_hash)
KV_SERIALIZE(tx_hashes)
KV_SERIALIZE(status)
KV_SERIALIZE(blob)
@@ -1357,6 +1361,8 @@ namespace cryptonote
bool relayed;
uint64_t last_relayed_time;
bool do_not_relay;
+ bool double_spend_seen;
+ std::string tx_blob;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(id_hash)
@@ -1372,6 +1378,8 @@ namespace cryptonote
KV_SERIALIZE(relayed)
KV_SERIALIZE(last_relayed_time)
KV_SERIALIZE(do_not_relay)
+ KV_SERIALIZE(double_spend_seen)
+ KV_SERIALIZE(tx_blob)
END_KV_SERIALIZE_MAP()
};
@@ -1480,6 +1488,7 @@ namespace cryptonote
uint32_t num_not_relayed;
uint64_t histo_98pc;
std::vector<txpool_histo> histo;
+ uint32_t num_double_spends;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(bytes_total)
@@ -1494,6 +1503,7 @@ namespace cryptonote
KV_SERIALIZE(num_not_relayed)
KV_SERIALIZE(histo_98pc)
KV_SERIALIZE_CONTAINER_POD_AS_BLOB(histo)
+ KV_SERIALIZE(num_double_spends)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp
index 086820180..d6da124d1 100644
--- a/src/rpc/message.cpp
+++ b/src/rpc/message.cpp
@@ -45,6 +45,15 @@ const char* Message::STATUS_FAILED = "Failed";
const char* Message::STATUS_BAD_REQUEST = "Invalid request type";
const char* Message::STATUS_BAD_JSON = "Malformed json";
+namespace
+{
+constexpr const char error_field[] = "error";
+constexpr const char id_field[] = "id";
+constexpr const char method_field[] = "method";
+constexpr const char params_field[] = "params";
+constexpr const char result_field[] = "result";
+}
+
rapidjson::Value Message::toJson(rapidjson::Document& doc) const
{
rapidjson::Value val(rapidjson::kObjectType);
@@ -70,8 +79,8 @@ FullMessage::FullMessage(const std::string& request, Message* message)
{
doc.SetObject();
- doc.AddMember("method", rapidjson::StringRef(request.c_str()), doc.GetAllocator());
- doc.AddMember("params", message->toJson(doc), doc.GetAllocator());
+ doc.AddMember(method_field, rapidjson::StringRef(request.c_str()), doc.GetAllocator());
+ doc.AddMember(params_field, message->toJson(doc), doc.GetAllocator());
// required by JSON-RPC 2.0 spec
doc.AddMember("jsonrpc", rapidjson::Value("2.0"), doc.GetAllocator());
@@ -86,7 +95,7 @@ FullMessage::FullMessage(Message* message)
if (message->status == Message::STATUS_OK)
{
- doc.AddMember("response", message->toJson(doc), doc.GetAllocator());
+ doc.AddMember(result_field, message->toJson(doc), doc.GetAllocator());
}
else
{
@@ -111,14 +120,14 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
if (request)
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "method")
- OBJECT_HAS_MEMBER_OR_THROW(doc, "params")
+ OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
+ OBJECT_HAS_MEMBER_OR_THROW(doc, params_field)
}
else
{
- if (!doc.HasMember("response") && !doc.HasMember("error"))
+ if (!doc.HasMember(result_field) && !doc.HasMember(error_field))
{
- throw cryptonote::json::MISSING_KEY("error/response");
+ throw cryptonote::json::MISSING_KEY("error/result");
}
}
}
@@ -126,9 +135,9 @@ FullMessage::FullMessage(const std::string& json_string, bool request)
std::string FullMessage::getJson()
{
- if (!doc.HasMember("id"))
+ if (!doc.HasMember(id_field))
{
- doc.AddMember("id", rapidjson::Value("unused"), doc.GetAllocator());
+ doc.AddMember(id_field, rapidjson::Value("unused"), doc.GetAllocator());
}
rapidjson::StringBuffer buf;
@@ -142,24 +151,24 @@ std::string FullMessage::getJson()
std::string FullMessage::getRequestType() const
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "method")
- return doc["method"].GetString();
+ OBJECT_HAS_MEMBER_OR_THROW(doc, method_field)
+ return doc[method_field].GetString();
}
rapidjson::Value& FullMessage::getMessage()
{
- if (doc.HasMember("params"))
+ if (doc.HasMember(params_field))
{
- return doc["params"];
+ return doc[params_field];
}
- else if (doc.HasMember("response"))
+ else if (doc.HasMember(result_field))
{
- return doc["response"];
+ return doc[result_field];
}
//else
- OBJECT_HAS_MEMBER_OR_THROW(doc, "error")
- return doc["error"];
+ OBJECT_HAS_MEMBER_OR_THROW(doc, error_field)
+ return doc[error_field];
}
@@ -172,20 +181,20 @@ rapidjson::Value FullMessage::getMessageCopy()
rapidjson::Value& FullMessage::getID()
{
- OBJECT_HAS_MEMBER_OR_THROW(doc, "id")
- return doc["id"];
+ OBJECT_HAS_MEMBER_OR_THROW(doc, id_field)
+ return doc[id_field];
}
void FullMessage::setID(rapidjson::Value& id)
{
- auto itr = doc.FindMember("id");
+ auto itr = doc.FindMember(id_field);
if (itr != doc.MemberEnd())
{
itr->value = id;
}
else
{
- doc.AddMember("id", id, doc.GetAllocator());
+ doc.AddMember(id_field, id, doc.GetAllocator());
}
}
@@ -193,7 +202,7 @@ cryptonote::rpc::error FullMessage::getError()
{
cryptonote::rpc::error err;
err.use = false;
- if (doc.HasMember("error"))
+ if (doc.HasMember(error_field))
{
GET_FROM_JSON_OBJECT(doc, err, error);
err.use = true;
diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h
index 00f1e0caa..581048eaf 100644
--- a/src/rpc/message_data_structs.h
+++ b/src/rpc/message_data_structs.h
@@ -95,6 +95,7 @@ namespace rpc
uint64_t last_relayed_time;
bool relayed;
bool do_not_relay;
+ bool double_spend_seen;
};
typedef std::unordered_map<crypto::key_image, std::vector<crypto::hash> > key_images_with_tx_hashes;
diff --git a/src/rpc/rpc_args.cpp b/src/rpc/rpc_args.cpp
index 4435f74d1..93309bf3c 100644..100755
--- a/src/rpc/rpc_args.cpp
+++ b/src/rpc/rpc_args.cpp
@@ -28,6 +28,7 @@
//
#include "rpc_args.h"
+#include <boost/algorithm/string.hpp>
#include <boost/asio/ip/address.hpp>
#include "common/command_line.h"
#include "common/i18n.h"
@@ -38,6 +39,7 @@ namespace cryptonote
: rpc_bind_ip({"rpc-bind-ip", rpc_args::tr("Specify ip to bind rpc server"), "127.0.0.1"})
, rpc_login({"rpc-login", rpc_args::tr("Specify username[:password] required for RPC server"), "", true})
, confirm_external_bind({"confirm-external-bind", rpc_args::tr("Confirm rpc-bind-ip value is NOT a loopback (local) IP")})
+ , rpc_access_control_origins({"rpc-access-control-origins", rpc_args::tr("Specify a comma separated list of origins to allow cross origin resource sharing"), ""})
{}
const char* rpc_args::tr(const char* str) { return i18n_translate(str, "cryptonote::rpc_args"); }
@@ -48,6 +50,7 @@ namespace cryptonote
command_line::add_arg(desc, arg.rpc_bind_ip);
command_line::add_arg(desc, arg.rpc_login);
command_line::add_arg(desc, arg.confirm_external_bind);
+ command_line::add_arg(desc, arg.rpc_access_control_origins);
}
boost::optional<rpc_args> rpc_args::process(const boost::program_options::variables_map& vm)
@@ -91,6 +94,21 @@ namespace cryptonote
}
}
+ auto access_control_origins_input = command_line::get_arg(vm, arg.rpc_access_control_origins);
+ if (!access_control_origins_input.empty())
+ {
+ if (!config.login)
+ {
+ LOG_ERROR(arg.rpc_access_control_origins.name << tr(" requires RFC server password --") << arg.rpc_login.name << tr(" cannot be empty"));
+ return boost::none;
+ }
+
+ std::vector<std::string> access_control_origins;
+ boost::split(access_control_origins, access_control_origins_input, boost::is_any_of(","));
+ std::for_each(access_control_origins.begin(), access_control_origins.end(), boost::bind(&boost::trim<std::string>, _1, std::locale::classic()));
+ config.access_control_origins = std::move(access_control_origins);
+ }
+
return {std::move(config)};
}
}
diff --git a/src/rpc/rpc_args.h b/src/rpc/rpc_args.h
index d6e7bab07..72b5aa706 100644..100755
--- a/src/rpc/rpc_args.h
+++ b/src/rpc/rpc_args.h
@@ -53,6 +53,7 @@ namespace cryptonote
const command_line::arg_descriptor<std::string> rpc_bind_ip;
const command_line::arg_descriptor<std::string> rpc_login;
const command_line::arg_descriptor<bool> confirm_external_bind;
+ const command_line::arg_descriptor<std::string> rpc_access_control_origins;
};
static const char* tr(const char* str);
@@ -62,6 +63,7 @@ namespace cryptonote
static boost::optional<rpc_args> process(const boost::program_options::variables_map& vm);
std::string bind_ip;
+ std::vector<std::string> access_control_origins;
boost::optional<tools::login> login; // currently `boost::none` if unspecified by user
};
}