295 lines
9.5 KiB
C++
295 lines
9.5 KiB
C++
#include "stdafx.h"
|
|
|
|
#include <Common/md5.h>
|
|
#include <Wininet.h>
|
|
#include <time.h>
|
|
#include <windows.h>
|
|
|
|
#pragma comment(lib, "Wininet.lib")
|
|
|
|
CProjectSupport::CProjectSupport() :
|
|
m_SupportInfo({0})
|
|
{
|
|
LoadSupportInfo();
|
|
}
|
|
|
|
bool CProjectSupport::RequestCode(const char * Email)
|
|
{
|
|
if (Email == nullptr || strlen(Email) == 0 || _stricmp(Email, "thank you from project64") == 0)
|
|
{
|
|
return false;
|
|
}
|
|
stdstr_f PostData("task=RequestCode&email=%s&machine=%s", Email, MachineID());
|
|
std::vector<std::string> Headers;
|
|
DWORD StatusCode;
|
|
if (!PerformRequest(L"/index.php?option=com_project64", PostData, StatusCode, Headers))
|
|
{
|
|
return false;
|
|
}
|
|
if (StatusCode == 200)
|
|
{
|
|
for (size_t i = 0, n = Headers.size(); i < n; i++)
|
|
{
|
|
if (strcmp(Headers[i].c_str(), "Email: Sent") == 0)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool CProjectSupport::ValidateCode(const char * Code)
|
|
{
|
|
stdstr_f PostData("task=ValidateCode&code=%s&machine=%s", Code, MachineID());
|
|
std::vector<std::string> Headers;
|
|
DWORD StatusCode;
|
|
if (PerformRequest(L"/index.php?option=com_project64", PostData, StatusCode, Headers) && StatusCode == 200)
|
|
{
|
|
std::string Name, Email;
|
|
struct
|
|
{
|
|
const char * Key;
|
|
std::string & Value;
|
|
} Test[] = {
|
|
{"SupporterName: ", Name},
|
|
{"SupporterEmail: ", Email},
|
|
};
|
|
|
|
for (size_t i = 0, n = Headers.size(); i < n; i++)
|
|
{
|
|
for (size_t t = 0; t < sizeof(Test) / sizeof(Test[0]); t++)
|
|
{
|
|
size_t KeyLen = strlen(Test[t].Key);
|
|
if (strncmp(Headers[i].c_str(), Test[t].Key, KeyLen) == 0)
|
|
{
|
|
Test[t].Value = stdstr(&Headers[i][KeyLen]).Trim();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Email.length() > 0)
|
|
{
|
|
strncpy(m_SupportInfo.Code, Code, sizeof(m_SupportInfo.Code));
|
|
strncpy(m_SupportInfo.Email, Email.c_str(), sizeof(m_SupportInfo.Email));
|
|
strncpy(m_SupportInfo.Name, Name.c_str(), sizeof(m_SupportInfo.Name));
|
|
m_SupportInfo.Validated = true;
|
|
SaveSupportInfo();
|
|
}
|
|
}
|
|
return m_SupportInfo.Validated;
|
|
}
|
|
|
|
std::string CProjectSupport::GenerateMachineID(void)
|
|
{
|
|
wchar_t ComputerName[256];
|
|
DWORD Length = sizeof(ComputerName) / sizeof(ComputerName[0]);
|
|
GetComputerName(ComputerName, &Length);
|
|
|
|
wchar_t SysPath[MAX_PATH] = {0}, VolumePath[MAX_PATH] = {0};
|
|
GetSystemDirectory(SysPath, sizeof(SysPath) / sizeof(SysPath[0]));
|
|
|
|
GetVolumePathName(SysPath, VolumePath, sizeof(VolumePath) / sizeof(VolumePath[0]));
|
|
|
|
DWORD SerialNumber = 0;
|
|
GetVolumeInformation(VolumePath, nullptr, NULL, &SerialNumber, nullptr, nullptr, nullptr, NULL);
|
|
|
|
wchar_t MachineGuid[200] = {0};
|
|
HKEY hKey;
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Cryptography", 0, KEY_QUERY_VALUE | KEY_WOW64_64KEY, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
DWORD Type, dwDataSize = sizeof(MachineGuid);
|
|
RegQueryValueEx(hKey, L"MachineGuid", nullptr, &Type, (LPBYTE)MachineGuid, &dwDataSize);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
stdstr_f Machine("%s.%ud.%s", stdstr().FromUTF16(ComputerName).c_str(), SerialNumber, stdstr().FromUTF16(MachineGuid).c_str());
|
|
return std::string(MD5((const unsigned char *)Machine.c_str(), (uint32_t)((UINT_PTR)Machine.size())).hex_digest());
|
|
}
|
|
|
|
void CProjectSupport::IncrementRunCount()
|
|
{
|
|
time_t now = time(nullptr);
|
|
if (m_SupportInfo.LastUpdated <= now && ((now - m_SupportInfo.LastUpdated) / 60) < 60)
|
|
{
|
|
return;
|
|
}
|
|
m_SupportInfo.RunCount += 1;
|
|
m_SupportInfo.LastUpdated = now;
|
|
SaveSupportInfo();
|
|
}
|
|
|
|
bool CProjectSupport::ShowSupportWindow()
|
|
{
|
|
time_t now = time(nullptr);
|
|
if (m_SupportInfo.LastShown <= now && ((now - m_SupportInfo.LastShown) / 60) < 60)
|
|
{
|
|
return false;
|
|
}
|
|
m_SupportInfo.LastShown = now;
|
|
SaveSupportInfo();
|
|
return true;
|
|
}
|
|
|
|
bool CProjectSupport::PerformRequest(const wchar_t * Url, const std::string & PostData, DWORD & StatusCode, std::vector<std::string> & Headers)
|
|
{
|
|
StatusCode = 0;
|
|
Headers.clear();
|
|
|
|
HINTERNET hSession = InternetOpen(L"Project64", INTERNET_OPEN_TYPE_PRECONFIG, nullptr, nullptr, 0);
|
|
if (hSession == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
HINTERNET hConnect = InternetConnect(hSession, L"www.pj64-emu.com", INTERNET_DEFAULT_HTTPS_PORT, L"", L"", INTERNET_SERVICE_HTTP, 0, 0);
|
|
if (hConnect == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
LPCWSTR lpszAcceptTypes[] = {
|
|
L"text/*",
|
|
nullptr,
|
|
};
|
|
HINTERNET hRequest = HttpOpenRequest(hConnect, L"POST", Url, nullptr, nullptr, lpszAcceptTypes, INTERNET_FLAG_SECURE | INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_PRAGMA_NOCACHE | INTERNET_FLAG_NO_CACHE_WRITE, (LPARAM)0);
|
|
if (hRequest == nullptr)
|
|
{
|
|
InternetCloseHandle(hRequest);
|
|
return false;
|
|
}
|
|
wchar_t hdheaders[] = _T("Content-Type: application/x-www-form-urlencoded\r\n");
|
|
BOOL Success = HttpSendRequest(hRequest, hdheaders, (uint32_t)((UINT_PTR)_tcslen(hdheaders)), (LPVOID)PostData.c_str(), (uint32_t)((UINT_PTR)PostData.length()));
|
|
if (!Success)
|
|
{
|
|
InternetCloseHandle(hRequest);
|
|
return false;
|
|
}
|
|
|
|
DWORD StatusCodeSize = sizeof(StatusCode);
|
|
if (!HttpQueryInfo(hRequest, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &StatusCode, &StatusCodeSize, nullptr))
|
|
{
|
|
InternetCloseHandle(hRequest);
|
|
return false;
|
|
}
|
|
|
|
DWORD dwSize = 0;
|
|
if (!HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, nullptr, &dwSize, nullptr) && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
|
|
{
|
|
std::vector<uint8_t> RawHeaderData(dwSize);
|
|
if (!HttpQueryInfo(hRequest, HTTP_QUERY_RAW_HEADERS_CRLF, RawHeaderData.data(), &dwSize, nullptr))
|
|
{
|
|
InternetCloseHandle(hRequest);
|
|
return false;
|
|
}
|
|
strvector RawHeader = stdstr().FromUTF16((wchar_t *)RawHeaderData.data()).Tokenize("\n");
|
|
for (size_t i = 0, n = RawHeader.size(); i < n; i++)
|
|
{
|
|
RawHeader[i].Replace("\r", "");
|
|
RawHeader[i].Trim();
|
|
if (RawHeader[i].length() > 0)
|
|
{
|
|
Headers.push_back(RawHeader[i]);
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CProjectSupport::SaveSupportInfo(void)
|
|
{
|
|
std::string hash = MD5((const unsigned char *)&m_SupportInfo, sizeof(m_SupportInfo)).hex_digest();
|
|
|
|
std::vector<uint8_t> InData(sizeof(m_SupportInfo) + hash.length());
|
|
memcpy(InData.data(), (const unsigned char *)&m_SupportInfo, sizeof(m_SupportInfo));
|
|
memcpy(InData.data() + sizeof(m_SupportInfo), hash.data(), hash.length());
|
|
std::vector<uint8_t> OutData(InData.size());
|
|
|
|
z_stream defstream;
|
|
defstream.zalloc = Z_NULL;
|
|
defstream.zfree = Z_NULL;
|
|
defstream.opaque = Z_NULL;
|
|
defstream.avail_in = (uInt)InData.size();
|
|
defstream.next_in = (Bytef *)InData.data();
|
|
defstream.avail_out = (uInt)OutData.size();
|
|
defstream.next_out = (Bytef *)OutData.data();
|
|
|
|
deflateInit(&defstream, Z_BEST_COMPRESSION);
|
|
deflate(&defstream, Z_FINISH);
|
|
deflateEnd(&defstream);
|
|
|
|
OutData.resize(defstream.total_out);
|
|
|
|
for (size_t i = 0, n = OutData.size(); i < n; i++)
|
|
{
|
|
OutData[i] ^= 0xAA;
|
|
}
|
|
|
|
HKEY hKeyResults = 0;
|
|
DWORD Disposition = 0;
|
|
long lResult = RegCreateKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Project64", 0, L"", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, nullptr, &hKeyResults, &Disposition);
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx(hKeyResults, L"user", 0, REG_BINARY, (BYTE *)OutData.data(), (uint32_t)((UINT_PTR)OutData.size()));
|
|
RegCloseKey(hKeyResults);
|
|
}
|
|
}
|
|
|
|
void CProjectSupport::LoadSupportInfo(void)
|
|
{
|
|
std::string MachineID = GenerateMachineID();
|
|
std::vector<uint8_t> InData;
|
|
|
|
HKEY hKeyResults = 0;
|
|
long lResult = RegOpenKeyEx(HKEY_CURRENT_USER, L"SOFTWARE\\Project64", 0, KEY_READ, &hKeyResults);
|
|
if (lResult == ERROR_SUCCESS)
|
|
{
|
|
DWORD DataSize = 0;
|
|
if (RegQueryValueEx(hKeyResults, L"user", nullptr, nullptr, nullptr, &DataSize) == ERROR_SUCCESS)
|
|
{
|
|
InData.resize(DataSize);
|
|
if (RegQueryValueEx(hKeyResults, L"user", nullptr, nullptr, InData.data(), &DataSize) != ERROR_SUCCESS)
|
|
{
|
|
InData.clear();
|
|
}
|
|
}
|
|
}
|
|
|
|
if (hKeyResults != nullptr)
|
|
{
|
|
RegCloseKey(hKeyResults);
|
|
hKeyResults = nullptr;
|
|
}
|
|
|
|
std::vector<uint8_t> OutData;
|
|
if (InData.size() > 0)
|
|
{
|
|
for (size_t i = 0, n = InData.size(); i < n; i++)
|
|
{
|
|
InData[i] ^= 0xAA;
|
|
}
|
|
OutData.resize(sizeof(m_SupportInfo) + 100);
|
|
uLongf DestLen = (uLongf)((UINT_PTR)OutData.size());
|
|
if (uncompress(OutData.data(), &DestLen, InData.data(), (uint32_t)((UINT_PTR)InData.size())) >= 0)
|
|
{
|
|
OutData.resize(DestLen);
|
|
}
|
|
else
|
|
{
|
|
OutData.clear();
|
|
}
|
|
}
|
|
|
|
if (OutData.size() == sizeof(SupportInfo) + 32)
|
|
{
|
|
SupportInfo * Info = (SupportInfo *)OutData.data();
|
|
const char * CurrentHash = (const char *)(OutData.data() + sizeof(SupportInfo));
|
|
std::string hash = MD5((const unsigned char *)Info, sizeof(SupportInfo)).hex_digest();
|
|
if (strcmp(hash.c_str(), CurrentHash) == 0 && strcmp(Info->MachineID, MachineID.c_str()) == 0)
|
|
{
|
|
memcpy(&m_SupportInfo, Info, sizeof(SupportInfo));
|
|
}
|
|
}
|
|
strcpy(m_SupportInfo.MachineID, MachineID.c_str());
|
|
}
|