We already have WSA init calls in init.cpp
[novacoin.git] / src / bitcoinrpc.cpp
index 89fc9b7..7a5b92a 100644 (file)
@@ -6,7 +6,7 @@
 #include "init.h"
 #include "util.h"
 #include "sync.h"
-#include "ui_interface.h"
+#include "interface.h"
 #include "base58.h"
 #include "bitcoinrpc.h"
 #include "db.h"
@@ -345,132 +345,7 @@ const CRPCCommand *CRPCTable::operator[](string name) const
     return (*it).second;
 }
 
-string rfc1123Time()
-{
-    return DateTimeStrFormat("%a, %d %b %Y %H:%M:%S +0000", GetTime());
-}
-
-static string HTTPReply(int nStatus, const string& strMsg, bool keepalive)
-{
-    if (nStatus == HTTP_UNAUTHORIZED)
-        return strprintf("HTTP/1.0 401 Authorization Required\r\n"
-            "Date: %s\r\n"
-            "Server: novacoin-json-rpc/%s\r\n"
-            "WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
-            "Content-Type: text/html\r\n"
-            "Content-Length: 296\r\n"
-            "\r\n"
-            "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
-            "\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
-            "<HTML>\r\n"
-            "<HEAD>\r\n"
-            "<TITLE>Error</TITLE>\r\n"
-            "<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
-            "</HEAD>\r\n"
-            "<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
-            "</HTML>\r\n", rfc1123Time().c_str(), FormatFullVersion().c_str());
-    const char *cStatus;
-         if (nStatus == HTTP_OK) cStatus = "OK";
-    else if (nStatus == HTTP_BAD_REQUEST) cStatus = "Bad Request";
-    else if (nStatus == HTTP_FORBIDDEN) cStatus = "Forbidden";
-    else if (nStatus == HTTP_NOT_FOUND) cStatus = "Not Found";
-    else if (nStatus == HTTP_INTERNAL_SERVER_ERROR) cStatus = "Internal Server Error";
-    else cStatus = "";
-    return strprintf(
-            "HTTP/1.1 %d %s\r\n"
-            "Date: %s\r\n"
-            "Connection: %s\r\n"
-            "Content-Length: %" PRIszu "\r\n"
-            "Content-Type: application/json\r\n"
-            "Server: novacoin-json-rpc/%s\r\n"
-            "\r\n"
-            "%s",
-        nStatus,
-        cStatus,
-        rfc1123Time().c_str(),
-        keepalive ? "keep-alive" : "close",
-        strMsg.size(),
-        FormatFullVersion().c_str(),
-        strMsg.c_str());
-}
-
-int ReadHTTPStatus(std::basic_istream<char>& stream, int &proto)
-{
-    string str;
-    getline(stream, str);
-    vector<string> vWords;
-    istringstream iss(str);
-    copy(istream_iterator<string>(iss), istream_iterator<string>(), back_inserter(vWords));
-    if (vWords.size() < 2)
-        return HTTP_INTERNAL_SERVER_ERROR;
-    proto = 0;
-    const char *ver = strstr(str.c_str(), "HTTP/1.");
-    if (ver != NULL)
-        proto = atoi(ver+7);
-    return atoi(vWords[1].c_str());
-}
-
-int ReadHTTPHeader(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet)
-{
-    int nLen = 0;
-    for ( ; ; )
-    {
-        string str;
-        std::getline(stream, str);
-        if (str.empty() || str == "\r")
-            break;
-        string::size_type nColon = str.find(":");
-        if (nColon != string::npos)
-        {
-            string strHeader = str.substr(0, nColon);
-            boost::trim(strHeader);
-            boost::to_lower(strHeader);
-            string strValue = str.substr(nColon+1);
-            boost::trim(strValue);
-            mapHeadersRet[strHeader] = strValue;
-            if (strHeader == "content-length")
-                nLen = atoi(strValue.c_str());
-        }
-    }
-    return nLen;
-}
-
-int ReadHTTP(std::basic_istream<char>& stream, map<string, string>& mapHeadersRet, string& strMessageRet)
-{
-    mapHeadersRet.clear();
-    strMessageRet.clear();
-
-    // Read status
-    int nProto = 0;
-    int nStatus = ReadHTTPStatus(stream, nProto);
-
-    // Read header
-    int nLen = ReadHTTPHeader(stream, mapHeadersRet);
-    if (nLen < 0 || nLen > (int)MAX_SIZE)
-        return HTTP_INTERNAL_SERVER_ERROR;
-
-    // Read message
-    if (nLen > 0)
-    {
-        vector<char> vch(nLen);
-        stream.read(&vch[0], nLen);
-        strMessageRet = string(vch.begin(), vch.end());
-    }
-
-    string sConHdr = mapHeadersRet["connection"];
-
-    if ((sConHdr != "close") && (sConHdr != "keep-alive"))
-    {
-        if (nProto >= 1)
-            mapHeadersRet["connection"] = "keep-alive";
-        else
-            mapHeadersRet["connection"] = "close";
-    }
-
-    return nStatus;
-}
-
-bool HTTPAuthorized(map<string, string>& mapHeaders)
+bool HTTPAuthorized(ix::WebSocketHttpHeaders& mapHeaders)
 {
     string strAuth = mapHeaders["authorization"];
     if (strAuth.substr(0,6) != "Basic ")
@@ -605,6 +480,31 @@ static CCriticalSection cs_THREAD_RPCHANDLER;
 
 void StartRPCServer()
 {
+    strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
+    if (mapArgs["-rpcpassword"].empty())
+    {
+        unsigned char rand_pwd[32];
+        RAND_bytes(rand_pwd, 32);
+        string strWhatAmI = "To use novacoind";
+        if (mapArgs.count("-server"))
+            strWhatAmI = strprintf(_("To use the %s option"), "\"-server\"");
+        else if (mapArgs.count("-daemon"))
+            strWhatAmI = strprintf(_("To use the %s option"), "\"-daemon\"");
+        uiInterface.ThreadSafeMessageBox(strprintf(
+            _("%s, you must set a rpcpassword in the configuration file:\n %s\n"
+              "It is recommended you use the following random password:\n"
+              "rpcuser=novacoinrpc\n"
+              "rpcpassword=%s\n"
+              "(you do not need to remember this password)\n"
+              "If the file does not exist, create it with owner-readable-only file permissions.\n"),
+                strWhatAmI.c_str(),
+                GetConfigFile().string().c_str(),
+                EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32).c_str()),
+            _("Error"), CClientUIInterface::OK | CClientUIInterface::MODAL);
+        StartShutdown();
+        return;
+    }
+
     string host = GetArg("-rpchost", "127.0.0.1");
     int port = GetArg("-rpcport", GetDefaultRPCPort());
 
@@ -614,19 +514,19 @@ void StartRPCServer()
 
     g_server->setOnConnectionCallback([](ix::HttpRequestPtr request, std::shared_ptr<ix::ConnectionState> connectionState) -> ix::HttpResponsePtr {
 
-        // Build a string for the response
-        std::stringstream ss;
-        ss << connectionState->getRemoteIp()
-           << " "
-           << request->method
-           << " "
-           << request->uri;
-
-        std::cout << ss.str() << std::endl;
-
         ix::WebSocketHttpHeaders headers;
+        headers["Server"] = string("novacoin-json-rpc/") + FormatFullVersion();
+        headers["WWW-Authenticate"] = "Basic realm=\"jsonrpc\"";
+
+        if (!HTTPAuthorized(request->headers))
+        {
+            printf("ThreadRPCServer incorrect password attempt from %s\n", connectionState->getRemoteIp().c_str());
+            connectionState->setTerminated();
+            return std::make_shared<ix::HttpResponse>(401, "Unauthorized", ix::HttpErrorCode::Ok, headers, "Not authorized");
+        }
 
         if (request->method != "POST") {
+            connectionState->setTerminated();
             return std::make_shared<ix::HttpResponse>(400, "Bad request", ix::HttpErrorCode::Ok, headers, "Bad request");
         }
 
@@ -745,6 +645,9 @@ Object CallRPC(const string& strMethod, const Array& params)
               "If the file does not exist, create it with owner-readable-only file permissions."),
                 GetConfigFile().string().c_str()));
 
+    // Init net subsystem
+    ix::initNetSystem();
+
     // Create HTTP client
     ix::HttpClient httpClient;
     ix::HttpRequestArgsPtr args = httpClient.createRequest();