LCOV - code coverage report
Current view: top level - src/rpc - request.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 94 106 88.7 %
Date: 2020-09-26 01:30:44 Functions: 12 12 100.0 %

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

Generated by: LCOV version 1.15