| 145 | } |
| 146 | |
| 147 | static bool HTTPReq_JSONRPC(const std::any& context, HTTPRequest* req) |
| 148 | { |
| 149 | // JSONRPC handles only POST |
| 150 | if (req->GetRequestMethod() != HTTPRequest::POST) { |
| 151 | req->WriteReply(HTTP_BAD_METHOD, "JSONRPC server handles only POST requests"); |
| 152 | return false; |
| 153 | } |
| 154 | // Check authorization |
| 155 | std::pair<bool, std::string> authHeader = req->GetHeader("authorization"); |
| 156 | if (!authHeader.first) { |
| 157 | req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA); |
| 158 | req->WriteReply(HTTP_UNAUTHORIZED); |
| 159 | return false; |
| 160 | } |
| 161 | |
| 162 | JSONRPCRequest jreq; |
| 163 | jreq.context = context; |
| 164 | jreq.peerAddr = req->GetPeer().ToString(); |
| 165 | if (!RPCAuthorized(authHeader.second, jreq.authUser)) { |
| 166 | LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", jreq.peerAddr); |
| 167 | |
| 168 | /* Deter brute-forcing |
| 169 | If this results in a DoS the user really |
| 170 | shouldn't have their RPC port exposed. */ |
| 171 | UninterruptibleSleep(std::chrono::milliseconds{250}); |
| 172 | |
| 173 | req->WriteHeader("WWW-Authenticate", WWW_AUTH_HEADER_DATA); |
| 174 | req->WriteReply(HTTP_UNAUTHORIZED); |
| 175 | return false; |
| 176 | } |
| 177 | |
| 178 | try { |
| 179 | // Parse request |
| 180 | UniValue valRequest; |
| 181 | if (!valRequest.read(req->ReadBody())) |
| 182 | throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); |
| 183 | |
| 184 | // Set the URI |
| 185 | jreq.URI = req->GetURI(); |
| 186 | |
| 187 | std::string strReply; |
| 188 | bool user_has_whitelist = g_rpc_whitelist.count(jreq.authUser); |
| 189 | if (!user_has_whitelist && g_rpc_whitelist_default) { |
| 190 | LogPrintf("RPC User %s not allowed to call any methods\n", jreq.authUser); |
| 191 | req->WriteReply(HTTP_FORBIDDEN); |
| 192 | return false; |
| 193 | |
| 194 | // singleton request |
| 195 | } else if (valRequest.isObject()) { |
| 196 | jreq.parse(valRequest); |
| 197 | if (user_has_whitelist && !g_rpc_whitelist[jreq.authUser].count(jreq.strMethod)) { |
| 198 | LogPrintf("RPC User %s not allowed to call method %s\n", jreq.authUser, jreq.strMethod); |
| 199 | req->WriteReply(HTTP_FORBIDDEN); |
| 200 | return false; |
| 201 | } |
| 202 | UniValue result = tableRPC.execute(jreq); |
| 203 | |
| 204 | // Send reply |
no test coverage detected