LCOV - code coverage report
Current view: top level - src/rpc - request.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 2 109 1.8 %
Date: 2023-09-26 12:08:55 Functions: 2 12 16.7 %

          Line data    Source code
       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             : 
      22             : /**
      23             :  * JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
      24             :  * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
      25             :  * unspecified (HTTP errors and contents of 'error').
      26             :  *
      27             :  * 1.0 spec: http://json-rpc.org/wiki/specification
      28             :  * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
      29             :  */
      30             : 
      31           0 : UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id)
      32             : {
      33           0 :     UniValue request(UniValue::VOBJ);
      34           0 :     request.pushKV("method", strMethod);
      35           0 :     request.pushKV("params", params);
      36           0 :     request.pushKV("id", id);
      37           0 :     return request;
      38           0 : }
      39             : 
      40           0 : UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
      41             : {
      42           0 :     UniValue reply(UniValue::VOBJ);
      43           0 :     if (!error.isNull())
      44           0 :         reply.pushKV("result", NullUniValue);
      45             :     else
      46           0 :         reply.pushKV("result", result);
      47           0 :     reply.pushKV("error", error);
      48           0 :     reply.pushKV("id", id);
      49           0 :     return reply;
      50           0 : }
      51             : 
      52           0 : std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
      53             : {
      54           0 :     UniValue reply = JSONRPCReplyObj(result, error, id);
      55           0 :     return reply.write() + "\n";
      56           0 : }
      57             : 
      58           0 : UniValue JSONRPCError(int code, const std::string& message)
      59             : {
      60           0 :     UniValue error(UniValue::VOBJ);
      61           0 :     error.pushKV("code", code);
      62           0 :     error.pushKV("message", message);
      63           0 :     return error;
      64           0 : }
      65             : 
      66             : /** Username used when cookie authentication is in use (arbitrary, only for
      67             :  * recognizability in debugging/logging purposes)
      68             :  */
      69           2 : static const std::string COOKIEAUTH_USER = "__cookie__";
      70             : /** Default name for auth cookie file */
      71             : static const char* const COOKIEAUTH_FILE = ".cookie";
      72             : 
      73             : /** Get name of RPC authentication cookie file */
      74           2 : static fs::path GetAuthCookieFile(bool temp=false)
      75             : {
      76           0 :     fs::path arg = gArgs.GetPathArg("-rpccookiefile", COOKIEAUTH_FILE);
      77           0 :     if (temp) {
      78           0 :         arg += ".tmp";
      79           0 :     }
      80           0 :     return AbsPathForConfigVal(gArgs, arg);
      81           0 : }
      82             : 
      83           0 : bool GenerateAuthCookie(std::string *cookie_out)
      84             : {
      85           0 :     const size_t COOKIE_SIZE = 32;
      86             :     unsigned char rand_pwd[COOKIE_SIZE];
      87           0 :     GetRandBytes(rand_pwd);
      88           0 :     std::string cookie = COOKIEAUTH_USER + ":" + HexStr(rand_pwd);
      89             : 
      90             :     /** the umask determines what permissions are used to create this file -
      91             :      * these are set to 0077 in common/system.cpp.
      92             :      */
      93           0 :     std::ofstream file;
      94           0 :     fs::path filepath_tmp = GetAuthCookieFile(true);
      95           0 :     file.open(filepath_tmp);
      96           0 :     if (!file.is_open()) {
      97           0 :         LogPrintf("Unable to open cookie authentication file %s for writing\n", fs::PathToString(filepath_tmp));
      98           0 :         return false;
      99             :     }
     100           0 :     file << cookie;
     101           0 :     file.close();
     102             : 
     103           0 :     fs::path filepath = GetAuthCookieFile(false);
     104           0 :     if (!RenameOver(filepath_tmp, filepath)) {
     105           0 :         LogPrintf("Unable to rename cookie authentication file %s to %s\n", fs::PathToString(filepath_tmp), fs::PathToString(filepath));
     106           0 :         return false;
     107             :     }
     108           0 :     LogPrintf("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
     109             : 
     110           0 :     if (cookie_out)
     111           0 :         *cookie_out = cookie;
     112           0 :     return true;
     113           0 : }
     114             : 
     115           0 : bool GetAuthCookie(std::string *cookie_out)
     116             : {
     117           0 :     std::ifstream file;
     118           0 :     std::string cookie;
     119           0 :     fs::path filepath = GetAuthCookieFile();
     120           0 :     file.open(filepath);
     121           0 :     if (!file.is_open())
     122           0 :         return false;
     123           0 :     std::getline(file, cookie);
     124           0 :     file.close();
     125             : 
     126           0 :     if (cookie_out)
     127           0 :         *cookie_out = cookie;
     128           0 :     return true;
     129           0 : }
     130             : 
     131           0 : void DeleteAuthCookie()
     132             : {
     133             :     try {
     134           0 :         fs::remove(GetAuthCookieFile());
     135           0 :     } catch (const fs::filesystem_error& e) {
     136           0 :         LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, fsbridge::get_filesystem_error_message(e));
     137           0 :     }
     138           0 : }
     139             : 
     140           0 : std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue& in)
     141             : {
     142           0 :     if (!in.isArray()) {
     143           0 :         throw std::runtime_error("Batch must be an array");
     144             :     }
     145           0 :     const size_t num {in.size()};
     146           0 :     std::vector<UniValue> batch(num);
     147           0 :     for (const UniValue& rec : in.getValues()) {
     148           0 :         if (!rec.isObject()) {
     149           0 :             throw std::runtime_error("Batch member must be an object");
     150             :         }
     151           0 :         size_t id = rec["id"].getInt<int>();
     152           0 :         if (id >= num) {
     153           0 :             throw std::runtime_error("Batch member id is larger than batch size");
     154             :         }
     155           0 :         batch[id] = rec;
     156             :     }
     157           0 :     return batch;
     158           0 : }
     159             : 
     160           0 : void JSONRPCRequest::parse(const UniValue& valRequest)
     161             : {
     162             :     // Parse request
     163           0 :     if (!valRequest.isObject())
     164           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
     165           0 :     const UniValue& request = valRequest.get_obj();
     166             : 
     167             :     // Parse id now so errors from here on will have the id
     168           0 :     id = request.find_value("id");
     169             : 
     170             :     // Parse method
     171           0 :     const UniValue& valMethod{request.find_value("method")};
     172           0 :     if (valMethod.isNull())
     173           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
     174           0 :     if (!valMethod.isStr())
     175           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
     176           0 :     strMethod = valMethod.get_str();
     177           0 :     if (fLogIPs)
     178           0 :         LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod),
     179             :             this->authUser, this->peerAddr);
     180             :     else
     181           0 :         LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
     182             : 
     183             :     // Parse params
     184           0 :     const UniValue& valParams{request.find_value("params")};
     185           0 :     if (valParams.isArray() || valParams.isObject())
     186           0 :         params = valParams;
     187           0 :     else if (valParams.isNull())
     188           0 :         params = UniValue(UniValue::VARR);
     189             :     else
     190           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
     191           0 : }

Generated by: LCOV version 1.14