Files
ANSCORE/anslicensing/licensingclient.h

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);
};