fixed: Bug #3933 - Plus signs in the email address cause premium login to fail

This commit is contained in:
Nick Bolton 2014-03-14 20:34:19 +00:00
parent d5b25069be
commit 28a6b16875
9 changed files with 154 additions and 40 deletions

View File

@ -298,7 +298,7 @@ if (UNIX)
else() # not-unix else() # not-unix
list(APPEND libs Wtsapi32 Userenv Wininet comsuppw) list(APPEND libs Wtsapi32 Userenv Wininet comsuppw Shlwapi)
add_definitions( add_definitions(
/DWIN32 /DWIN32

View File

@ -24,6 +24,39 @@
#include <sstream> #include <sstream>
#include <curl/curl.h> #include <curl/curl.h>
class CurlFacade {
public:
CurlFacade();
~CurlFacade();
CString get(const CString& url);
CString urlEncode(const CString& url);
private:
CURL* m_curl;
};
//
// CArchInternetUnix
//
CString
CArchInternetUnix::get(const CString& url)
{
CurlFacade curl;
return curl.get(url);
}
CString
CArchInternetUnix::urlEncode(const CString& url)
{
CurlFacade curl;
return curl.urlEncode(url);
}
//
// CurlFacade
//
static size_t static size_t
curlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp) curlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
{ {
@ -31,47 +64,64 @@ curlWriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
return size * nmemb; return size * nmemb;
} }
CString CurlFacade::CurlFacade() :
CArchInternetUnix::get(const CString& url) m_curl(NULL)
{ {
std::string result; CURLcode init = curl_global_init(CURL_GLOBAL_ALL);
curl_global_init(CURL_GLOBAL_DEFAULT); if (init != CURLE_OK) {
throw XArch("CURL global init failed.");
try {
CURL *curl = curl_easy_init();
if (curl == NULL) {
throw XArch("CURL init failed.");
} }
try { m_curl = curl_easy_init();
if (m_curl == NULL) {
throw XArch("CURL easy init failed.");
}
}
CurlFacade::~CurlFacade()
{
if (m_curl != NULL) {
curl_easy_cleanup(m_curl);
}
curl_global_cleanup();
}
CString
CurlFacade::get(const CString& url)
{
curl_easy_setopt(m_curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, curlWriteCallback);
std::stringstream userAgent; std::stringstream userAgent;
userAgent << "Synergy "; userAgent << "Synergy ";
userAgent << kVersion; userAgent << kVersion;
curl_easy_setopt(m_curl, CURLOPT_USERAGENT, userAgent.str().c_str());
curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); std::string result;
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent.str().c_str()); curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &result);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);
CURLcode code = curl_easy_perform(curl); CURLcode code = curl_easy_perform(m_curl);
if (code != CURLE_OK) { if (code != CURLE_OK) {
LOG((CLOG_ERR "curl perform error: %s", curl_easy_strerror(code))); LOG((CLOG_ERR "curl perform error: %s", curl_easy_strerror(code)));
throw XArch("CURL perform failed."); throw XArch("CURL perform failed.");
} }
curl_easy_cleanup(curl); return result;
} }
catch (...) {
curl_easy_cleanup(curl); CString
throw; CurlFacade::urlEncode(const CString& url)
{
char* resultCStr = curl_easy_escape(m_curl, url.c_str(), 0);
if (resultCStr == NULL) {
curl_free(resultCStr);
throw XArch("CURL escape failed.");
} }
curl_global_cleanup(); std::string result(resultCStr);
} curl_free(resultCStr);
catch (...) {
curl_global_cleanup();
throw;
}
return result; return result;
} }

View File

@ -24,4 +24,5 @@
class CArchInternetUnix { class CArchInternetUnix {
public: public:
CString get(const CString& url); CString get(const CString& url);
CString urlEncode(const CString& url);
}; };

View File

@ -22,6 +22,7 @@
#include <sstream> #include <sstream>
#include <Wininet.h> #include <Wininet.h>
#include <Shlwapi.h>
struct CWinINetUrl { struct CWinINetUrl {
CString m_scheme; CString m_scheme;
@ -60,6 +61,27 @@ CArchInternetWindows::get(const CString& url)
return request.send(); return request.send();
} }
CString
CArchInternetWindows::urlEncode(const CString& url)
{
TCHAR buffer[1024];
DWORD bufferSize = sizeof(buffer);
if (UrlEscape(url.c_str(), buffer, &bufferSize, URL_ESCAPE_UNSAFE) != S_OK) {
throw XArch(new XArchEvalWindows());
}
CString result(buffer);
// the win32 url encoding funcitons are pretty useless (to us) and only
// escape "unsafe" chars, but not + or =, so we need to replace these
// manually (and probably many other chars).
find_replace_all(result, "+", "%2B");
find_replace_all(result, "=", "%3D");
return result;
}
// //
// CWinINetRequest // CWinINetRequest
// //

View File

@ -24,4 +24,5 @@
class CArchInternetWindows { class CArchInternetWindows {
public: public:
CString get(const CString& url); CString get(const CString& url);
CString urlEncode(const CString& url);
}; };

31
src/lib/base/String.cpp Normal file
View File

@ -0,0 +1,31 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2014 Bolton Software Ltd.
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "base/String.h"
void
find_replace_all(
CString& subject,
const CString& find,
const CString& replace)
{
size_t pos = 0;
while ((pos = subject.find(find, pos)) != CString::npos) {
subject.replace(pos, find.length(), replace);
pos += replace.length();
}
}

View File

@ -23,3 +23,5 @@
// use standard C++ string class for our string class // use standard C++ string class for our string class
typedef std::string CString; typedef std::string CString;
void find_replace_all(CString& subject, const CString& find, const CString& replace);

View File

@ -44,7 +44,7 @@ CToolApp::run(int argc, char** argv)
std::stringstream ss; std::stringstream ss;
ss << PREMIUM_AUTH_URL; ss << PREMIUM_AUTH_URL;
ss << "?email=" << email; ss << "?email=" << ARCH->internet().urlEncode(email);
ss << "&password=" << password; ss << "&password=" << password;
std::cout << ARCH->internet().get(ss.str()) << std::endl; std::cout << ARCH->internet().get(ss.str()) << std::endl;

View File

@ -28,3 +28,10 @@ TEST(ArchInternetTests, get)
CString result = internet.get(TEST_URL); CString result = internet.get(TEST_URL);
ASSERT_EQ("Hello world!", result); ASSERT_EQ("Hello world!", result);
} }
TEST(ArchInternetTests, urlEncode)
{
ARCH_INTERNET internet;
CString result = internet.urlEncode("hello=+&world");
ASSERT_EQ("hello%3D%2B%26world", result);
}