603 lines
16 KiB
C++
603 lines
16 KiB
C++
#pragma once
|
|
|
|
#include <memory>
|
|
#include <vector>
|
|
|
|
#include "except.h"
|
|
#include "template.h"
|
|
#include "generator.h"
|
|
#include "validator.h"
|
|
#include "ntpclient.h"
|
|
#include "uniconv.h"
|
|
#include "license.h"
|
|
#include "licensevalidationargs.h"
|
|
#include "licensevalidationresult.h"
|
|
|
|
#include <time.h>
|
|
|
|
#ifdef _WIN32
|
|
#include <winhttp.h>
|
|
#include <tchar.h>
|
|
#else
|
|
#include <curl/curl.h>
|
|
#endif
|
|
|
|
using namespace std;
|
|
|
|
// these methods are compiler workarounds to eliminate circular references.
|
|
// They only call the corresponding LicensingClient::... methods
|
|
// GCC complains of cross-references between LicensingClientImpl and LicensingClientT
|
|
|
|
const wchar_t * GetCurrentHardwareIdW(void *);
|
|
const char * GetCurrentHardwareIdA(void *);
|
|
bool MatchCurrentHardwareIdW(void *, const wchar_t *);
|
|
bool MatchCurrentHardwareIdA(void *, const char *);
|
|
|
|
class LicensingClientImpl
|
|
{
|
|
public:
|
|
LicensingClientImpl(void * licensingClient, bool usesWideChar)
|
|
{
|
|
licenseKeyValidationDataLen = 0;
|
|
licenseTemplateId.clear();
|
|
parentLicensingClient = licensingClient;
|
|
parentUsesWideChar = usesWideChar;
|
|
timeValidationMethod = PREFER_INTERNET_TIME;
|
|
m_licenseValidityDays = 0;
|
|
// GetCurrentHardwareIdCallback = GetCurrentHardwareId;
|
|
// MatchCurrentHardwareIdCallback = MatchCurrentHardwareId;
|
|
}
|
|
|
|
void SetLicenseTemplate(const LicenseTemplateImpl* tmpl)
|
|
{
|
|
licenseTemplate = tmpl;
|
|
}
|
|
|
|
void SetLicenseKey(const char * key)
|
|
{
|
|
licenseKey = key;
|
|
}
|
|
|
|
void SetActivationKey(const char * key)
|
|
{
|
|
activationKey = key;
|
|
}
|
|
|
|
const char * GetActivationKey()
|
|
{
|
|
return activationKey.c_str();
|
|
}
|
|
|
|
void SetHardwareId(const char * hwid)
|
|
{
|
|
hardwareId = hwid;
|
|
}
|
|
|
|
const char * GetHardwareId()
|
|
{
|
|
return hardwareId.c_str();
|
|
}
|
|
|
|
void SetLicenseTemplateId(const char * templateId)
|
|
{
|
|
licenseTemplateId = templateId;
|
|
}
|
|
|
|
const char * GetLicenseTemplateId()
|
|
{
|
|
return licenseTemplateId.c_str();
|
|
}
|
|
|
|
void SetLicenseKeyValidationData(const void* data, unsigned len)
|
|
{
|
|
licenseKeyValidationData.resize(len);
|
|
|
|
memcpy(licenseKeyValidationData.data(), data, len);
|
|
|
|
licenseKeyValidationDataLen = len;
|
|
}
|
|
|
|
LicenseTemplateImpl * CreateActivationTemplate()
|
|
{
|
|
LicenseTemplateImpl * tmpl = new LicenseTemplateImpl();
|
|
|
|
tmpl->SetCharactersPerGroup(licenseTemplate->GetCharactersPerGroup());
|
|
tmpl->SetNumberOfGroups(licenseTemplate->GetNumberOfGroups());
|
|
tmpl->SetGroupSeparator(licenseTemplate->GetGroupSeparator());
|
|
//activationKeyTemplate.SetDataSize(t.GetDataSize());
|
|
tmpl->SetSignatureSize(licenseTemplate->GetSignatureSize());
|
|
tmpl->SetEncoding(licenseTemplate->GetEncoding());
|
|
tmpl->SetPublicKeyCertificate(licenseTemplate->GetPublicKeyCertificate());
|
|
|
|
int keyLen = tmpl->GetNumberOfGroups() * tmpl->GetCharactersPerGroup()
|
|
+ (tmpl->GetNumberOfGroups() - 1) * strlen(tmpl->GetGroupSeparator());
|
|
|
|
int hwidLen = 29;
|
|
|
|
if (hardwareId.length() > 0)
|
|
hwidLen = hardwareId.length();
|
|
|
|
tmpl->SetDataSize(tmpl->GetCharactersPerGroup() * tmpl->GetNumberOfGroups() * tmpl->GetEncoding() - tmpl->GetSignatureSize());
|
|
tmpl->SetValidationDataSize((keyLen + hwidLen ) * 8 + licenseTemplate->GetValidationDataSize());
|
|
|
|
tmpl->AddDataField("ExpirationDate", FIELD_TYPE_RAW, 16, 0);
|
|
tmpl->AddValidationField("LicenseKey", FIELD_TYPE_STRING, keyLen * 8, 0);
|
|
tmpl->AddValidationField("HardwareId", FIELD_TYPE_STRING, hwidLen * 8, keyLen * 8);
|
|
|
|
if (!licenseKeyValidationData.empty())
|
|
{
|
|
tmpl->AddValidationField("LicenseKeyValidationData", FIELD_TYPE_RAW, licenseKeyValidationDataLen * 8, (keyLen + hwidLen) * 8);
|
|
}
|
|
|
|
if (licensingServiceUrl.empty())
|
|
tmpl->SetLicensingServiceUrl(licenseTemplate->GetLicensingServiceUrl());
|
|
else
|
|
tmpl->SetLicensingServiceUrl(licensingServiceUrl.c_str());
|
|
|
|
if (licenseTemplateId.empty())
|
|
tmpl->SetTemplateId(licenseTemplate->GetTemplateId());
|
|
else
|
|
tmpl->SetTemplateId(licenseTemplateId.c_str());
|
|
|
|
return tmpl;
|
|
}
|
|
|
|
bool ValidateHardwareId()
|
|
{
|
|
if (!MatchCurrentHardwareIdCallback(hardwareId.c_str()))
|
|
{
|
|
activationStatus = STATUS_INVALID_HARDWARE_ID;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool ValidateActivationKey(LicenseTemplateImpl* activationTemplate = nullptr, bool validateExpirationDate = true)
|
|
{
|
|
bool ownActivationTemplate = false;
|
|
|
|
try {
|
|
if (!activationTemplate)
|
|
{
|
|
activationTemplate = CreateActivationTemplate();
|
|
ownActivationTemplate = true;
|
|
}
|
|
|
|
KeyValidatorImpl validator(activationTemplate);
|
|
|
|
validator.SetValidationData("LicenseKey", licenseKey.c_str());
|
|
validator.SetValidationData("HardwareId", hardwareId.c_str());
|
|
|
|
if (!licenseKeyValidationData.empty())
|
|
validator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), (activationTemplate->GetValidationDataSize() + 7) >> 3);
|
|
|
|
try
|
|
{
|
|
validator.SetKey(activationKey.c_str());
|
|
}
|
|
catch (Exception * ex)
|
|
{
|
|
ex->Destroy();
|
|
activationStatus = STATUS_INVALID_ACTIVATION_KEY;
|
|
if (ownActivationTemplate) delete activationTemplate;
|
|
return false;
|
|
}
|
|
|
|
if (!validator.IsKeyValid())
|
|
{
|
|
activationStatus = STATUS_INVALID_ACTIVATION_KEY;
|
|
if (ownActivationTemplate) delete activationTemplate;
|
|
return false;
|
|
}
|
|
|
|
unsigned char rawKeyData[2];
|
|
int rawKeyDataBits = 16;
|
|
|
|
validator.QueryKeyData("ExpirationDate", rawKeyData, &rawKeyDataBits);
|
|
|
|
unsigned short keyData = (unsigned short)(((unsigned short)rawKeyData[0]) << 8 | rawKeyData[1]);
|
|
|
|
memset(&licenseExpirationTime, 0, sizeof(licenseExpirationTime));
|
|
|
|
if (keyData != 0)
|
|
{
|
|
licenseExpirationTime.tm_year = (2000 + (keyData >> 9)) - 1900;
|
|
licenseExpirationTime.tm_mon = ((keyData & 0x01FF) >> 5) - 1;
|
|
licenseExpirationTime.tm_mday = keyData & 0x001F;
|
|
|
|
if (!validateExpirationDate)
|
|
{
|
|
if (ownActivationTemplate) delete activationTemplate;
|
|
return true;
|
|
}
|
|
|
|
time_t currentTime;
|
|
|
|
if (timeValidationMethod != USE_LOCAL_TIME)
|
|
{
|
|
currentTime = NTPClient::GetCurrentTimeUTC();
|
|
|
|
if (currentTime == 0) // if couldn't obtain internet time
|
|
{
|
|
if (timeValidationMethod == USE_INTERNET_TIME) // internet time was mandatory
|
|
{
|
|
activationStatus = STATUS_NET_ERROR;
|
|
if (ownActivationTemplate) delete activationTemplate;
|
|
return false;
|
|
}
|
|
|
|
// fallback to local time
|
|
currentTime = time(NULL);
|
|
}
|
|
}
|
|
else
|
|
currentTime = time(NULL);
|
|
|
|
double diffSeconds = difftime(mktime(&licenseExpirationTime), currentTime);
|
|
|
|
if (diffSeconds < 0)
|
|
{
|
|
m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() - (int)(((time_t)(-diffSeconds) + 86400 - 1) / 86400);
|
|
|
|
if (m_licenseValidityDays < 0)
|
|
m_licenseValidityDays = 0;
|
|
|
|
activationStatus = STATUS_LICENSE_EXPIRED;
|
|
|
|
if (ownActivationTemplate) delete activationTemplate;
|
|
|
|
return false;
|
|
} else
|
|
m_licenseValidityDays = licenseTemplate->GetLicenseGracePeriod() + (int)(((time_t)diffSeconds + 86400 - 1) / 86400);
|
|
}
|
|
else
|
|
m_licenseValidityDays = -1;
|
|
|
|
if (ownActivationTemplate) delete activationTemplate;
|
|
|
|
return true;
|
|
}
|
|
catch (...)
|
|
{
|
|
if (ownActivationTemplate && activationTemplate)
|
|
delete activationTemplate;
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
bool IsLicenseValid()
|
|
{
|
|
activationStatus = STATUS_GENERIC_ERROR;
|
|
|
|
try
|
|
{
|
|
if (ValidateHardwareId() && ValidateActivationKey())
|
|
{
|
|
activationStatus = STATUS_SUCCESS;
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
catch (Exception * ex)
|
|
{
|
|
ex->Destroy();
|
|
|
|
activationStatus = STATUS_GENERIC_ERROR;
|
|
return false;
|
|
}
|
|
catch (...)
|
|
{
|
|
activationStatus = STATUS_GENERIC_ERROR;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
LicenseValidationResultImpl& ValidateLicense(LicenseValidationArgsImpl * args)
|
|
{
|
|
const LicenseImpl * license = args->GetLicense();
|
|
const char * lk = args->GetLicenseKey();
|
|
|
|
licenseKey = (lk) ? lk : "";
|
|
|
|
if (license == NULL && licenseKey.length() == 0)
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "either a license or a license key must be provided");
|
|
|
|
if (license == NULL)
|
|
{
|
|
try {
|
|
KeyValidatorImpl keyValidator;
|
|
|
|
keyValidator.SetKeyTemplate(licenseTemplate);
|
|
|
|
keyValidator.SetKey(lk);
|
|
|
|
if (licenseTemplate->GetValidationDataSize() > 0)
|
|
{
|
|
int fieldType, fieldSize, fieldOffset;
|
|
|
|
for (std::list<NameValuePair>::iterator iter = args->m_licenseKeyValidationData.begin(); iter != args->m_licenseKeyValidationData.end(); iter++)
|
|
{
|
|
if (!licenseTemplate->GetValidationField(iter->name.c_str(), &fieldType, &fieldSize, &fieldOffset))
|
|
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key validation data is invalid");
|
|
|
|
switch (fieldType)
|
|
{
|
|
case FIELD_TYPE_INTEGER:
|
|
keyValidator.SetValidationData(iter->name.c_str(), iter->intValue);
|
|
break;
|
|
|
|
case FIELD_TYPE_STRING:
|
|
keyValidator.SetValidationData(iter->name.c_str(), iter->stringValue.c_str());
|
|
break;
|
|
|
|
case FIELD_TYPE_DATE13:
|
|
case FIELD_TYPE_DATE14:
|
|
case FIELD_TYPE_DATE16:
|
|
keyValidator.SetValidationData(iter->name.c_str(), iter->dateValue.year, iter->dateValue.month, iter->dateValue.day);
|
|
break;
|
|
|
|
case FIELD_TYPE_RAW:
|
|
// keyValidator.SetValidationData(iter->name.c_str(), &(iter->value.binaryValue[0]), iter->value.binaryValue.size);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
licenseKeyValidationDataLen = (licenseTemplate->GetValidationDataSize() + 7) >> 3;
|
|
|
|
licenseKeyValidationData.resize(licenseKeyValidationDataLen);
|
|
|
|
keyValidator.QueryValidationData(NULL, licenseKeyValidationData.data(), &licenseKeyValidationDataLen);
|
|
}
|
|
|
|
if (!keyValidator.IsKeyValid())
|
|
{
|
|
throw new LicensingException(STATUS_INVALID_LICENSE_KEY, "license key is not valid");
|
|
}
|
|
|
|
AcquireLicense();
|
|
}
|
|
catch (LicensingException * ex)
|
|
{
|
|
if (ex->GetCode() == STATUS_PAYMENT_REQUIRED)
|
|
{
|
|
m_licenseValidationResult.SetPaymentRequired(true);
|
|
ex->Destroy();
|
|
}
|
|
else
|
|
throw;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
licenseKey = license->GetLicenseKey();
|
|
hardwareId = license->GetHardwareId();
|
|
activationKey = license->GetActivationKey();
|
|
|
|
const void* buf; int len;
|
|
license->GetLicenseKeyValidationData(&buf, &len);
|
|
|
|
if (buf && (len > 0))
|
|
SetLicenseKeyValidationData(buf, (unsigned int)len);
|
|
|
|
if (ValidateActivationKey(NULL, true))
|
|
{
|
|
m_licenseValidationResult.SetLicenseValid(true);
|
|
m_licenseValidationResult.SetPaymentRequired(false);
|
|
m_licenseValidationResult.SetLicenseExpired(false);
|
|
m_licenseValidationResult.SetLicense(NULL);
|
|
return m_licenseValidationResult;
|
|
}
|
|
else
|
|
{
|
|
if (activationStatus == STATUS_LICENSE_EXPIRED)
|
|
{
|
|
m_licenseValidationResult.SetLicenseExpired(true);
|
|
}
|
|
|
|
if ((activationStatus == STATUS_LICENSE_EXPIRED) && (m_licenseValidityDays > 0) && license->IsLease())
|
|
{
|
|
try
|
|
{
|
|
AcquireLicense();
|
|
m_licenseValidationResult.SetLicenseExpired(false);
|
|
}
|
|
catch (LicensingException * ex)
|
|
{
|
|
if (ex->GetCode() == STATUS_PAYMENT_REQUIRED)
|
|
{
|
|
m_licenseValidationResult.SetPaymentRequired(true);
|
|
ex->Destroy();
|
|
}
|
|
else
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (licenseExpirationTime.tm_year > 0)
|
|
{
|
|
m_licenseValidationResult.SetLicenseExpirationDate(
|
|
1900 + licenseExpirationTime.tm_year,
|
|
1 + licenseExpirationTime.tm_mon,
|
|
licenseExpirationTime.tm_mday);
|
|
}
|
|
else
|
|
{
|
|
m_licenseValidationResult.SetLicenseExpirationDate(0, 0, 0);
|
|
}
|
|
|
|
return m_licenseValidationResult;
|
|
}
|
|
|
|
void AcquireLicense()
|
|
{
|
|
if (hardwareId.empty())
|
|
hardwareId = (parentLicensingClient) ? GetCurrentHardwareIdCallback() : GetCurrentHardwareId();
|
|
|
|
unique_ptr<LicenseTemplateImpl> activationTemplate(CreateActivationTemplate());
|
|
|
|
const char * templateId = activationTemplate->GetTemplateId();
|
|
|
|
if (templateId != NULL && templateId[0] != '\0')
|
|
{
|
|
char params[64] = "ProductId=";
|
|
sprintf(params + sizeof("ProductId"), "%s", activationTemplate->GetTemplateId());
|
|
activationTemplate->SetLicensingServiceParameters(params);
|
|
}
|
|
|
|
KeyGeneratorImpl generator(activationTemplate.get());
|
|
|
|
generator.SetKeyData("ExpirationDate", (int)0);
|
|
|
|
generator.SetValidationData("LicenseKey", licenseKey.c_str());
|
|
|
|
generator.SetValidationData("HardwareId", hardwareId.c_str());
|
|
|
|
if (!licenseKeyValidationData.empty())
|
|
{
|
|
generator.SetValidationData("LicenseKeyValidationData", licenseKeyValidationData.data(), licenseKeyValidationDataLen * 8);
|
|
}
|
|
|
|
try {
|
|
activationKey = generator.GenerateKey();
|
|
}
|
|
catch (LicensingException * ex)
|
|
{
|
|
if ((ex->GetCode() == STATUS_NET_ERROR) && (generator.GetSigningServiceStatusCode() == 406))
|
|
{
|
|
m_licenseValidationResult.SetPaymentRequired(true);
|
|
ex->Destroy();
|
|
}
|
|
else
|
|
throw;
|
|
}
|
|
|
|
if (ValidateActivationKey(activationTemplate.get(), false))
|
|
{
|
|
activationStatus = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
throw new LicensingException(STATUS_GENERIC_ERROR, "internal error - invalid returned activation key");
|
|
|
|
m_licenseValidationResult.m_license = std::make_unique<LicenseImpl>();
|
|
|
|
m_licenseValidationResult.m_license->SetHardwareId(hardwareId.c_str());
|
|
m_licenseValidationResult.m_license->SetActivationKey(activationKey.c_str());
|
|
m_licenseValidationResult.m_license->SetLicenseKey(licenseKey.c_str());
|
|
m_licenseValidationResult.m_license->SetLicenseKeyValidationData(licenseKeyValidationData.data(), licenseKeyValidationDataLen);
|
|
|
|
int status = generator.GetSigningServiceStatusCode();
|
|
|
|
if (status == 200 /* HTTP OK */)
|
|
m_licenseValidationResult.m_license->SetLease(false);
|
|
else
|
|
if (status == 201 || status == 202)
|
|
m_licenseValidationResult.m_license->SetLease(true);
|
|
|
|
m_licenseValidationResult.SetLicenseValid(true);
|
|
}
|
|
|
|
void SetLicensingServiceUrl(const char * url)
|
|
{
|
|
licensingServiceUrl = url;
|
|
}
|
|
|
|
int GetLicenseActivationStatus()
|
|
{
|
|
return activationStatus;
|
|
}
|
|
|
|
void GetLicenseExpirationDate(int * year, int * month, int * day)
|
|
{
|
|
if (licenseExpirationTime.tm_year > 0)
|
|
{
|
|
*year = 1900 + licenseExpirationTime.tm_year;
|
|
*month = 1 + licenseExpirationTime.tm_mon;
|
|
*day = licenseExpirationTime.tm_mday;
|
|
} else
|
|
{
|
|
*year = 0;
|
|
*month = 0;
|
|
*day = 0;
|
|
}
|
|
}
|
|
|
|
const char * GetCurrentHardwareIdCallback()
|
|
{
|
|
if (parentUsesWideChar)
|
|
{
|
|
static string hwid = w2s(GetCurrentHardwareIdW(parentLicensingClient));
|
|
return hwid.c_str();
|
|
}
|
|
else
|
|
{
|
|
return GetCurrentHardwareIdA(parentLicensingClient);
|
|
}
|
|
}
|
|
|
|
bool MatchCurrentHardwareIdCallback(const char * hwid)
|
|
{
|
|
if (parentUsesWideChar)
|
|
{
|
|
return MatchCurrentHardwareIdW(parentLicensingClient, s2w(hwid).c_str());
|
|
}
|
|
else
|
|
return MatchCurrentHardwareIdA(parentLicensingClient, hwid);
|
|
}
|
|
|
|
static const char * GetCurrentHardwareId()
|
|
{
|
|
return KeyHelper::GetCurrentHardwareId();
|
|
}
|
|
|
|
static bool MatchCurrentHardwareId(const char * hwid)
|
|
{
|
|
return KeyHelper::MatchCurrentHardwareId(hwid);
|
|
}
|
|
|
|
void SetTimeValidationMethod(int method)
|
|
{
|
|
timeValidationMethod = method;
|
|
}
|
|
|
|
private:
|
|
void StrReplaceA(std::string& str, const std::string& oldStr, const std::string& newStr)
|
|
{
|
|
size_t pos = 0;
|
|
while ((pos = str.find(oldStr, pos)) != std::string::npos)
|
|
{
|
|
str.replace(pos, oldStr.length(), newStr);
|
|
pos += newStr.length();
|
|
}
|
|
}
|
|
|
|
private:
|
|
const LicenseTemplateImpl* licenseTemplate;
|
|
|
|
LicenseValidationResultImpl m_licenseValidationResult;
|
|
|
|
struct tm licenseExpirationTime;
|
|
string licenseKey;
|
|
string activationKey;
|
|
string hardwareId;
|
|
string licensingServiceUrl;
|
|
|
|
vector<unsigned char> licenseKeyValidationData;
|
|
int licenseKeyValidationDataLen;
|
|
int activationStatus;
|
|
string licenseTemplateId;
|
|
void * parentLicensingClient;
|
|
bool parentUsesWideChar;
|
|
int timeValidationMethod;
|
|
int m_licenseValidityDays;
|
|
//const char * (*GetCurrentHardwareIdCallback)(void * callerContext);
|
|
//bool (*MatchCurrentHardwareIdCallback)(void * callerContext, const char * hwid);
|
|
};
|