mirror of
https://github.com/dashpay/dash.git
synced 2024-12-28 05:23:01 +01:00
71cbeaad9a
When no `-rpcpassword` is specified, use a special 'cookie' file for authentication. This file is generated with random content when the daemon starts, and deleted when it exits. Read access to this file controls who can access through RPC. By default this file is stored in the data directory but it be overriden with `-rpccookiefile`. This is similar to Tor CookieAuthentication: see https://www.torproject.org/docs/tor-manual.html.en Alternative to #6258. Like that pull, this allows running bitcoind without any manual configuration. However, daemons should ideally never write to their configuration files, so I prefer this solution.
179 lines
8.0 KiB
C++
179 lines
8.0 KiB
C++
// Copyright (c) 2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2014 The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#ifndef BITCOIN_RPCPROTOCOL_H
|
|
#define BITCOIN_RPCPROTOCOL_H
|
|
|
|
#include <list>
|
|
#include <map>
|
|
#include <stdint.h>
|
|
#include <string>
|
|
#include <boost/iostreams/concepts.hpp>
|
|
#include <boost/iostreams/stream.hpp>
|
|
#include <boost/asio.hpp>
|
|
#include <boost/asio/ssl.hpp>
|
|
#include <boost/filesystem.hpp>
|
|
|
|
#include "univalue/univalue.h"
|
|
|
|
//! HTTP status codes
|
|
enum HTTPStatusCode
|
|
{
|
|
HTTP_OK = 200,
|
|
HTTP_BAD_REQUEST = 400,
|
|
HTTP_UNAUTHORIZED = 401,
|
|
HTTP_FORBIDDEN = 403,
|
|
HTTP_NOT_FOUND = 404,
|
|
HTTP_INTERNAL_SERVER_ERROR = 500,
|
|
HTTP_SERVICE_UNAVAILABLE = 503,
|
|
};
|
|
|
|
//! Bitcoin RPC error codes
|
|
enum RPCErrorCode
|
|
{
|
|
//! Standard JSON-RPC 2.0 errors
|
|
RPC_INVALID_REQUEST = -32600,
|
|
RPC_METHOD_NOT_FOUND = -32601,
|
|
RPC_INVALID_PARAMS = -32602,
|
|
RPC_INTERNAL_ERROR = -32603,
|
|
RPC_PARSE_ERROR = -32700,
|
|
|
|
//! General application defined errors
|
|
RPC_MISC_ERROR = -1, //! std::exception thrown in command handling
|
|
RPC_FORBIDDEN_BY_SAFE_MODE = -2, //! Server is in safe mode, and command is not allowed in safe mode
|
|
RPC_TYPE_ERROR = -3, //! Unexpected type was passed as parameter
|
|
RPC_INVALID_ADDRESS_OR_KEY = -5, //! Invalid address or key
|
|
RPC_OUT_OF_MEMORY = -7, //! Ran out of memory during operation
|
|
RPC_INVALID_PARAMETER = -8, //! Invalid, missing or duplicate parameter
|
|
RPC_DATABASE_ERROR = -20, //! Database error
|
|
RPC_DESERIALIZATION_ERROR = -22, //! Error parsing or validating structure in raw format
|
|
RPC_VERIFY_ERROR = -25, //! General error during transaction or block submission
|
|
RPC_VERIFY_REJECTED = -26, //! Transaction or block was rejected by network rules
|
|
RPC_VERIFY_ALREADY_IN_CHAIN = -27, //! Transaction already in chain
|
|
RPC_IN_WARMUP = -28, //! Client still warming up
|
|
|
|
//! Aliases for backward compatibility
|
|
RPC_TRANSACTION_ERROR = RPC_VERIFY_ERROR,
|
|
RPC_TRANSACTION_REJECTED = RPC_VERIFY_REJECTED,
|
|
RPC_TRANSACTION_ALREADY_IN_CHAIN= RPC_VERIFY_ALREADY_IN_CHAIN,
|
|
|
|
//! P2P client errors
|
|
RPC_CLIENT_NOT_CONNECTED = -9, //! Bitcoin is not connected
|
|
RPC_CLIENT_IN_INITIAL_DOWNLOAD = -10, //! Still downloading initial blocks
|
|
RPC_CLIENT_NODE_ALREADY_ADDED = -23, //! Node is already added
|
|
RPC_CLIENT_NODE_NOT_ADDED = -24, //! Node has not been added before
|
|
RPC_CLIENT_NODE_NOT_CONNECTED = -29, //! Node to disconnect not found in connected nodes
|
|
RPC_CLIENT_INVALID_IP_OR_SUBNET = -30, //! Invalid IP/Subnet
|
|
|
|
//! Wallet errors
|
|
RPC_WALLET_ERROR = -4, //! Unspecified problem with wallet (key not found etc.)
|
|
RPC_WALLET_INSUFFICIENT_FUNDS = -6, //! Not enough funds in wallet or account
|
|
RPC_WALLET_INVALID_ACCOUNT_NAME = -11, //! Invalid account name
|
|
RPC_WALLET_KEYPOOL_RAN_OUT = -12, //! Keypool ran out, call keypoolrefill first
|
|
RPC_WALLET_UNLOCK_NEEDED = -13, //! Enter the wallet passphrase with walletpassphrase first
|
|
RPC_WALLET_PASSPHRASE_INCORRECT = -14, //! The wallet passphrase entered was incorrect
|
|
RPC_WALLET_WRONG_ENC_STATE = -15, //! Command given in wrong wallet encryption state (encrypting an encrypted wallet etc.)
|
|
RPC_WALLET_ENCRYPTION_FAILED = -16, //! Failed to encrypt the wallet
|
|
RPC_WALLET_ALREADY_UNLOCKED = -17, //! Wallet is already unlocked
|
|
};
|
|
|
|
/**
|
|
* IOStream device that speaks SSL but can also speak non-SSL
|
|
*/
|
|
template <typename Protocol>
|
|
class SSLIOStreamDevice : public boost::iostreams::device<boost::iostreams::bidirectional> {
|
|
public:
|
|
SSLIOStreamDevice(boost::asio::ssl::stream<typename Protocol::socket> &streamIn, bool fUseSSLIn) : stream(streamIn)
|
|
{
|
|
fUseSSL = fUseSSLIn;
|
|
fNeedHandshake = fUseSSLIn;
|
|
}
|
|
|
|
void handshake(boost::asio::ssl::stream_base::handshake_type role)
|
|
{
|
|
if (!fNeedHandshake) return;
|
|
fNeedHandshake = false;
|
|
stream.handshake(role);
|
|
}
|
|
std::streamsize read(char* s, std::streamsize n)
|
|
{
|
|
handshake(boost::asio::ssl::stream_base::server); // HTTPS servers read first
|
|
if (fUseSSL) return stream.read_some(boost::asio::buffer(s, n));
|
|
return stream.next_layer().read_some(boost::asio::buffer(s, n));
|
|
}
|
|
std::streamsize write(const char* s, std::streamsize n)
|
|
{
|
|
handshake(boost::asio::ssl::stream_base::client); // HTTPS clients write first
|
|
if (fUseSSL) return boost::asio::write(stream, boost::asio::buffer(s, n));
|
|
return boost::asio::write(stream.next_layer(), boost::asio::buffer(s, n));
|
|
}
|
|
bool connect(const std::string& server, const std::string& port)
|
|
{
|
|
using namespace boost::asio::ip;
|
|
tcp::resolver resolver(stream.get_io_service());
|
|
tcp::resolver::iterator endpoint_iterator;
|
|
#if BOOST_VERSION >= 104300
|
|
try {
|
|
#endif
|
|
// The default query (flags address_configured) tries IPv6 if
|
|
// non-localhost IPv6 configured, and IPv4 if non-localhost IPv4
|
|
// configured.
|
|
tcp::resolver::query query(server.c_str(), port.c_str());
|
|
endpoint_iterator = resolver.resolve(query);
|
|
#if BOOST_VERSION >= 104300
|
|
} catch (const boost::system::system_error&) {
|
|
// If we at first don't succeed, try blanket lookup (IPv4+IPv6 independent of configured interfaces)
|
|
tcp::resolver::query query(server.c_str(), port.c_str(), resolver_query_base::flags());
|
|
endpoint_iterator = resolver.resolve(query);
|
|
}
|
|
#endif
|
|
boost::system::error_code error = boost::asio::error::host_not_found;
|
|
tcp::resolver::iterator end;
|
|
while (error && endpoint_iterator != end)
|
|
{
|
|
stream.lowest_layer().close();
|
|
stream.lowest_layer().connect(*endpoint_iterator++, error);
|
|
}
|
|
if (error)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
bool fNeedHandshake;
|
|
bool fUseSSL;
|
|
boost::asio::ssl::stream<typename Protocol::socket>& stream;
|
|
};
|
|
|
|
std::string HTTPPost(const std::string& strMsg, const std::map<std::string,std::string>& mapRequestHeaders);
|
|
std::string HTTPError(int nStatus, bool keepalive,
|
|
bool headerOnly = false);
|
|
std::string HTTPReplyHeader(int nStatus, bool keepalive, size_t contentLength,
|
|
const char *contentType = "application/json");
|
|
std::string HTTPReply(int nStatus, const std::string& strMsg, bool keepalive,
|
|
bool headerOnly = false,
|
|
const char *contentType = "application/json");
|
|
bool ReadHTTPRequestLine(std::basic_istream<char>& stream, int &proto,
|
|
std::string& http_method, std::string& http_uri);
|
|
int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto);
|
|
int ReadHTTPHeaders(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet);
|
|
int ReadHTTPMessage(std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet,
|
|
std::string& strMessageRet, int nProto, size_t max_size);
|
|
std::string JSONRPCRequest(const std::string& strMethod, const UniValue& params, const UniValue& id);
|
|
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id);
|
|
std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id);
|
|
UniValue JSONRPCError(int code, const std::string& message);
|
|
|
|
/** Get name of RPC authentication cookie file */
|
|
boost::filesystem::path GetAuthCookieFile();
|
|
/** Generate a new RPC authentication cookie and write it to disk */
|
|
bool GenerateAuthCookie(std::string *cookie_out);
|
|
/** Read the RPC authentication cookie from disk */
|
|
bool GetAuthCookie(std::string *cookie_out);
|
|
/** Delete RPC authentication cookie from disk */
|
|
void DeleteAuthCookie();
|
|
|
|
#endif // BITCOIN_RPCPROTOCOL_H
|