Bitcoin Core  27.99.0
P2P Digital Currency
request.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <rpc/request.h>
7 
8 #include <util/fs.h>
9 
10 #include <common/args.h>
11 #include <logging.h>
12 #include <random.h>
13 #include <rpc/protocol.h>
14 #include <util/fs_helpers.h>
15 #include <util/strencodings.h>
16 
17 #include <fstream>
18 #include <stdexcept>
19 #include <string>
20 #include <vector>
21 
31 UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id)
32 {
33  UniValue request(UniValue::VOBJ);
34  request.pushKV("method", strMethod);
35  request.pushKV("params", params);
36  request.pushKV("id", id);
37  return request;
38 }
39 
40 UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
41 {
42  UniValue reply(UniValue::VOBJ);
43  if (!error.isNull())
44  reply.pushKV("result", NullUniValue);
45  else
46  reply.pushKV("result", result);
47  reply.pushKV("error", error);
48  reply.pushKV("id", id);
49  return reply;
50 }
51 
52 std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
53 {
54  UniValue reply = JSONRPCReplyObj(result, error, id);
55  return reply.write() + "\n";
56 }
57 
58 UniValue JSONRPCError(int code, const std::string& message)
59 {
60  UniValue error(UniValue::VOBJ);
61  error.pushKV("code", code);
62  error.pushKV("message", message);
63  return error;
64 }
65 
69 static const std::string COOKIEAUTH_USER = "__cookie__";
71 static const char* const COOKIEAUTH_FILE = ".cookie";
72 
74 static fs::path GetAuthCookieFile(bool temp=false)
75 {
76  fs::path arg = gArgs.GetPathArg("-rpccookiefile", COOKIEAUTH_FILE);
77  if (temp) {
78  arg += ".tmp";
79  }
80  return AbsPathForConfigVal(gArgs, arg);
81 }
82 
83 static bool g_generated_cookie = false;
84 
85 bool GenerateAuthCookie(std::string *cookie_out)
86 {
87  const size_t COOKIE_SIZE = 32;
88  unsigned char rand_pwd[COOKIE_SIZE];
89  GetRandBytes(rand_pwd);
90  std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd);
91 
95  std::ofstream file;
96  fs::path filepath_tmp = GetAuthCookieFile(true);
97  file.open(filepath_tmp);
98  if (!file.is_open()) {
99  LogPrintf("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
100  return false;
101  }
102  file << cookie;
103  file.close();
104 
105  fs::path filepath = GetAuthCookieFile(false);
106  if (!RenameOver(filepath_tmp, filepath)) {
107  LogPrintf("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
108  return false;
109  }
110  g_generated_cookie = true;
111  LogPrintf("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
112 
113  if (cookie_out)
114  *cookie_out = cookie;
115  return true;
116 }
117 
118 bool GetAuthCookie(std::string *cookie_out)
119 {
120  std::ifstream file;
121  std::string cookie;
122  fs::path filepath = GetAuthCookieFile();
123  file.open(filepath);
124  if (!file.is_open())
125  return false;
126  std::getline(file, cookie);
127  file.close();
128 
129  if (cookie_out)
130  *cookie_out = cookie;
131  return true;
132 }
133 
135 {
136  try {
137  if (g_generated_cookie) {
138  // Delete the cookie file if it was generated by this process
139  fs::remove(GetAuthCookieFile());
140  }
141  } catch (const fs::filesystem_error& e) {
142  LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, fsbridge::get_filesystem_error_message(e));
143  }
144 }
145 
146 std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue& in)
147 {
148  if (!in.isArray()) {
149  throw std::runtime_error("Batch must be an array");
150  }
151  const size_t num {in.size()};
152  std::vector<UniValue> batch(num);
153  for (const UniValue& rec : in.getValues()) {
154  if (!rec.isObject()) {
155  throw std::runtime_error("Batch member must be an object");
156  }
157  size_t id = rec["id"].getInt<int>();
158  if (id >= num) {
159  throw std::runtime_error("Batch member id is larger than batch size");
160  }
161  batch[id] = rec;
162  }
163  return batch;
164 }
165 
166 void JSONRPCRequest::parse(const UniValue& valRequest)
167 {
168  // Parse request
169  if (!valRequest.isObject())
170  throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
171  const UniValue& request = valRequest.get_obj();
172 
173  // Parse id now so errors from here on will have the id
174  id = request.find_value("id");
175 
176  // Parse method
177  const UniValue& valMethod{request.find_value("method")};
178  if (valMethod.isNull())
179  throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
180  if (!valMethod.isStr())
181  throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
182  strMethod = valMethod.get_str();
183  if (fLogIPs)
184  LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod),
185  this->authUser, this->peerAddr);
186  else
187  LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
188 
189  // Parse params
190  const UniValue& valParams{request.find_value("params")};
191  if (valParams.isArray() || valParams.isObject())
192  params = valParams;
193  else if (valParams.isNull())
195  else
196  throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
197 }
ArgsManager gArgs
Definition: args.cpp:41
fs::path AbsPathForConfigVal(const ArgsManager &args, const fs::path &path, bool net_specific=true)
Most paths passed as configuration arguments are treated as relative to the datadir if they are not a...
Definition: config.cpp:211
fs::path GetPathArg(std::string arg, const fs::path &default_value={}) const
Return path argument or default value.
Definition: args.cpp:270
UniValue params
Definition: request.h:33
std::string strMethod
Definition: request.h:32
std::string peerAddr
Definition: request.h:37
void parse(const UniValue &valRequest)
Definition: request.cpp:166
std::string authUser
Definition: request.h:36
bool isArray() const
Definition: univalue.h:85
const UniValue & find_value(std::string_view key) const
Definition: univalue.cpp:233
@ VOBJ
Definition: univalue.h:24
@ VARR
Definition: univalue.h:24
std::string write(unsigned int prettyIndent=0, unsigned int indentLevel=0) const
bool isNull() const
Definition: univalue.h:79
const UniValue & get_obj() const
size_t size() const
Definition: univalue.h:71
const std::vector< UniValue > & getValues() const
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:126
bool isObject() const
Definition: univalue.h:86
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
bool RenameOver(fs::path src, fs::path dest)
Rename src to dest.
Definition: fs_helpers.cpp:250
bool fLogIPs
Definition: logging.cpp:40
#define LogPrint(category,...)
Definition: logging.h:263
#define LogPrintf(...)
Definition: logging.h:244
@ RPC
Definition: logging.h:48
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
std::string get_filesystem_error_message(const fs::filesystem_error &e)
Definition: fs.cpp:118
void GetRandBytes(Span< unsigned char > bytes) noexcept
Overall design of the RNG and entropy sources.
Definition: random.cpp:638
static fs::path GetAuthCookieFile(bool temp=false)
Get name of RPC authentication cookie file.
Definition: request.cpp:74
std::vector< UniValue > JSONRPCProcessBatchReply(const UniValue &in)
Parse JSON-RPC batch reply into a vector.
Definition: request.cpp:146
bool GetAuthCookie(std::string *cookie_out)
Read the RPC authentication cookie from disk.
Definition: request.cpp:118
std::string JSONRPCReply(const UniValue &result, const UniValue &error, const UniValue &id)
Definition: request.cpp:52
UniValue JSONRPCRequestObj(const std::string &strMethod, const UniValue &params, const UniValue &id)
JSON-RPC protocol.
Definition: request.cpp:31
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
static const char *const COOKIEAUTH_FILE
Default name for auth cookie file.
Definition: request.cpp:71
void DeleteAuthCookie()
Delete RPC authentication cookie from disk.
Definition: request.cpp:134
bool GenerateAuthCookie(std::string *cookie_out)
Generate a new RPC authentication cookie and write it to disk.
Definition: request.cpp:85
UniValue JSONRPCReplyObj(const UniValue &result, const UniValue &error, const UniValue &id)
Definition: request.cpp:40
static const std::string COOKIEAUTH_USER
Username used when cookie authentication is in use (arbitrary, only for recognizability in debugging/...
Definition: request.cpp:69
static bool g_generated_cookie
Definition: request.cpp:83
@ RPC_INVALID_REQUEST
Standard JSON-RPC 2.0 errors.
Definition: protocol.h:28
const UniValue NullUniValue
Definition: univalue.cpp:16
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::string SanitizeString(std::string_view str, int rule)
Remove unsafe chars.