LCOV - code coverage report
Current view: top level - src/rpc - request.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 16 124 12.9 %
Date: 2026-06-25 07:23:51 Functions: 2 11 18.2 %

          Line data    Source code
       1             : // Copyright (c) 2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Copyright (c) 2014-2025 The Dash Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #include <rpc/request.h>
       8             : 
       9             : #include <fs.h>
      10             : #include <random.h>
      11             : #include <rpc/protocol.h>
      12             : #include <util/system.h>
      13             : #include <util/strencodings.h>
      14             : 
      15             : #include <fstream>
      16             : #include <stdexcept>
      17             : #include <string>
      18             : #include <vector>
      19             : 
      20             : /**
      21             :  * JSON-RPC protocol.  Bitcoin speaks version 1.0 for maximum compatibility,
      22             :  * but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
      23             :  * unspecified (HTTP errors and contents of 'error').
      24             :  *
      25             :  * 1.0 spec: http://json-rpc.org/wiki/specification
      26             :  * 1.2 spec: http://jsonrpc.org/historical/json-rpc-over-http.html
      27             :  */
      28             : 
      29           0 : UniValue JSONRPCRequestObj(const std::string& strMethod, const UniValue& params, const UniValue& id)
      30             : {
      31           0 :     UniValue request(UniValue::VOBJ);
      32           0 :     request.pushKV("method", strMethod);
      33           0 :     request.pushKV("params", params);
      34           0 :     request.pushKV("id", id);
      35           0 :     return request;
      36           0 : }
      37             : 
      38           0 : UniValue JSONRPCReplyObj(const UniValue& result, const UniValue& error, const UniValue& id)
      39             : {
      40           0 :     UniValue reply(UniValue::VOBJ);
      41           0 :     if (!error.isNull())
      42           0 :         reply.pushKV("result", NullUniValue);
      43             :     else
      44           0 :         reply.pushKV("result", result);
      45           0 :     reply.pushKV("error", error);
      46           0 :     reply.pushKV("id", id);
      47           0 :     return reply;
      48           0 : }
      49             : 
      50           0 : std::string JSONRPCReply(const UniValue& result, const UniValue& error, const UniValue& id)
      51             : {
      52           0 :     UniValue reply = JSONRPCReplyObj(result, error, id);
      53           0 :     return reply.write() + "\n";
      54           0 : }
      55             : 
      56          34 : UniValue JSONRPCError(int code, const std::string& message)
      57             : {
      58          34 :     UniValue error(UniValue::VOBJ);
      59          34 :     error.pushKV("code", code);
      60          34 :     error.pushKV("message", message);
      61          34 :     return error;
      62          34 : }
      63             : 
      64             : /** Username used when cookie authentication is in use (arbitrary, only for
      65             :  * recognizability in debugging/logging purposes)
      66             :  */
      67             : static const std::string COOKIEAUTH_USER = "__cookie__";
      68             : /** Default name for auth cookie file */
      69             : static const char* const COOKIEAUTH_FILE = ".cookie";
      70             : 
      71             : /** Get name of RPC authentication cookie file */
      72           0 : static fs::path GetAuthCookieFile(bool temp=false)
      73             : {
      74           0 :     fs::path arg = gArgs.GetPathArg("-rpccookiefile", COOKIEAUTH_FILE);
      75           0 :     if (temp) {
      76           0 :         arg += ".tmp";
      77           0 :     }
      78           0 :     return AbsPathForConfigVal(arg);
      79           0 : }
      80             : 
      81             : static bool g_generated_cookie = false;
      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 util/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 :     g_generated_cookie = true;
     109           0 :     LogPrintf("Generated RPC authentication cookie %s\n", fs::PathToString(filepath));
     110             : 
     111           0 :     if (cookie_out)
     112           0 :         *cookie_out = cookie;
     113           0 :     return true;
     114           0 : }
     115             : 
     116           0 : bool GetAuthCookie(std::string *cookie_out)
     117             : {
     118           0 :     std::ifstream file;
     119           0 :     std::string cookie;
     120           0 :     fs::path filepath = GetAuthCookieFile();
     121           0 :     file.open(filepath);
     122           0 :     if (!file.is_open())
     123           0 :         return false;
     124           0 :     std::getline(file, cookie);
     125           0 :     file.close();
     126             : 
     127           0 :     if (cookie_out)
     128           0 :         *cookie_out = cookie;
     129           0 :     return true;
     130           0 : }
     131             : 
     132           0 : void DeleteAuthCookie()
     133             : {
     134             :     try {
     135           0 :         if (g_generated_cookie) {
     136             :             // Delete the cookie file if it was generated by this process
     137           0 :             fs::remove(GetAuthCookieFile());
     138           0 :         }
     139           0 :     } catch (const fs::filesystem_error& e) {
     140           0 :         LogPrintf("%s: Unable to remove random auth cookie file: %s\n", __func__, fsbridge::get_filesystem_error_message(e));
     141           0 :     }
     142           0 : }
     143             : 
     144           0 : std::vector<UniValue> JSONRPCProcessBatchReply(const UniValue& in)
     145             : {
     146           0 :     if (!in.isArray()) {
     147           0 :         throw std::runtime_error("Batch must be an array");
     148             :     }
     149           0 :     const size_t num {in.size()};
     150           0 :     std::vector<UniValue> batch(num);
     151           0 :     for (const UniValue& rec : in.getValues()) {
     152           0 :         if (!rec.isObject()) {
     153           0 :             throw std::runtime_error("Batch member must be an object");
     154             :         }
     155           0 :         size_t id = rec["id"].getInt<int>();
     156           0 :         if (id >= num) {
     157           0 :             throw std::runtime_error("Batch member id is larger than batch size");
     158             :         }
     159           0 :         batch[id] = rec;
     160             :     }
     161           0 :     return batch;
     162           0 : }
     163             : 
     164           0 : void JSONRPCRequest::parse(const UniValue& valRequest)
     165             : {
     166             :     // Parse request
     167           0 :     if (!valRequest.isObject())
     168           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
     169           0 :     const UniValue& request = valRequest.get_obj();
     170             : 
     171             :     // Parse id now so errors from here on will have the id
     172           0 :     id = request.find_value("id");
     173             : 
     174             :     // Parse method
     175           0 :     const UniValue& valMethod{request.find_value("method")};
     176           0 :     if (valMethod.isNull())
     177           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
     178           0 :     if (!valMethod.isStr())
     179           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
     180           0 :     strMethod = valMethod.get_str();
     181           0 :     if (strMethod != "getblocktemplate") {
     182           0 :         if (fLogIPs)
     183           0 :             LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s peeraddr=%s\n", SanitizeString(strMethod),
     184             :                 this->authUser, this->peerAddr);
     185             :         else
     186           0 :             LogPrint(BCLog::RPC, "ThreadRPCServer method=%s user=%s\n", SanitizeString(strMethod), this->authUser);
     187           0 :     }
     188             : 
     189             :     // Parse params
     190           0 :     const UniValue& valParams{request.find_value("params")};
     191           0 :     if (valParams.isArray() || valParams.isObject())
     192           0 :         params = valParams;
     193           0 :     else if (valParams.isNull())
     194           0 :         params = UniValue(UniValue::VARR);
     195             :     else
     196           0 :         throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array or object");
     197           0 : }
     198             : 
     199          10 : JSONRPCRequest JSONRPCRequest::squashed() const
     200             : {
     201          10 :    if (params.empty()) {
     202           0 :         return *this;
     203             :     }
     204          10 :     JSONRPCRequest new_request{*this};
     205          10 :     new_request.strMethod = strMethod + params[0].get_str();
     206          10 :     new_request.params.setArray();
     207          24 :     for (unsigned int i = 1; i < params.size(); ++i) {
     208          14 :         new_request.params.push_back(params[i]);
     209          14 :     }
     210          10 :     return new_request;
     211          20 : }

Generated by: LCOV version 1.16