Changeset View
Changeset View
Standalone View
Standalone View
src/rpc/protocol.cpp
// Copyright (c) 2010 Satoshi Nakamoto | // Copyright (c) 2010 Satoshi Nakamoto | ||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "rpc/protocol.h" | #include "rpc/protocol.h" | ||||
#include "random.h" | #include "random.h" | ||||
#include "tinyformat.h" | #include "tinyformat.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include "utilstrencodings.h" | #include "utilstrencodings.h" | ||||
#include "utiltime.h" | #include "utiltime.h" | ||||
#include "version.h" | #include "version.h" | ||||
#include <stdint.h> | #include <cstdint> | ||||
#include <fstream> | #include <fstream> | ||||
using namespace std; | using namespace std; | ||||
/** | /** | ||||
* JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, | * JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility, but | ||||
* but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were | * uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were | ||||
* unspecified (HTTP errors and contents of 'error'). | * unspecified (HTTP errors and contents of 'error'). | ||||
* | * | ||||
* 1.0 spec: http://json-rpc.org/wiki/specification | * 1.0 spec: http://json-rpc.org/wiki/specification | ||||
* 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html | * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html | ||||
*/ | */ | ||||
UniValue JSONRPCRequestObj(const string& strMethod, const UniValue& params, const UniValue& id) | UniValue JSONRPCRequestObj(const string &strMethod, const UniValue ¶ms, | ||||
{ | const UniValue &id) { | ||||
UniValue request(UniValue::VOBJ); | UniValue request(UniValue::VOBJ); | ||||
request.push_back(Pair("method", strMethod)); | request.push_back(Pair("method", strMethod)); | ||||
request.push_back(Pair("params", params)); | request.push_back(Pair("params", params)); | ||||
request.push_back(Pair("id", id)); | request.push_back(Pair("id", id)); | ||||
return request; | return request; | ||||
} | } | ||||
UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id) | UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, | ||||
{ | const UniValue &id) { | ||||
UniValue reply(UniValue::VOBJ); | UniValue reply(UniValue::VOBJ); | ||||
if (!error.isNull()) | if (!error.isNull()) | ||||
reply.push_back(Pair("result", NullUniValue)); | reply.push_back(Pair("result", NullUniValue)); | ||||
else | else | ||||
reply.push_back(Pair("result", result)); | reply.push_back(Pair("result", result)); | ||||
reply.push_back(Pair("error", error)); | reply.push_back(Pair("error", error)); | ||||
reply.push_back(Pair("id", id)); | reply.push_back(Pair("id", id)); | ||||
return reply; | return reply; | ||||
} | } | ||||
string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id) | string JSONRPCReply(const UniValue &result, const UniValue &error, | ||||
{ | const UniValue &id) { | ||||
UniValue reply = JSONRPCReplyObj(result, error, id); | UniValue reply = JSONRPCReplyObj(result, error, id); | ||||
return reply.write() + "\n"; | return reply.write() + "\n"; | ||||
} | } | ||||
UniValue JSONRPCError(int code, const string& message) | UniValue JSONRPCError(int code, const string &message) { | ||||
{ | |||||
UniValue error(UniValue::VOBJ); | UniValue error(UniValue::VOBJ); | ||||
error.push_back(Pair("code", code)); | error.push_back(Pair("code", code)); | ||||
error.push_back(Pair("message", message)); | error.push_back(Pair("message", message)); | ||||
return error; | return error; | ||||
} | } | ||||
/** Username used when cookie authentication is in use (arbitrary, only for | /** Username used when cookie authentication is in use (arbitrary, only for | ||||
* recognizability in debugging/logging purposes) | * recognizability in debugging/logging purposes) | ||||
*/ | */ | ||||
static const std::string COOKIEAUTH_USER = "__cookie__"; | static const std::string COOKIEAUTH_USER = "__cookie__"; | ||||
/** Default name for auth cookie file */ | /** Default name for auth cookie file */ | ||||
static const std::string COOKIEAUTH_FILE = ".cookie"; | static const std::string COOKIEAUTH_FILE = ".cookie"; | ||||
boost::filesystem::path GetAuthCookieFile() | boost::filesystem::path GetAuthCookieFile() { | ||||
{ | |||||
boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE)); | boost::filesystem::path path(GetArg("-rpccookiefile", COOKIEAUTH_FILE)); | ||||
if (!path.is_complete()) path = GetDataDir() / path; | if (!path.is_complete()) path = GetDataDir() / path; | ||||
return path; | return path; | ||||
} | } | ||||
bool GenerateAuthCookie(std::string *cookie_out) | bool GenerateAuthCookie(std::string *cookie_out) { | ||||
{ | |||||
const size_t COOKIE_SIZE = 32; | const size_t COOKIE_SIZE = 32; | ||||
unsigned char rand_pwd[COOKIE_SIZE]; | unsigned char rand_pwd[COOKIE_SIZE]; | ||||
GetRandBytes(rand_pwd, COOKIE_SIZE); | GetRandBytes(rand_pwd, COOKIE_SIZE); | ||||
std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd, rand_pwd+COOKIE_SIZE); | std::string cookie = | ||||
COOKIEAUTH_USER + ":" + HexStr(rand_pwd, rand_pwd + COOKIE_SIZE); | |||||
/** the umask determines what permissions are used to create this file - | /** the umask determines what permissions are used to create this file - | ||||
* these are set to 077 in init.cpp unless overridden with -sysperms. | * these are set to 077 in init.cpp unless overridden with -sysperms. | ||||
*/ | */ | ||||
std::ofstream file; | std::ofstream file; | ||||
boost::filesystem::path filepath = GetAuthCookieFile(); | boost::filesystem::path filepath = GetAuthCookieFile(); | ||||
file.open(filepath.string().c_str()); | file.open(filepath.string().c_str()); | ||||
if (!file.is_open()) { | if (!file.is_open()) { | ||||
LogPrintf("Unable to open cookie authentication file %s for writing\n", filepath.string()); | LogPrintf("Unable to open cookie authentication file %s for writing\n", | ||||
filepath.string()); | |||||
return false; | return false; | ||||
} | } | ||||
file << cookie; | file << cookie; | ||||
file.close(); | file.close(); | ||||
LogPrintf("Generated RPC authentication cookie %s\n", filepath.string()); | LogPrintf("Generated RPC authentication cookie %s\n", filepath.string()); | ||||
if (cookie_out) | if (cookie_out) *cookie_out = cookie; | ||||
*cookie_out = cookie; | |||||
return true; | return true; | ||||
} | } | ||||
bool GetAuthCookie(std::string *cookie_out) | bool GetAuthCookie(std::string *cookie_out) { | ||||
{ | |||||
std::ifstream file; | std::ifstream file; | ||||
std::string cookie; | std::string cookie; | ||||
boost::filesystem::path filepath = GetAuthCookieFile(); | boost::filesystem::path filepath = GetAuthCookieFile(); | ||||
file.open(filepath.string().c_str()); | file.open(filepath.string().c_str()); | ||||
if (!file.is_open()) | if (!file.is_open()) return false; | ||||
return false; | |||||
std::getline(file, cookie); | std::getline(file, cookie); | ||||
file.close(); | file.close(); | ||||
if (cookie_out) | if (cookie_out) *cookie_out = cookie; | ||||
*cookie_out = cookie; | |||||
return true; | return true; | ||||
} | } | ||||
void DeleteAuthCookie() | void DeleteAuthCookie() { | ||||
{ | |||||
try { | try { | ||||
boost::filesystem::remove(GetAuthCookieFile()); | boost::filesystem::remove(GetAuthCookieFile()); | ||||
} catch (const boost::filesystem::filesystem_error& e) { | } catch (const boost::filesystem::filesystem_error &e) { | ||||
LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, e.what()); | LogPrintf("%s: Unable to remove random auth cookie file: %s\n", | ||||
__func__, e.what()); | |||||
} | } | ||||
} | } | ||||