BBS2chProxyAuth.cpp 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #include <time.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4. #include <sstream>
  5. #include <iomanip>
  6. #include <vector>
  7. #include "BBS2chProxyAuth.h"
  8. #include "BBS2chProxyHttpHeaders.h"
  9. #include "hmac.h"
  10. #define SID_UPDATE_INTERVAL (60*60)
  11. extern char *proxy_server;
  12. extern long proxy_port;
  13. extern long proxy_type;
  14. extern long timeout;
  15. extern char *user_agent;
  16. extern char *appKey;
  17. extern char *hmacKey;
  18. extern BBS2chProxyHttpHeaders api_auth_headers;
  19. extern int force_ipv4;
  20. extern char *api_server;
  21. extern CURLSH *curl_share;
  22. extern void log_printf(int level, const char *format ...);
  23. static size_t write_callback_download(char *buffer, size_t size, size_t nitems, void *userdata)
  24. {
  25. std::vector<char> *data = static_cast<std::vector<char> *>(userdata);
  26. size_t downloaded = size*nitems;
  27. data->insert(data->end(), buffer, buffer+downloaded);
  28. return downloaded;
  29. }
  30. bool BBS2chProxyAuth::updateSID(CURL *curl)
  31. {
  32. int ct = time(0);
  33. bool ret = false;
  34. bool shouldReleaseCurlHandle = false;
  35. pthread_mutex_lock(&mutex);
  36. if(ct < expire) {
  37. ret = true;
  38. goto last;
  39. }
  40. if (!curl) {
  41. curl = curl_easy_init();
  42. shouldReleaseCurlHandle = true;
  43. }
  44. if(curl) {
  45. CURLcode res;
  46. struct curl_slist *headers = NULL;
  47. std::vector<char> dat;
  48. char gateway[1024];
  49. snprintf(gateway,1024,"https://%s/v1/auth/",api_server);
  50. std::set<std::string> excludes;
  51. if(curl_share) curl_easy_setopt(curl, CURLOPT_SHARE, curl_share);
  52. curl_easy_setopt(curl, CURLOPT_URL, gateway);
  53. curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
  54. curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
  55. if (api_auth_headers.has("Accept-Encoding")) {
  56. excludes.insert("accept-encoding");
  57. curl_easy_setopt(curl, CURLOPT_ENCODING, api_auth_headers.get("Accept-Encoding").c_str());
  58. }
  59. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_download);
  60. curl_easy_setopt(curl, CURLOPT_WRITEDATA, &dat);
  61. curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
  62. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
  63. curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
  64. if(force_ipv4) curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
  65. if(proxy_server) {
  66. curl_easy_setopt(curl, CURLOPT_PROXY, proxy_server);
  67. curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxy_port);
  68. curl_easy_setopt(curl, CURLOPT_PROXYTYPE, proxy_type);
  69. }
  70. if (!api_auth_headers.has("User-Agent")) {
  71. curl_easy_setopt(curl, CURLOPT_USERAGENT, "");
  72. }
  73. if (!api_auth_headers.empty()) headers = api_auth_headers.appendToCurlSlist(headers, excludes);
  74. if(headers) curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
  75. curl_easy_setopt(curl, CURLOPT_POST, 1L);
  76. std::stringstream postData;
  77. std::stringstream msg;
  78. postData << "ID=&PW=&KY=" << appKey << "&CT=" << ct << "&HB=";
  79. msg << appKey << ct;
  80. unsigned char digest[32];
  81. proxy2ch_HMAC_SHA256(hmacKey, strlen(hmacKey), msg.str().c_str(), msg.str().length(), digest);
  82. for(int i=0;i<32;i++) {
  83. postData << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)digest[i];
  84. }
  85. #if LIBCURL_VERSION_NUM >= 0x071101
  86. curl_easy_setopt(curl, CURLOPT_COPYPOSTFIELDS, postData.str().c_str());
  87. #else
  88. std::string postDataStr = postData.str();
  89. curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postDataStr.c_str());
  90. #endif
  91. res = curl_easy_perform(curl);
  92. if(res == CURLE_OK) {
  93. long statusCode;
  94. curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &statusCode);
  95. //fprintf(stderr,"%ld\n",statusCode);
  96. if(statusCode == 200) {
  97. dat.push_back('\0');
  98. char *ptr = strchr(&dat.front(),':');
  99. if(ptr && !strncmp(&dat.front(),"SESSION-ID=Monazilla",20)) {
  100. sid = std::string(ptr+1);
  101. expire = ct + SID_UPDATE_INTERVAL;
  102. ret = true;
  103. log_printf(1,"Updated SID: %s\n",sid.c_str());
  104. }
  105. else {
  106. log_printf(0,"Cannot update SID: %s\n",&dat.front());
  107. }
  108. }
  109. else {
  110. log_printf(0,"Cannot update SID: API gateway returned %ld\n",statusCode);
  111. }
  112. }
  113. else log_printf(0,"curl error while updating SID: %s\n",curl_easy_strerror(res));
  114. curl_slist_free_all(headers);
  115. if (shouldReleaseCurlHandle) curl_easy_cleanup(curl);
  116. else curl_easy_reset(curl);
  117. }
  118. last:
  119. pthread_mutex_unlock(&mutex);
  120. return ret;
  121. }
  122. std::string BBS2chProxyAuth::requestBodyForURL(const char *url, CURL *curl)
  123. {
  124. if (!updateSID(curl) || sid.empty()) return "";
  125. std::stringstream postData;
  126. std::stringstream msg;
  127. postData << "sid=" << sid << "&appkey=" << appKey << "&hobo=";
  128. msg << strstr(url,"/v1/") << sid << appKey;
  129. unsigned char digest[32];
  130. proxy2ch_HMAC_SHA256(hmacKey, strlen(hmacKey), msg.str().c_str(), msg.str().length(), digest);
  131. for(int i=0;i<32;i++) {
  132. postData << std::hex << std::setw(2) << std::setfill('0') << (unsigned int)digest[i];
  133. }
  134. return postData.str();
  135. }
  136. const std::string& BBS2chProxyAuth::getSID()
  137. {
  138. updateSID(NULL);
  139. return sid;
  140. }