license: Implemented new license format
* Implemented new format splitting user, version, and usage period into separate lines * Refactored all classes: License, LicenseGenerator, LicenseChecker * Removed redundant license check hash from ApplicationSettings, don't generate, store and check it anymore * Moved license checking and encoding logic to LicenseChecker * Moved default for license generation to main.cpp * Refactored license checking logic in whole app, removed involved message types * Added LicenseCheckerTestSuite for checking all legacy and current license types * Generate new license type lifelong
This commit is contained in:
@@ -349,6 +349,7 @@ set_property(
|
||||
TARGET ${LIB_CXX_PROJECT_NAME}
|
||||
PROPERTY INCLUDE_DIRECTORIES
|
||||
"${LIB_CXX_INCLUDE_PATHS}"
|
||||
"${LIB_LICENSE_INCLUDE_PATHS}"
|
||||
"${LIB_UTILITY_INCLUDE_PATHS}"
|
||||
"${LIB_INCLUDE_PATHS}"
|
||||
)
|
||||
|
||||
@@ -82,7 +82,6 @@
|
||||
</recent_projects>
|
||||
|
||||
<license>
|
||||
<check><!-- STRING: hashed path of the working directory used when entering the license key --></check>
|
||||
<license><!-- STRING: the license key --></license>
|
||||
<non_commercial_use><!-- BOOL: if used non-commercially --></non_commercial_use>
|
||||
</license>
|
||||
|
||||
+2
-3
@@ -15,7 +15,6 @@
|
||||
#include "QtCoreApplication.h"
|
||||
#include "utilityQt.h"
|
||||
#include "QtViewFactory.h"
|
||||
#include "QtEulaWindow.h"
|
||||
#include "ApplicationSettings.h"
|
||||
#include "CommandLineParser.h"
|
||||
#include "ConsoleLogger.h"
|
||||
@@ -258,7 +257,7 @@ int main(int argc, char *argv[])
|
||||
|
||||
// check if already agreed to EULA
|
||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||
if (appSettings->getAcceptedEulaVersion() < QtEulaWindow::EULA_VERSION)
|
||||
if (appSettings->getAcceptedEulaVersion() < Application::EULA_VERSION)
|
||||
{
|
||||
if (!commandLineParser.acceptedEULA())
|
||||
{
|
||||
@@ -282,7 +281,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
|
||||
std::cout << "\nSourcetrail End User License Agreement accepted.\n" << std::endl;
|
||||
appSettings->setAcceptedEulaVersion(QtEulaWindow::EULA_VERSION);
|
||||
appSettings->setAcceptedEulaVersion(Application::EULA_VERSION);
|
||||
appSettings->save();
|
||||
}
|
||||
|
||||
|
||||
+81
-45
@@ -1,36 +1,36 @@
|
||||
#include "Application.h"
|
||||
|
||||
#include "IDECommunicationController.h"
|
||||
#include "NetworkFactory.h"
|
||||
#include "DialogView.h"
|
||||
#include "GraphViewStyle.h"
|
||||
#include "MainView.h"
|
||||
#include "ViewFactory.h"
|
||||
#include "StorageCache.h"
|
||||
#include "LicenseChecker.h"
|
||||
#include "ApplicationSettings.h"
|
||||
#include "ProjectSettings.h"
|
||||
#include "AppPath.h"
|
||||
#include "ColorScheme.h"
|
||||
#include "DialogView.h"
|
||||
#include "FileSystem.h"
|
||||
#include "SharedMemoryGarbageCollector.h"
|
||||
#include "GraphViewStyle.h"
|
||||
#include "IDECommunicationController.h"
|
||||
#include "LicenseChecker.h"
|
||||
#include "logging.h"
|
||||
#include "LogManager.h"
|
||||
#include "MainView.h"
|
||||
#include "MessageFilterErrorCountUpdate.h"
|
||||
#include "MessageFilterFocusInOut.h"
|
||||
#include "MessageFilterSearchAutocomplete.h"
|
||||
#include "MessageQueue.h"
|
||||
#include "MessageForceEnterLicense.h"
|
||||
#include "MessageQuitApplication.h"
|
||||
#include "MessageStatus.h"
|
||||
#include "NetworkFactory.h"
|
||||
#include "ProjectSettings.h"
|
||||
#include "SharedMemoryGarbageCollector.h"
|
||||
#include "StorageCache.h"
|
||||
#include "TabId.h"
|
||||
#include "TaskManager.h"
|
||||
#include "TaskScheduler.h"
|
||||
#include "tracing.h"
|
||||
#include "UpdateChecker.h"
|
||||
#include "UserPaths.h"
|
||||
#include "utilityString.h"
|
||||
#include "utilityUuid.h"
|
||||
#include "Version.h"
|
||||
#include "UpdateChecker.h"
|
||||
#include "ViewFactory.h"
|
||||
|
||||
std::shared_ptr<Application> Application::s_instance;
|
||||
std::string Application::s_uuid;
|
||||
@@ -38,7 +38,17 @@ std::string Application::s_uuid;
|
||||
void Application::createInstance(
|
||||
const Version& version, ViewFactory* viewFactory, NetworkFactory* networkFactory
|
||||
){
|
||||
bool hasGui = (viewFactory != nullptr);
|
||||
|
||||
Version::setApplicationVersion(version);
|
||||
LicenseChecker::loadPublicKey();
|
||||
LicenseChecker::setEncodeKey(AppPath::getAppPath().str());
|
||||
|
||||
if (hasGui)
|
||||
{
|
||||
GraphViewStyle::setImpl(viewFactory->createGraphStyleImpl());
|
||||
}
|
||||
|
||||
loadSettings();
|
||||
|
||||
SharedMemoryGarbageCollector* collector = SharedMemoryGarbageCollector::createInstance();
|
||||
@@ -51,7 +61,6 @@ void Application::createInstance(
|
||||
TaskManager::createScheduler(TabId::background());
|
||||
MessageQueue::getInstance();
|
||||
|
||||
bool hasGui = (viewFactory != nullptr);
|
||||
s_instance = std::shared_ptr<Application>(new Application(hasGui));
|
||||
|
||||
s_instance->m_storageCache = std::make_shared<StorageCache>();
|
||||
@@ -60,9 +69,6 @@ void Application::createInstance(
|
||||
{
|
||||
s_instance->m_mainView = viewFactory->createMainView(s_instance->m_storageCache.get());
|
||||
s_instance->m_mainView->setup();
|
||||
s_instance->updateTitle();
|
||||
|
||||
GraphViewStyle::setImpl(viewFactory->createGraphStyleImpl());
|
||||
}
|
||||
|
||||
if (networkFactory != nullptr)
|
||||
@@ -121,7 +127,6 @@ void Application::loadStyle(const FilePath& colorSchemePath)
|
||||
|
||||
Application::Application(bool withGUI)
|
||||
: m_hasGUI(withGUI)
|
||||
, m_licenseType(MessageEnteredLicense::LICENSE_NONE)
|
||||
, m_lastLicenseCheck(TimeStamp::now())
|
||||
{
|
||||
}
|
||||
@@ -207,21 +212,6 @@ void Application::handleMessage(MessageActivateWindow* message)
|
||||
}
|
||||
}
|
||||
|
||||
void Application::handleMessage(MessageEnteredLicense* message)
|
||||
{
|
||||
MessageStatus(L"Found valid license key, unlocked application.").dispatch();
|
||||
|
||||
m_licenseType = message->type;
|
||||
|
||||
updateTitle();
|
||||
loadSettings();
|
||||
|
||||
if (m_hasGUI)
|
||||
{
|
||||
m_mainView->refreshViews();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::handleMessage(MessageIndexingFinished* message)
|
||||
{
|
||||
logStorageStats();
|
||||
@@ -241,11 +231,7 @@ void Application::handleMessage(MessageLoadProject* message)
|
||||
TRACE("app load project");
|
||||
|
||||
FilePath projectSettingsFilePath(message->projectSettingsFilePath);
|
||||
if (m_hasGUI)
|
||||
{
|
||||
bool showStartWindow = projectSettingsFilePath.empty();
|
||||
m_mainView->loadWindow(showStartWindow);
|
||||
}
|
||||
loadWindow(projectSettingsFilePath.empty());
|
||||
|
||||
if (projectSettingsFilePath.empty())
|
||||
{
|
||||
@@ -332,6 +318,8 @@ void Application::handleMessage(MessageRefreshUI* message)
|
||||
|
||||
if (m_hasGUI)
|
||||
{
|
||||
updateTitle();
|
||||
|
||||
if (message->loadStyle)
|
||||
{
|
||||
loadStyle(ApplicationSettings::getInstance()->getColorSchemePath());
|
||||
@@ -366,9 +354,9 @@ void Application::handleMessage(MessageWindowFocus* message)
|
||||
m_lastLicenseCheck = TimeStamp::now();
|
||||
|
||||
LicenseChecker::LicenseState state = LicenseChecker::checkCurrentLicense();
|
||||
if (state != LicenseChecker::LICENSE_VALID && state != LicenseChecker::LICENSE_MOVED)
|
||||
if (state != LicenseChecker::LicenseState::VALID)
|
||||
{
|
||||
MessageForceEnterLicense(state).dispatch();
|
||||
m_mainView->forceEnterLicense(LicenseChecker::getLicenseErrorForState(state));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -417,6 +405,54 @@ void Application::startMessagingAndScheduling()
|
||||
queue->startMessageLoopThreaded();
|
||||
}
|
||||
|
||||
void Application::loadWindow(bool showStartWindow)
|
||||
{
|
||||
if (!m_hasGUI)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!m_loadedWindow)
|
||||
{
|
||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||
LicenseChecker::LicenseState state = LicenseChecker::LicenseState::VALID;
|
||||
std::string licenseError;
|
||||
|
||||
if (!appSettings->getNonCommercialUse())
|
||||
{
|
||||
state = LicenseChecker::setCurrentLicenseStringEncoded(appSettings->getLicenseString());
|
||||
licenseError = LicenseChecker::getLicenseErrorForState(state);
|
||||
|
||||
if (state == LicenseChecker::LicenseState::VALID)
|
||||
{
|
||||
MessageStatus(L"Found valid license key, unlocked application.").dispatch();
|
||||
}
|
||||
else if (state == LicenseChecker::LicenseState::EMPTY)
|
||||
{
|
||||
licenseError = "";
|
||||
}
|
||||
else if (state == LicenseChecker::LicenseState::MALFORMED)
|
||||
{
|
||||
licenseError = "Plese re-enter your license key.";
|
||||
appSettings->setLicenseString("");
|
||||
appSettings->save();
|
||||
}
|
||||
}
|
||||
|
||||
updateTitle();
|
||||
|
||||
bool showEula = (appSettings->getAcceptedEulaVersion() < EULA_VERSION);
|
||||
bool enterLicense = (state != LicenseChecker::LicenseState::VALID);
|
||||
|
||||
m_mainView->loadWindow(showStartWindow, showEula, enterLicense, licenseError);
|
||||
m_loadedWindow = true;
|
||||
}
|
||||
else if (!showStartWindow)
|
||||
{
|
||||
m_mainView->hideStartScreen();
|
||||
}
|
||||
}
|
||||
|
||||
void Application::refreshProject(RefreshMode refreshMode)
|
||||
{
|
||||
if (m_project && checkSharedMemory())
|
||||
@@ -487,16 +523,15 @@ void Application::updateTitle()
|
||||
{
|
||||
std::wstring title = L"Sourcetrail";
|
||||
|
||||
switch (m_licenseType)
|
||||
switch (LicenseChecker::getCurrentLicenseType())
|
||||
{
|
||||
case MessageEnteredLicense::LICENSE_TEST:
|
||||
case LicenseType::TEST:
|
||||
title += L" [test]";
|
||||
break;
|
||||
case MessageEnteredLicense::LICENSE_NONE:
|
||||
case MessageEnteredLicense::LICENSE_NON_COMMERCIAL:
|
||||
case LicenseType::NON_COMMERCIAL:
|
||||
title += L" [non-commercial]";
|
||||
break;
|
||||
case MessageEnteredLicense::LICENSE_COMMERCIAL:
|
||||
case LicenseType::COMMERCIAL:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -519,7 +554,8 @@ bool Application::checkSharedMemory()
|
||||
std::wstring error = utility::decodeFromUtf8(SharedMemory::checkSharedMemory(getUUID()));
|
||||
if (error.size())
|
||||
{
|
||||
MessageStatus(L"Error on accessing shared memory. Indexing not possible. Please restart computer or run as admin: " + error, true).dispatch();
|
||||
MessageStatus(L"Error on accessing shared memory. Indexing not possible. "
|
||||
"Please restart computer or run as admin: " + error, true).dispatch();
|
||||
handleDialog(
|
||||
L"There was an error accessing shared memory on your computer: " + error + L"\n\n"
|
||||
"Project indexing is not possible. Please restart your computer or try running Sourcetrail as admin. If the "
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include "MessageListener.h"
|
||||
#include "MessageIndexingFinished.h"
|
||||
#include "MessageActivateWindow.h"
|
||||
#include "MessageEnteredLicense.h"
|
||||
#include "MessageLoadProject.h"
|
||||
#include "MessageRefresh.h"
|
||||
#include "MessageRefreshUI.h"
|
||||
@@ -27,7 +26,6 @@ class ViewFactory;
|
||||
|
||||
class Application
|
||||
: public MessageListener<MessageActivateWindow>
|
||||
, public MessageListener<MessageEnteredLicense>
|
||||
, public MessageListener<MessageIndexingFinished>
|
||||
, public MessageListener<MessageLoadProject>
|
||||
, public MessageListener<MessageRefresh>
|
||||
@@ -36,6 +34,8 @@ class Application
|
||||
, public MessageListener<MessageWindowFocus>
|
||||
{
|
||||
public:
|
||||
static const int EULA_VERSION = 5;
|
||||
|
||||
static void createInstance(const Version& version, ViewFactory* viewFactory, NetworkFactory* networkFactory);
|
||||
static std::shared_ptr<Application> getInstance();
|
||||
static void destroyInstance();
|
||||
@@ -68,7 +68,6 @@ private:
|
||||
Application(bool withGUI = true);
|
||||
|
||||
void handleMessage(MessageActivateWindow* message) override;
|
||||
void handleMessage(MessageEnteredLicense* message) override;
|
||||
void handleMessage(MessageIndexingFinished* message) override;
|
||||
void handleMessage(MessageLoadProject* message) override;
|
||||
void handleMessage(MessageRefresh* message) override;
|
||||
@@ -79,6 +78,8 @@ private:
|
||||
FilePath migrateProjectSettings(const FilePath& projectSettingsFilePath) const;
|
||||
void startMessagingAndScheduling();
|
||||
|
||||
void loadWindow(bool showStartWindow);
|
||||
|
||||
void refreshProject(RefreshMode refreshMode);
|
||||
void updateRecentProjects(const FilePath& projectSettingsFilePath);
|
||||
|
||||
@@ -89,6 +90,8 @@ private:
|
||||
bool checkSharedMemory();
|
||||
|
||||
const bool m_hasGUI;
|
||||
bool m_loadedWindow = false;
|
||||
|
||||
std::shared_ptr<Project> m_project;
|
||||
std::shared_ptr<StorageCache> m_storageCache;
|
||||
|
||||
@@ -97,7 +100,6 @@ private:
|
||||
std::shared_ptr<IDECommunicationController> m_ideCommunicationController;
|
||||
std::shared_ptr<UpdateChecker> m_updateChecker;
|
||||
|
||||
MessageEnteredLicense::LicenseType m_licenseType;
|
||||
TimeStamp m_lastLicenseCheck;
|
||||
};
|
||||
|
||||
|
||||
@@ -495,12 +495,10 @@ add_files(
|
||||
utility/messaging/type/MessageClearStatusView.h
|
||||
utility/messaging/type/MessageCodeReference.h
|
||||
utility/messaging/type/MessageDeactivateEdge.h
|
||||
utility/messaging/type/MessageEnteredLicense.h
|
||||
utility/messaging/type/MessageFind.h
|
||||
utility/messaging/type/MessageFlushUpdates.h
|
||||
utility/messaging/type/MessageFocusIn.h
|
||||
utility/messaging/type/MessageFocusOut.h
|
||||
utility/messaging/type/MessageForceEnterLicense.h
|
||||
utility/messaging/type/MessageGraphNodeBundleSplit.h
|
||||
utility/messaging/type/MessageGraphNodeExpand.h
|
||||
utility/messaging/type/MessageGraphNodeHide.h
|
||||
@@ -655,7 +653,5 @@ add_files(
|
||||
LanguagePackage.h
|
||||
LanguagePackageManager.cpp
|
||||
LanguagePackageManager.h
|
||||
LicenseChecker.cpp
|
||||
LicenseChecker.h
|
||||
UpdateChecker.h
|
||||
)
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
#include "LicenseChecker.h"
|
||||
|
||||
#include "ApplicationSettings.h"
|
||||
#include "AppPath.h"
|
||||
#include "License.h"
|
||||
#include "logging.h"
|
||||
#include "utilityApp.h"
|
||||
|
||||
std::string LicenseChecker::getCurrentLicenseString()
|
||||
{
|
||||
License license;
|
||||
bool isLoaded = license.loadFromEncodedString(
|
||||
ApplicationSettings::getInstance()->getLicenseString(), AppPath::getAppPath().str());
|
||||
|
||||
if (isLoaded)
|
||||
{
|
||||
return license.getLicenseString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
void LicenseChecker::saveCurrentLicenseString(const std::string& licenseString)
|
||||
{
|
||||
License license;
|
||||
bool isLoaded = license.loadFromString(licenseString);
|
||||
if (!isLoaded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
utility::saveLicense(&license);
|
||||
}
|
||||
|
||||
bool LicenseChecker::isCurrentLicenseValid()
|
||||
{
|
||||
return checkCurrentLicense() == LICENSE_VALID;
|
||||
}
|
||||
|
||||
LicenseChecker::LicenseState LicenseChecker::checkCurrentLicense()
|
||||
{
|
||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||
if (appSettings == nullptr)
|
||||
{
|
||||
LOG_ERROR_STREAM(<< "Unable to retrieve app settings");
|
||||
return LICENSE_EMPTY;
|
||||
}
|
||||
|
||||
const FilePath appPath = AppPath::getAppPath();
|
||||
|
||||
if (appPath.empty())
|
||||
{
|
||||
LOG_ERROR_STREAM(<< "Failed to retrieve app path");
|
||||
return LICENSE_EMPTY;
|
||||
}
|
||||
|
||||
std::string licenseString = appSettings->getLicenseString();
|
||||
if (licenseString.size() == 0)
|
||||
{
|
||||
LOG_ERROR_STREAM(<< "No license key available.");
|
||||
return LICENSE_EMPTY;
|
||||
}
|
||||
|
||||
if (!License::checkLocation(appPath.getAbsolute().str(), appSettings->getLicenseCheck()))
|
||||
{
|
||||
LOG_ERROR_STREAM(<< "Application was moved, reenter license key.");
|
||||
return LICENSE_MOVED;
|
||||
}
|
||||
|
||||
License license;
|
||||
bool isLoaded = license.loadFromEncodedString(licenseString, appPath.str());
|
||||
if (!isLoaded)
|
||||
{
|
||||
LOG_ERROR_STREAM(<< "License is invalid or application was moved.");
|
||||
return LICENSE_MOVED;
|
||||
}
|
||||
|
||||
return checkLicense(license);
|
||||
}
|
||||
|
||||
LicenseChecker::LicenseState LicenseChecker::checkLicenseString(const std::string& licenseString)
|
||||
{
|
||||
if (licenseString.size() == 0)
|
||||
{
|
||||
return LICENSE_EMPTY;
|
||||
}
|
||||
|
||||
License license;
|
||||
bool isLoaded = license.loadFromString(licenseString);
|
||||
if (!isLoaded)
|
||||
{
|
||||
return LICENSE_MALFORMED;
|
||||
}
|
||||
|
||||
license.print();
|
||||
|
||||
return checkLicense(license);
|
||||
}
|
||||
|
||||
MessageEnteredLicense::LicenseType LicenseChecker::getCurrentLicenseType()
|
||||
{
|
||||
License license;
|
||||
bool isLoaded = license.loadFromEncodedString(
|
||||
ApplicationSettings::getInstance()->getLicenseString(), AppPath::getAppPath().str());
|
||||
|
||||
if (!isLoaded)
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_NONE;
|
||||
}
|
||||
|
||||
LicenseState state = checkLicense(license);
|
||||
if (state != LICENSE_VALID)
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_NONE;
|
||||
}
|
||||
else if (license.isTestLicense())
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_TEST;
|
||||
}
|
||||
else if (license.isNonCommercialLicenseType())
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_NON_COMMERCIAL;
|
||||
}
|
||||
|
||||
return MessageEnteredLicense::LICENSE_COMMERCIAL;
|
||||
}
|
||||
|
||||
MessageEnteredLicense::LicenseType LicenseChecker::getLicenseType(const std::string& licenseString)
|
||||
{
|
||||
if (licenseString.size() == 0)
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_NONE;
|
||||
}
|
||||
|
||||
License license;
|
||||
bool isLoaded = license.loadFromString(licenseString);
|
||||
if (!isLoaded)
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_NONE;
|
||||
}
|
||||
|
||||
LicenseState state = checkLicense(license);
|
||||
if (state != LICENSE_VALID)
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_NONE;
|
||||
}
|
||||
else if (license.isTestLicense())
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_TEST;
|
||||
}
|
||||
else if (license.isNonCommercialLicenseType())
|
||||
{
|
||||
return MessageEnteredLicense::LICENSE_NON_COMMERCIAL;
|
||||
}
|
||||
|
||||
return MessageEnteredLicense::LICENSE_COMMERCIAL;
|
||||
}
|
||||
|
||||
std::string LicenseChecker::getCurrentLicenseTypeString()
|
||||
{
|
||||
// WARNING: Don't change these string. The server API relies on them.
|
||||
switch (getCurrentLicenseType())
|
||||
{
|
||||
case MessageEnteredLicense::LICENSE_NONE:
|
||||
case MessageEnteredLicense::LICENSE_NON_COMMERCIAL:
|
||||
return "private";
|
||||
case MessageEnteredLicense::LICENSE_TEST:
|
||||
return "test";
|
||||
case MessageEnteredLicense::LICENSE_COMMERCIAL:
|
||||
return "commercial";
|
||||
}
|
||||
|
||||
return "private";
|
||||
}
|
||||
|
||||
LicenseChecker::LicenseState LicenseChecker::checkLicense(License& license)
|
||||
{
|
||||
if (license.isExpired())
|
||||
{
|
||||
return LICENSE_EXPIRED;
|
||||
}
|
||||
|
||||
if (license.isValid())
|
||||
{
|
||||
return LICENSE_VALID;
|
||||
}
|
||||
|
||||
return LICENSE_INVALID;
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
#ifndef LICENSE_CHECKER_H
|
||||
#define LICENSE_CHECKER_H
|
||||
|
||||
#include "MessageEnteredLicense.h"
|
||||
|
||||
class License;
|
||||
|
||||
class LicenseChecker
|
||||
{
|
||||
public:
|
||||
enum LicenseState
|
||||
{
|
||||
LICENSE_EMPTY,
|
||||
LICENSE_MOVED,
|
||||
LICENSE_MALFORMED,
|
||||
LICENSE_INVALID,
|
||||
LICENSE_EXPIRED,
|
||||
LICENSE_VALID
|
||||
};
|
||||
|
||||
static std::string getCurrentLicenseString();
|
||||
static void saveCurrentLicenseString(const std::string& licenseString);
|
||||
|
||||
static bool isCurrentLicenseValid();
|
||||
static LicenseState checkCurrentLicense();
|
||||
static LicenseState checkLicenseString(const std::string& licenseString);
|
||||
|
||||
static MessageEnteredLicense::LicenseType getCurrentLicenseType();
|
||||
static MessageEnteredLicense::LicenseType getLicenseType(const std::string& licenseString);
|
||||
|
||||
static std::string getCurrentLicenseTypeString();
|
||||
|
||||
private:
|
||||
static LicenseState checkLicense(License& license);
|
||||
};
|
||||
|
||||
#endif // LICENSE_CHECKER_H
|
||||
@@ -32,11 +32,12 @@ public:
|
||||
|
||||
virtual void refreshView() = 0;
|
||||
|
||||
virtual void loadWindow(bool showStartWindow) = 0;
|
||||
virtual void loadWindow(bool showStartWindow, bool showEULA, bool enterLicense, std::string licenseError) = 0;
|
||||
|
||||
virtual void hideStartScreen() = 0;
|
||||
virtual void setTitle(const std::wstring& title) = 0;
|
||||
virtual void activateWindow() = 0;
|
||||
virtual void forceEnterLicense(std::string licenseError) = 0;
|
||||
|
||||
virtual void updateRecentProjectMenu() = 0;
|
||||
|
||||
|
||||
@@ -53,20 +53,6 @@ bool ApplicationSettings::load(const FilePath& filePath, bool readOnly)
|
||||
"network/coati_port",
|
||||
"network/sourcetrail_port"
|
||||
));
|
||||
migrator.addMigration(3, std::make_shared<SettingsMigrationLambda>(
|
||||
[](const SettingsMigration* migration, Settings* settings)
|
||||
{
|
||||
License license;
|
||||
bool isLoaded = license.loadFromEncodedString(
|
||||
migration->getValueFromSettings<std::string>(settings, "user/license/license", ""), AppPath::getAppPath().str());
|
||||
if (isLoaded && license.isValid() && license.isNonCommercialLicenseType())
|
||||
{
|
||||
migration->removeValuesInSettings(settings, "user/license/license");
|
||||
migration->removeValuesInSettings(settings, "user/license/check");
|
||||
migration->setValueInSettings(settings, "user/license/non_commercial_use", true);
|
||||
}
|
||||
}
|
||||
));
|
||||
migrator.addMigration(4, std::make_shared<SettingsMigrationLambda>(
|
||||
[](const SettingsMigration* migration, Settings* settings)
|
||||
{
|
||||
@@ -680,16 +666,6 @@ void ApplicationSettings::setLicenseString(const std::string& licenseString)
|
||||
setValue<std::string>("user/license/license", licenseString);
|
||||
}
|
||||
|
||||
std::string ApplicationSettings::getLicenseCheck() const
|
||||
{
|
||||
return getValue<std::string>("user/license/check", "");
|
||||
}
|
||||
|
||||
void ApplicationSettings::setLicenseCheck(const std::string& hash)
|
||||
{
|
||||
setValue<std::string>("user/license/check", hash);
|
||||
}
|
||||
|
||||
bool ApplicationSettings::getNonCommercialUse() const
|
||||
{
|
||||
return getValue<bool>("user/license/non_commercial_use", false);
|
||||
|
||||
@@ -191,9 +191,6 @@ public:
|
||||
std::string getLicenseString() const;
|
||||
void setLicenseString(const std::string& licenseString);
|
||||
|
||||
std::string getLicenseCheck() const;
|
||||
void setLicenseCheck(const std::string& hash);
|
||||
|
||||
bool getNonCommercialUse() const;
|
||||
void setNonCommercialUse(bool nonCommercialUse);
|
||||
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
#ifndef MESSAGE_ENTERED_LICENSE_H
|
||||
#define MESSAGE_ENTERED_LICENSE_H
|
||||
|
||||
#include "Message.h"
|
||||
|
||||
class MessageEnteredLicense
|
||||
: public Message<MessageEnteredLicense>
|
||||
{
|
||||
public:
|
||||
enum LicenseType
|
||||
{
|
||||
LICENSE_NONE,
|
||||
LICENSE_TEST,
|
||||
LICENSE_NON_COMMERCIAL,
|
||||
LICENSE_COMMERCIAL
|
||||
};
|
||||
|
||||
MessageEnteredLicense(LicenseType type)
|
||||
: type(type)
|
||||
{
|
||||
setSendAsTask(false);
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
{
|
||||
return "MessageEnteredLicense";
|
||||
}
|
||||
|
||||
const LicenseType type;
|
||||
};
|
||||
|
||||
#endif // MESSAGE_ENTERED_LICENSE_H
|
||||
@@ -1,25 +0,0 @@
|
||||
#ifndef MESSAGE_FORCE_ENTER_LICENSE_H
|
||||
#define MESSAGE_FORCE_ENTER_LICENSE_H
|
||||
|
||||
#include "LicenseChecker.h"
|
||||
#include "Message.h"
|
||||
|
||||
class MessageForceEnterLicense
|
||||
: public Message<MessageForceEnterLicense>
|
||||
{
|
||||
public:
|
||||
MessageForceEnterLicense(LicenseChecker::LicenseState state)
|
||||
: state(state)
|
||||
{
|
||||
setSendAsTask(false);
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
{
|
||||
return "MessageForceEnterLicense";
|
||||
}
|
||||
|
||||
const LicenseChecker::LicenseState state;
|
||||
};
|
||||
|
||||
#endif // MESSAGE_FORCE_ENTER_LICENSE_H
|
||||
@@ -98,12 +98,12 @@ void QtMainView::saveLayout()
|
||||
m_window->saveLayout();
|
||||
}
|
||||
|
||||
void QtMainView::loadWindow(bool showStartWindow)
|
||||
void QtMainView::loadWindow(bool showStartWindow, bool showEULA, bool enterLicense, std::string licenseError)
|
||||
{
|
||||
m_onQtThread(
|
||||
[=]()
|
||||
{
|
||||
m_window->loadWindow(showStartWindow);
|
||||
m_window->loadWindow(showStartWindow, showEULA, enterLicense, licenseError);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -163,6 +163,16 @@ void QtMainView::activateWindow()
|
||||
);
|
||||
}
|
||||
|
||||
void QtMainView::forceEnterLicense(std::string licenseError)
|
||||
{
|
||||
m_onQtThread(
|
||||
[=]()
|
||||
{
|
||||
m_window->forceEnterLicense(licenseError);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void QtMainView::updateRecentProjectMenu()
|
||||
{
|
||||
m_onQtThread(
|
||||
@@ -208,18 +218,6 @@ void QtMainView::clearBookmarksMenu()
|
||||
updateBookmarksMenu({});
|
||||
}
|
||||
|
||||
void QtMainView::handleMessage(MessageForceEnterLicense* message)
|
||||
{
|
||||
LicenseChecker::LicenseState state = message->state;
|
||||
|
||||
m_onQtThread(
|
||||
[=]()
|
||||
{
|
||||
m_window->forceEnterLicense(state);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
void QtMainView::handleMessage(MessageProjectEdit* message)
|
||||
{
|
||||
m_onQtThread(
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "QtThreadedFunctor.h"
|
||||
|
||||
#include "MessageListener.h"
|
||||
#include "MessageForceEnterLicense.h"
|
||||
#include "MessageProjectEdit.h"
|
||||
#include "MessageProjectNew.h"
|
||||
|
||||
@@ -19,7 +18,6 @@ class View;
|
||||
|
||||
class QtMainView
|
||||
: public MainView
|
||||
, public MessageListener<MessageForceEnterLicense>
|
||||
, public MessageListener<MessageProjectEdit>
|
||||
, public MessageListener<MessageProjectNew>
|
||||
{
|
||||
@@ -50,13 +48,14 @@ public:
|
||||
void loadLayout() override;
|
||||
void saveLayout() override;
|
||||
|
||||
void loadWindow(bool showStartWindow) override;
|
||||
void loadWindow(bool showStartWindow, bool showEULA, bool enterLicense, std::string licenseError) override;
|
||||
|
||||
void refreshView() override;
|
||||
|
||||
void hideStartScreen() override;
|
||||
void setTitle(const std::wstring& title) override;
|
||||
void activateWindow() override;
|
||||
void forceEnterLicense(std::string licenseError) override;
|
||||
|
||||
void updateRecentProjectMenu() override;
|
||||
|
||||
@@ -67,7 +66,6 @@ public:
|
||||
void clearBookmarksMenu() override;
|
||||
|
||||
private:
|
||||
void handleMessage(MessageForceEnterLicense* message) override;
|
||||
void handleMessage(MessageProjectEdit* message) override;
|
||||
void handleMessage(MessageProjectNew* message) override;
|
||||
|
||||
|
||||
@@ -7,9 +7,8 @@ class QtEulaWindow
|
||||
: public QtWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static const int EULA_VERSION = 5;
|
||||
|
||||
public:
|
||||
QtEulaWindow(QWidget* parent, bool forceAccept);
|
||||
QSize sizeHint() const override;
|
||||
|
||||
|
||||
@@ -85,9 +85,11 @@ void QtLicenseWindow::populateWindow(QWidget* widget)
|
||||
m_licenseText->setPlaceholderText(
|
||||
"-----BEGIN LICENSE-----\n"
|
||||
"Product: Sourcetrail\n"
|
||||
"Licensed to:\n"
|
||||
"License holder:\n"
|
||||
"License type:\n"
|
||||
"Valid up to version:\n"
|
||||
"Licensed number of users:\n"
|
||||
"Licensed product version:\n"
|
||||
"Licensed usage period:\n"
|
||||
"-\n"
|
||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
|
||||
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
|
||||
@@ -152,45 +154,22 @@ void QtLicenseWindow::handleNext()
|
||||
if (m_commercialUse->isChecked())
|
||||
{
|
||||
std::string licenseString = m_licenseText->toPlainText().toStdString();
|
||||
|
||||
LicenseChecker::LicenseState state = LicenseChecker::checkLicenseString(licenseString);
|
||||
|
||||
std::string errorString;
|
||||
std::string errorString = LicenseChecker::getLicenseErrorForState(state);
|
||||
|
||||
switch (state)
|
||||
if (state == LicenseChecker::LicenseState::VALID)
|
||||
{
|
||||
case LicenseChecker::LICENSE_EMPTY:
|
||||
errorString = "No license key was entered.";
|
||||
break;
|
||||
case LicenseChecker::LICENSE_MOVED:
|
||||
case LicenseChecker::LICENSE_MALFORMED:
|
||||
errorString = "The entered license key is malformed.";
|
||||
break;
|
||||
case LicenseChecker::LICENSE_INVALID:
|
||||
errorString = "The entered license key is invalid.";
|
||||
break;
|
||||
case LicenseChecker::LICENSE_EXPIRED:
|
||||
errorString = "The entered license key is expired.";
|
||||
break;
|
||||
case LicenseChecker::LICENSE_VALID:
|
||||
{
|
||||
if (LicenseChecker::getLicenseType(licenseString) == MessageEnteredLicense::LICENSE_NON_COMMERCIAL)
|
||||
{
|
||||
errorString =
|
||||
"The entered license key does not permit commercial use. You no longer need a license "
|
||||
"key for non-commercial use. Please choose the non-commercial option below.";
|
||||
break;
|
||||
}
|
||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||
|
||||
LicenseChecker::saveCurrentLicenseString(licenseString);
|
||||
m_errorLabel->setText(" ");
|
||||
LicenseChecker::setCurrentLicenseString(licenseString);
|
||||
|
||||
ApplicationSettings::getInstance()->setNonCommercialUse(false);
|
||||
ApplicationSettings::getInstance()->save();
|
||||
appSettings->setLicenseString(LicenseChecker::getCurrentLicenseStringEncoded());
|
||||
appSettings->setNonCommercialUse(false);
|
||||
appSettings->save();
|
||||
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
m_errorLabel->setText(errorString.c_str());
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "QtStartScreen.h"
|
||||
#include "ApplicationSettings.h"
|
||||
#include "FileSystem.h"
|
||||
#include "LicenseChecker.h"
|
||||
#include "logging.h"
|
||||
#include "MessageErrorsHelpMessage.h"
|
||||
#include "MessageHistoryRedo.h"
|
||||
@@ -39,7 +40,6 @@
|
||||
#include "MessageBookmarkBrowse.h"
|
||||
#include "MessageBookmarkCreate.h"
|
||||
#include "MessageCodeReference.h"
|
||||
#include "MessageEnteredLicense.h"
|
||||
#include "MessageFind.h"
|
||||
#include "MessageIndexingShowDialog.h"
|
||||
#include "MessageLoadProject.h"
|
||||
@@ -116,8 +116,7 @@ bool MouseReleaseFilter::eventFilter(QObject* obj, QEvent* event)
|
||||
|
||||
|
||||
QtMainWindow::QtMainWindow()
|
||||
: m_loaded(false)
|
||||
, m_historyMenu(nullptr)
|
||||
: m_historyMenu(nullptr)
|
||||
, m_bookmarksMenu(nullptr)
|
||||
, m_showDockWidgetTitleBars(true)
|
||||
, m_windowStack(this)
|
||||
@@ -324,46 +323,20 @@ void QtMainWindow::loadDockWidgetLayout()
|
||||
}
|
||||
}
|
||||
|
||||
void QtMainWindow::loadWindow(bool showStartWindow)
|
||||
void QtMainWindow::loadWindow(bool showStartWindow, bool showEULA, bool enterLicense, const std::string& licenseError)
|
||||
{
|
||||
if (m_loaded)
|
||||
{
|
||||
if (!showStartWindow)
|
||||
{
|
||||
hideStartScreen();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
m_loaded = true;
|
||||
|
||||
LicenseChecker::LicenseState state = LicenseChecker::checkCurrentLicense();
|
||||
bool licenseValid = (state == LicenseChecker::LICENSE_VALID);
|
||||
|
||||
if (licenseValid)
|
||||
{
|
||||
MessageEnteredLicense(LicenseChecker::getCurrentLicenseType()).dispatch();
|
||||
}
|
||||
|
||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||
|
||||
if (state == LicenseChecker::LICENSE_MOVED)
|
||||
{
|
||||
appSettings->setLicenseString("");
|
||||
}
|
||||
|
||||
if (showStartWindow)
|
||||
{
|
||||
showStartScreen();
|
||||
}
|
||||
|
||||
if (state != LicenseChecker::LICENSE_VALID && !appSettings->getNonCommercialUse())
|
||||
if (enterLicense)
|
||||
{
|
||||
forceEnterLicense(state);
|
||||
forceEnterLicense(licenseError);
|
||||
}
|
||||
|
||||
#ifndef Q_OS_WIN
|
||||
if (appSettings->getAcceptedEulaVersion() < QtEulaWindow::EULA_VERSION)
|
||||
if (showEULA)
|
||||
{
|
||||
showEula(true);
|
||||
}
|
||||
@@ -387,7 +360,7 @@ void QtMainWindow::saveLayout()
|
||||
settings.setValue("DOCK_LOCATIONS", this->saveState());
|
||||
}
|
||||
|
||||
void QtMainWindow::forceEnterLicense(LicenseChecker::LicenseState state)
|
||||
void QtMainWindow::forceEnterLicense(const std::string& licenseError)
|
||||
{
|
||||
QtLicenseWindow* window = dynamic_cast<QtLicenseWindow*>(m_windowStack.getTopWindow());
|
||||
if (window)
|
||||
@@ -404,14 +377,9 @@ void QtMainWindow::forceEnterLicense(LicenseChecker::LicenseState state)
|
||||
return;
|
||||
}
|
||||
|
||||
if (state == LicenseChecker::LICENSE_EXPIRED)
|
||||
if (licenseError.size())
|
||||
{
|
||||
window->setErrorMessage("The license key is expired.");
|
||||
}
|
||||
else if (state != LicenseChecker::LICENSE_VALID && state != LicenseChecker::LICENSE_EMPTY)
|
||||
{
|
||||
window->clear();
|
||||
window->setErrorMessage("Please re-enter your license key.");
|
||||
window->setErrorMessage(QString::fromStdString(licenseError));
|
||||
}
|
||||
|
||||
window->updateCloseButton("Quit");
|
||||
@@ -620,7 +588,7 @@ void QtMainWindow::showEula(bool forceAccept)
|
||||
|
||||
void QtMainWindow::acceptedEula()
|
||||
{
|
||||
ApplicationSettings::getInstance()->setAcceptedEulaVersion(QtEulaWindow::EULA_VERSION);
|
||||
ApplicationSettings::getInstance()->setAcceptedEulaVersion(Application::EULA_VERSION);
|
||||
ApplicationSettings::getInstance()->save();
|
||||
|
||||
setEnabled(true);
|
||||
@@ -654,7 +622,7 @@ void QtMainWindow::enteredLicense()
|
||||
|
||||
m_windowStack.clearWindows();
|
||||
|
||||
MessageEnteredLicense(LicenseChecker::getCurrentLicenseType()).dispatch();
|
||||
MessageRefreshUI().dispatch();
|
||||
|
||||
setEnabled(true);
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "SearchMatch.h"
|
||||
#include "LicenseChecker.h"
|
||||
#include "QtWindowsTaskbarButton.h"
|
||||
#include "QtWindowStack.h"
|
||||
|
||||
class Bookmark;
|
||||
class MessageBase;
|
||||
class QDockWidget;
|
||||
class View;
|
||||
|
||||
@@ -73,9 +73,9 @@ public:
|
||||
void saveLayout();
|
||||
|
||||
void loadDockWidgetLayout();
|
||||
void loadWindow(bool showStartWindow);
|
||||
void loadWindow(bool showStartWindow, bool showEULA, bool enterLicense, const std::string& licenseError);
|
||||
|
||||
void forceEnterLicense(LicenseChecker::LicenseState state);
|
||||
void forceEnterLicense(const std::string& licenseError);
|
||||
|
||||
void updateHistoryMenu(std::shared_ptr<MessageBase> message);
|
||||
void clearHistoryMenu();
|
||||
@@ -190,8 +190,6 @@ private:
|
||||
|
||||
std::vector<DockWidget> m_dockWidgets;
|
||||
|
||||
bool m_loaded;
|
||||
|
||||
QMenu* m_viewMenu;
|
||||
QAction* m_viewSeparator;
|
||||
|
||||
|
||||
@@ -8,11 +8,9 @@
|
||||
#include <QMessageBox>
|
||||
|
||||
#include "ApplicationSettings.h"
|
||||
#include "AppPath.h"
|
||||
#include "License.h"
|
||||
#include "LicenseChecker.h"
|
||||
#include "MessageLoadProject.h"
|
||||
#include "ProjectSettings.h"
|
||||
#include "PublicKey.h"
|
||||
#include "QtUpdateCheckerWidget.h"
|
||||
#include "QtNewsWidget.h"
|
||||
#include "ResourcePaths.h"
|
||||
@@ -146,9 +144,6 @@ void QtStartScreen::updateButtons()
|
||||
|
||||
void QtStartScreen::setupStartScreen()
|
||||
{
|
||||
License license;
|
||||
license.loadFromEncodedString(ApplicationSettings::getInstance()->getLicenseString(), AppPath::getAppPath().str());
|
||||
|
||||
setStyleSheet(utility::getStyleSheet(ResourcePaths::getGuiPath().concatenate(L"startscreen/startscreen.css")).c_str());
|
||||
addLogo();
|
||||
|
||||
@@ -170,15 +165,15 @@ void QtStartScreen::setupStartScreen()
|
||||
|
||||
col->addSpacing(15);
|
||||
|
||||
if (license.isValid())
|
||||
if (LicenseChecker::checkCurrentLicense() == LicenseChecker::LicenseState::VALID)
|
||||
{
|
||||
std::string licenseString = license.getLicenseInfo();
|
||||
std::string licenseInfo = LicenseChecker::getCurrentLicense()->getLicenseInfo();
|
||||
|
||||
QLabel* licenseHeader = new QLabel("Licensed to:");
|
||||
licenseHeader->setObjectName("boldLabel");
|
||||
col->addWidget(licenseHeader);
|
||||
col->addSpacing(2);
|
||||
QLabel* licenseLabel = new QLabel(licenseString.c_str());
|
||||
QLabel* licenseLabel = new QLabel(licenseInfo.c_str());
|
||||
licenseLabel->setObjectName("textLabel");
|
||||
col->addWidget(licenseLabel);
|
||||
}
|
||||
|
||||
@@ -224,32 +224,3 @@ std::string utility::getOsTypeString()
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
bool utility::saveLicense(const License* license)
|
||||
{
|
||||
if (license == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (license->isValid())
|
||||
{
|
||||
ApplicationSettings* appSettings = ApplicationSettings::getInstance().get();
|
||||
if (appSettings == nullptr)
|
||||
{
|
||||
LOG_ERROR_STREAM(<< "Unable to retrieve app settings");
|
||||
return false;
|
||||
}
|
||||
|
||||
const FilePath appLocation = AppPath::getAppPath();
|
||||
appSettings->setLicenseString(license->getLicenseEncodedString(appLocation.str()));
|
||||
appSettings->setLicenseCheck(license->hashLocation(appLocation.getAbsolute().str()));
|
||||
appSettings->save();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_ERROR( "The entered license key is invalid.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,8 +28,6 @@ namespace utility
|
||||
|
||||
OsType getOsType();
|
||||
std::string getOsTypeString();
|
||||
|
||||
bool saveLicense(const License* license);
|
||||
}
|
||||
|
||||
#endif // UTILITY_APP_H
|
||||
|
||||
@@ -6,4 +6,7 @@ add_files(
|
||||
|
||||
License.cpp
|
||||
License.h
|
||||
LicenseChecker.cpp
|
||||
LicenseChecker.h
|
||||
LicenseType.h
|
||||
)
|
||||
|
||||
+377
-468
@@ -1,28 +1,18 @@
|
||||
#include "License.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <istream>
|
||||
#include <sstream>
|
||||
|
||||
//#include <botan_all.h>
|
||||
#include <boost/date_time.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <botan/rsa.h>
|
||||
#include <botan/cryptobox.h>
|
||||
#include <botan/passhash9.h>
|
||||
#include <botan/base64.h>
|
||||
#include <botan/pubkey.h>
|
||||
#include <botan/pk_keys.h>
|
||||
// #include <botan_all.h>
|
||||
#include <botan/auto_rng.h>
|
||||
#include <botan/pbkdf.h>
|
||||
#include <botan/passhash9.h>
|
||||
|
||||
#include "Version.h"
|
||||
#include "PublicKey.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
@@ -41,96 +31,7 @@ std::string toLowerCase(const std::string& in)
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
License::License()
|
||||
: m_rng(std::make_shared<Botan::AutoSeeded_RNG>())
|
||||
, m_user("")
|
||||
, m_type("Private License")
|
||||
, m_numberOfUsers(0)
|
||||
, m_createdWithSeats(false)
|
||||
, m_expire("")
|
||||
{
|
||||
loadPublicKey();
|
||||
}
|
||||
|
||||
License::~License()
|
||||
{
|
||||
}
|
||||
|
||||
void License::createHeader(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
const std::string& expiration,
|
||||
bool expiresAtDate,
|
||||
size_t numberOfUsers
|
||||
)
|
||||
{
|
||||
if (user.empty() || type.empty() || expiration.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
m_user = user;
|
||||
m_expire = expiration;
|
||||
m_expiresAtDate = expiresAtDate;
|
||||
m_type = type;
|
||||
m_numberOfUsers = numberOfUsers;
|
||||
}
|
||||
|
||||
std::string License::getMessage(bool withNewlines) const
|
||||
{
|
||||
const std::string separator = (withNewlines ? "\n" : "");
|
||||
std::string message = "";
|
||||
|
||||
if ( m_user.empty() || m_type.empty() || m_expire.empty() || m_hashLine.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
message += LicenseConstants::PRODUCT_STRING + separator;
|
||||
message += LicenseConstants::LICENSED_TO_STRING + m_user + separator;
|
||||
message += LicenseConstants::LICENSE_TYPE_STRING + m_type;
|
||||
|
||||
if (m_numberOfUsers == 0)
|
||||
{
|
||||
message += (m_createdWithSeats ? " (unlimited seats)" : " (unlimited users)");
|
||||
}
|
||||
else if (m_numberOfUsers == 1)
|
||||
{
|
||||
message += (m_createdWithSeats ? " (1 Seat)" : " (1 user)");
|
||||
}
|
||||
else if (m_numberOfUsers > 1)
|
||||
{
|
||||
message += " (" + std::to_string(m_numberOfUsers) + (m_createdWithSeats ? " Seats)" : " users)");
|
||||
}
|
||||
|
||||
message += separator;
|
||||
message += getExpireLine() + separator;
|
||||
message += LicenseConstants::SEPARATOR_STRING + separator;
|
||||
message += m_hashLine;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
std::string License::getLine(std::istream& stream)
|
||||
{
|
||||
std::string line;
|
||||
if(getline(stream, line, '\n'))
|
||||
{
|
||||
return trim(line);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void License::setHashLine(const std::string &hash)
|
||||
{
|
||||
if (!hash.empty())
|
||||
{
|
||||
m_hashLine = hash;
|
||||
}
|
||||
}
|
||||
|
||||
std::string License::removeCaption(const std::string& line, const std::string& caption) const
|
||||
std::string removeCaption(const std::string& line, const std::string& caption)
|
||||
{
|
||||
if (line.substr(0, caption.length()) == caption)
|
||||
{
|
||||
@@ -139,50 +40,20 @@ std::string License::removeCaption(const std::string& line, const std::string& c
|
||||
return "";
|
||||
}
|
||||
|
||||
bool License::extractData(const std::string& data, LICENSE_LINE line)
|
||||
{
|
||||
switch ( line )
|
||||
{
|
||||
case USER_LINE:
|
||||
m_user = removeCaption(data, LicenseConstants::LICENSED_TO_STRING);
|
||||
return !m_user.empty();
|
||||
case EXPIRE_LINE:
|
||||
m_expire = removeCaption(data, LicenseConstants::VALID_UP_TO_STRING);
|
||||
m_expiresAtDate = false;
|
||||
if (m_expire.empty())
|
||||
{
|
||||
m_expire = removeCaption(data, LicenseConstants::VALID_UNTIL_STRING);
|
||||
m_expiresAtDate = true;
|
||||
}
|
||||
return !m_expire.empty();
|
||||
case TYPE_LINE:
|
||||
setTypeAndNumberOfUsers(removeCaption(data, LicenseConstants::LICENSE_TYPE_STRING));
|
||||
return !m_type.empty();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool License::isTestLicense() const
|
||||
License::License()
|
||||
: m_rng(std::make_unique<Botan::AutoSeeded_RNG>())
|
||||
{
|
||||
return m_type == LicenseConstants::TEST_LICENSE_STRING;
|
||||
}
|
||||
|
||||
bool License::isNonCommercialLicenseType() const
|
||||
License::~License()
|
||||
{
|
||||
for ( const std::string& nonCommercialLicenseType : NON_COMMERCIAL_LICENSE_TYPES)
|
||||
{
|
||||
if (m_type == nonCommercialLicenseType)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t License::getNumberOfUsers() const
|
||||
std::string License::getUser() const
|
||||
{
|
||||
return m_numberOfUsers;
|
||||
return m_user;
|
||||
}
|
||||
|
||||
std::string License::getType() const
|
||||
@@ -190,18 +61,9 @@ std::string License::getType() const
|
||||
return m_type;
|
||||
}
|
||||
|
||||
std::string License::getExpireLine() const
|
||||
size_t License::getNumberOfUsers() const
|
||||
{
|
||||
return (m_expiresAtDate ?
|
||||
LicenseConstants::VALID_UNTIL_STRING :
|
||||
LicenseConstants::VALID_UP_TO_STRING) + m_expire;
|
||||
}
|
||||
|
||||
std::string License::getExpireLineUI() const
|
||||
{
|
||||
return toLowerCase(m_expiresAtDate ?
|
||||
LicenseConstants::VALID_UNTIL_STRING :
|
||||
LicenseConstants::VALID_UP_TO_STRING) + m_expire;
|
||||
return m_numberOfUsers;
|
||||
}
|
||||
|
||||
std::string License::getLicenseInfo() const
|
||||
@@ -211,11 +73,7 @@ std::string License::getLicenseInfo() const
|
||||
info += m_type + "\n";
|
||||
|
||||
// get info depending on license type
|
||||
if (isNonCommercialLicenseType())
|
||||
{
|
||||
info += "not registered for commercial development\n";
|
||||
}
|
||||
else if (m_numberOfUsers == 0)
|
||||
if (m_numberOfUsers == 0)
|
||||
{
|
||||
info += "unlimited users\n";
|
||||
}
|
||||
@@ -228,21 +86,135 @@ std::string License::getLicenseInfo() const
|
||||
info += "1 user\n";
|
||||
}
|
||||
|
||||
info += getExpireLineUI();
|
||||
if (m_expirationVersion != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
info += "valid up to version " + m_expirationVersion;
|
||||
}
|
||||
else if (m_expirationDate != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
info += "valid until " + m_expirationDate;
|
||||
}
|
||||
else
|
||||
{
|
||||
info += "valid perpetually";
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
std::string License::getUser() const
|
||||
std::string License::getMessage(bool withNewlines) const
|
||||
{
|
||||
return m_user;
|
||||
if (m_user.empty() || m_type.empty() || m_expirationVersion.empty() || m_expirationDate.empty() || m_hashLine.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
const std::string separator = (withNewlines ? "\n" : "");
|
||||
std::string message = LicenseConstants::PRODUCT + separator;
|
||||
|
||||
if (m_isOldFormat)
|
||||
{
|
||||
message += LicenseConstants::LICENSED_TO_OLD + m_user + separator;
|
||||
message += LicenseConstants::LICENSE_TYPE + m_type;
|
||||
|
||||
if (m_numberOfUsers == 0)
|
||||
{
|
||||
message += (m_createdWithSeats ? " (unlimited seats)" : " (unlimited users)");
|
||||
}
|
||||
else if (m_numberOfUsers == 1)
|
||||
{
|
||||
message += (m_createdWithSeats ? " (1 Seat)" : " (1 user)");
|
||||
}
|
||||
else if (m_numberOfUsers > 1)
|
||||
{
|
||||
message += " (" + std::to_string(m_numberOfUsers) + (m_createdWithSeats ? " Seats)" : " users)");
|
||||
}
|
||||
message += separator;
|
||||
|
||||
if (m_expirationVersion != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
message += LicenseConstants::VALID_UP_TO_OLD + m_expirationVersion + separator;
|
||||
}
|
||||
else if (m_expirationDate != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
message += LicenseConstants::VALID_UNTIL_OLD + m_expirationDate + separator;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string s;
|
||||
message += LicenseConstants::LICENSE_HOLDER + m_user + separator;
|
||||
message += LicenseConstants::LICENSE_TYPE + m_type + separator;
|
||||
|
||||
if (m_numberOfUsers > 0)
|
||||
{
|
||||
message += LicenseConstants::LICENSED_USERS + std::to_string(m_numberOfUsers) + separator;
|
||||
}
|
||||
else
|
||||
{
|
||||
message += s + LicenseConstants::LICENSED_USERS + LicenseConstants::VALID_UNLIMITED + separator;
|
||||
}
|
||||
|
||||
if (m_expirationVersion != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
message += s + LicenseConstants::LICENSED_VERSION + LicenseConstants::VALID_UP_TO + m_expirationVersion + separator;
|
||||
}
|
||||
else
|
||||
{
|
||||
message += s + LicenseConstants::LICENSED_VERSION + LicenseConstants::VALID_UNLIMITED + separator;
|
||||
}
|
||||
|
||||
if (m_expirationDate != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
message += s + LicenseConstants::LICENSED_PERIOD + LicenseConstants::VALID_UNTIL + m_expirationDate + separator;
|
||||
}
|
||||
else
|
||||
{
|
||||
message += s + LicenseConstants::LICENSED_PERIOD + LicenseConstants::VALID_UNLIMITED + separator;
|
||||
}
|
||||
}
|
||||
|
||||
message += LicenseConstants::SEPARATOR + separator;
|
||||
message += m_hashLine;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void License::setMessage(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers,
|
||||
const std::string& expirationVersion,
|
||||
const std::string& expirationDate
|
||||
){
|
||||
if (user.empty() || type.empty() || (numberOfUsers == 0 && expirationVersion.empty() && expirationDate.empty()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_user = user;
|
||||
m_type = type;
|
||||
m_numberOfUsers = numberOfUsers;
|
||||
m_expirationVersion = expirationVersion.size() ? expirationVersion : LicenseConstants::VALID_UNLIMITED;
|
||||
m_expirationDate = expirationDate.size() ? expirationDate : LicenseConstants::VALID_UNLIMITED;
|
||||
m_hashLine = generateHash(user + type);
|
||||
}
|
||||
|
||||
const std::string& License::getSignature() const
|
||||
{
|
||||
return m_signature;
|
||||
}
|
||||
|
||||
void License::setSignature(const std::string& signature)
|
||||
{
|
||||
m_signature = signature;
|
||||
}
|
||||
|
||||
int License::getTimeLeft() const
|
||||
{
|
||||
const std::string dateText = "YYYY-MMM-DD";
|
||||
|
||||
std::string dateString = m_expire;
|
||||
std::string dateString = m_expirationDate;
|
||||
if (dateString.length() != dateText.length())
|
||||
{
|
||||
return -2;
|
||||
@@ -269,100 +241,6 @@ bool License::loadFromString(const std::string& licenseText)
|
||||
return load(license);
|
||||
}
|
||||
|
||||
bool License::load(std::istream& stream)
|
||||
{
|
||||
std::string line;
|
||||
std::array<std::string, LICENSE_LINES> lines;
|
||||
|
||||
line = getLine(stream);
|
||||
if (line == LicenseConstants::BEGIN_LICENSE_STRING)
|
||||
{
|
||||
line = getLine(stream);
|
||||
}
|
||||
|
||||
// sourcetrail line
|
||||
if (line != LicenseConstants::PRODUCT_STRING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// user line
|
||||
if (!extractData(getLine(stream), USER_LINE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!extractData(getLine(stream), TYPE_LINE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// expire line
|
||||
if (!extractData(getLine(stream), EXPIRE_LINE))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// separator line
|
||||
getline(stream, line, '\n');
|
||||
if (trim(line) != LicenseConstants::SEPARATOR_STRING)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// hash line
|
||||
m_hashLine = getLine(stream);
|
||||
|
||||
// signature
|
||||
m_signature = "";
|
||||
while (getline(stream, line, '\n'))
|
||||
{
|
||||
std::string l = trim(line);
|
||||
if (l == LicenseConstants::END_LICENSE_STRING)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if (l.size())
|
||||
{
|
||||
m_signature += l;
|
||||
}
|
||||
}
|
||||
if (m_signature.length() != 344)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void License::setTypeAndNumberOfUsers(const std::string& line)
|
||||
{
|
||||
size_t pos = line.find("(");
|
||||
|
||||
if (pos != line.npos)
|
||||
{
|
||||
m_type = line.substr(0, pos - 1);
|
||||
try
|
||||
{
|
||||
m_numberOfUsers = std::stoi(line.substr(pos+1));
|
||||
}
|
||||
catch (std::invalid_argument e)
|
||||
{
|
||||
m_numberOfUsers = 0;
|
||||
}
|
||||
|
||||
if (toLowerCase(line).find("seat") != line.npos)
|
||||
{
|
||||
m_createdWithSeats = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = line;
|
||||
m_numberOfUsers = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool License::loadFromFile(const std::string& filename)
|
||||
{
|
||||
std::ifstream sigfile(filename);
|
||||
@@ -374,293 +252,324 @@ void License::print()
|
||||
std::cout << getLicenseString();
|
||||
}
|
||||
|
||||
bool License::isValid() const
|
||||
bool License::isEmpty() const
|
||||
{
|
||||
if (!m_publicKey)
|
||||
if (m_user.empty() && m_type.empty() &&
|
||||
m_expirationVersion.empty() && m_expirationDate.empty() &&
|
||||
m_hashLine.empty() && m_signature.empty())
|
||||
{
|
||||
std::cout << "No public key loaded" << std::endl;
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (m_signature.empty())
|
||||
{
|
||||
std::cout << "Could not read signature" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
Botan::secure_vector<Botan::byte> signature = Botan::base64_decode(m_signature);
|
||||
|
||||
if (m_publicKey == NULL)
|
||||
{
|
||||
std::cout << "Public key is NULL" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isExpired())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Botan::PK_Verifier verifier(*m_publicKey.get(), "EMSA4(SHA-256)");
|
||||
|
||||
Botan::DataSource_Memory in(getMessage());
|
||||
Botan::byte buffer[4096] = {0};
|
||||
while(size_t got = in.read(buffer, sizeof(buffer)))
|
||||
{
|
||||
verifier.update(buffer, got); // what does 'got' stand for?
|
||||
}
|
||||
|
||||
const bool ok = verifier.check_signature(signature);
|
||||
if (!ok)
|
||||
{
|
||||
std::cout << "License check failed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
catch(...) // invalid character, or something else... why not check what the exception is?
|
||||
{
|
||||
std::cout << "Invalid character in Licensekey" << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool License::isExpired() const
|
||||
{
|
||||
if (m_expiresAtDate)
|
||||
{
|
||||
return (getTimeLeft() == -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
Version version = Version::fromString(m_expire);
|
||||
return Version::getApplicationVersion().toShortVersion() > version;
|
||||
}
|
||||
}
|
||||
|
||||
std::string License::getPublicKeyFilename() const
|
||||
{
|
||||
if (m_publicKeyFilename.empty())
|
||||
{
|
||||
return "public-sourcetrail" + KEY_FILEENDING;
|
||||
}
|
||||
return m_publicKeyFilename;
|
||||
}
|
||||
|
||||
bool License::loadPublicKeyFromFile(const std::string& filename)
|
||||
{
|
||||
if (!filename.empty())
|
||||
{
|
||||
m_publicKeyFilename = filename;
|
||||
}
|
||||
|
||||
if (boost::filesystem::exists(getPublicKeyFilename()))
|
||||
{
|
||||
Botan::RSA_PublicKey* rsaPublicKey =
|
||||
dynamic_cast<Botan::RSA_PublicKey*>(Botan::X509::load_key(getPublicKeyFilename()));
|
||||
|
||||
if (!rsaPublicKey)
|
||||
{
|
||||
std::cout << "The loaded key is not a RSA key" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_publicKey = std::shared_ptr<Botan::RSA_PublicKey>(rsaPublicKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool License::loadPublicKey()
|
||||
bool License::isComplete() const
|
||||
{
|
||||
Botan::DataSource_Memory in(PUBLIC_KEY);
|
||||
Botan::RSA_PublicKey *rsaPublicKey = dynamic_cast<Botan::RSA_PublicKey *>(Botan::X509::load_key(in));
|
||||
|
||||
if (!rsaPublicKey)
|
||||
if (m_user.empty() || m_type.empty() ||
|
||||
m_expirationVersion.empty() || m_expirationDate.empty() ||
|
||||
m_hashLine.empty() || m_signature.empty())
|
||||
{
|
||||
std::cout << "The loaded key is not a RSA key" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_publicKey = std::shared_ptr<Botan::RSA_PublicKey>(rsaPublicKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool License::loadPublicKeyFromString(const std::string& publicKey)
|
||||
bool License::isExpired() const
|
||||
{
|
||||
if (publicKey.empty())
|
||||
if (m_expirationVersion != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
Version version = Version::fromString(m_expirationVersion);
|
||||
return Version::getApplicationVersion().toShortVersion() > version;
|
||||
}
|
||||
else if (m_expirationDate != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
return (getTimeLeft() == -1);
|
||||
}
|
||||
else if (m_expirationVersion == LicenseConstants::VALID_UNLIMITED &&
|
||||
m_expirationDate == LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
std::cout << "Public key is empty" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
Botan::DataSource_Memory in(publicKey);
|
||||
Botan::RSA_PublicKey *rsaPublicKey = dynamic_cast<Botan::RSA_PublicKey *>(Botan::X509::load_key(in));
|
||||
|
||||
if (!rsaPublicKey)
|
||||
{
|
||||
std::cout << "The loaded key is not a RSA key" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_publicKey = std::shared_ptr<Botan::RSA_PublicKey>(rsaPublicKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool License::isTestLicense() const
|
||||
{
|
||||
return m_type == LicenseConstants::TEST_LICENSE;
|
||||
}
|
||||
|
||||
std::string License::getLicenseString() const
|
||||
{
|
||||
if (m_user.empty() || m_type.empty() || m_expirationVersion.empty() || m_expirationDate.empty())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string signatureLines;
|
||||
std::stringstream ss;
|
||||
const int lineLength = 55;
|
||||
for (size_t i = 0; i < m_signature.size(); i++)
|
||||
{
|
||||
if (i % lineLength == 0 && i != 0)
|
||||
{
|
||||
signatureLines += ss.str() + "\n";
|
||||
ss.str("");
|
||||
}
|
||||
ss << m_signature[i];
|
||||
}
|
||||
signatureLines += ss.str();
|
||||
|
||||
std::string license = "";
|
||||
license += LicenseConstants::BEGIN_LICENSE_STRING;
|
||||
license += LicenseConstants::BEGIN_LICENSE;
|
||||
license += "\n";
|
||||
license += getMessage(true) + "\n";
|
||||
license += getSignature() + "\n";
|
||||
license += LicenseConstants::END_LICENSE_STRING;
|
||||
license += signatureLines + "\n";
|
||||
license += LicenseConstants::END_LICENSE;
|
||||
license += "\n";
|
||||
|
||||
return license;
|
||||
}
|
||||
|
||||
std::string License::hashLocation(const std::string& location) const
|
||||
std::string License::generateHash(const std::string& str) const
|
||||
{
|
||||
if (m_rng == NULL || location.size() <= 0)
|
||||
if (m_rng == NULL || str.size() <= 0)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
return Botan::generate_passhash9(location, *(m_rng.get()));
|
||||
return Botan::generate_passhash9(str, *(m_rng.get()));
|
||||
}
|
||||
|
||||
bool License::checkLocation(const std::string& location, const std::string& hash)
|
||||
bool License::checkHash(const std::string& str, const std::string& hash)
|
||||
{
|
||||
if (location.empty() || hash.empty())
|
||||
if (str.empty() || hash.empty())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return Botan::check_passhash9(location, hash);
|
||||
return Botan::check_passhash9(str, hash);
|
||||
}
|
||||
|
||||
std::string License::getLicenseEncodedString(const std::string& applicationLocation) const
|
||||
bool License::load(std::istream& stream)
|
||||
{
|
||||
if (applicationLocation.empty())
|
||||
std::string line;
|
||||
std::vector<std::string> lines;
|
||||
|
||||
while (getline(stream, line, '\n'))
|
||||
{
|
||||
std::cout << "No application location was given" << std::endl;
|
||||
return "";
|
||||
line = trim(line);
|
||||
|
||||
if ((!lines.size() && line == LicenseConstants::BEGIN_LICENSE) || line == LicenseConstants::END_LICENSE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.size())
|
||||
{
|
||||
lines.push_back(line);
|
||||
}
|
||||
}
|
||||
|
||||
Botan::AutoSeeded_RNG rng;
|
||||
std::vector<Botan::byte> fileContents;
|
||||
std::stringstream input(getLicenseString());
|
||||
|
||||
//prepare the license string to work with the botan cryptobox
|
||||
while(input.good())
|
||||
if (lines.size() == 15)
|
||||
{
|
||||
Botan::byte filebuffer[4096] = { 0 };
|
||||
input.read((char*)filebuffer, sizeof(filebuffer));
|
||||
size_t got = input.gcount(); // what does got stand for?
|
||||
|
||||
fileContents.insert(fileContents.end(), filebuffer, filebuffer + got);
|
||||
m_isOldFormat = false;
|
||||
return loadFromLines(lines);
|
||||
}
|
||||
|
||||
if(fileContents.size() <= 0)
|
||||
else if (lines.size() == 13)
|
||||
{
|
||||
std::cout << "Failed to read license string" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string result =
|
||||
Botan::CryptoBox::encrypt(&fileContents[0], fileContents.size(), getEncodeKey(applicationLocation), rng);
|
||||
|
||||
//remove Botan Cryptobox begin and end
|
||||
//should not be in the application settings
|
||||
const int leMagicNumberA = 40;
|
||||
const int leMagicNumberB = 78;
|
||||
|
||||
if (result.length() < leMagicNumberA + leMagicNumberB)
|
||||
{
|
||||
std::cout << "Invalid result" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
result = result.substr(leMagicNumberA, result.length() - leMagicNumberB);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool License::loadFromEncodedString(const std::string& encodedLicense, const std::string& applicationLocation)
|
||||
{
|
||||
if (encodedLicense.empty())
|
||||
{
|
||||
std::cout << "No license string given" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (applicationLocation.empty())
|
||||
{
|
||||
std::cout << "No application location given" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
//add cryptobox begin and end to loaded string
|
||||
std::string crypbobxInput = "-----BEGIN BOTAN CRYPTOBOX MESSAGE-----\n";
|
||||
crypbobxInput += encodedLicense;
|
||||
crypbobxInput += "-----END BOTAN CRYPTOBOX MESSAGE-----";
|
||||
|
||||
//decrypt license
|
||||
return loadFromString(Botan::CryptoBox::decrypt(crypbobxInput, getEncodeKey(applicationLocation)));
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
//loaded string from application settings is invalid
|
||||
return false;
|
||||
m_isOldFormat = true;
|
||||
return loadFromLinesOld(lines);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string License::getHashedLicense() const
|
||||
bool License::loadFromLines(const std::vector<std::string>& lines)
|
||||
{
|
||||
return getEncodeKey("fakeKey");
|
||||
}
|
||||
|
||||
std::string License::getEncodeKey(const std::string applicationLocation) const
|
||||
{
|
||||
if (applicationLocation.empty())
|
||||
if (lines.size() != 15)
|
||||
{
|
||||
std::cout << "No application location given" << std::endl;
|
||||
return "";
|
||||
return false;
|
||||
}
|
||||
|
||||
Botan::PBKDF *pbkdf = Botan::get_pbkdf("PBKDF2(SHA-256)");
|
||||
Botan::secure_vector<Botan::byte> salt = Botan::base64_decode("34zA54n60v4CxjY5n20k3J40c976n690", 32);
|
||||
Botan::AutoSeeded_RNG rng;
|
||||
return pbkdf->derive_key(32, applicationLocation, &salt[0], salt.size(), 10000).as_string();
|
||||
}
|
||||
|
||||
std::string License::getSignature() const
|
||||
{
|
||||
std::string sig;
|
||||
std::stringstream ss;
|
||||
const int lineLength = 55;
|
||||
for (size_t i = 0; i < m_signature.size(); i++)
|
||||
// sourcetrail line
|
||||
if (lines[0] != LicenseConstants::PRODUCT)
|
||||
{
|
||||
if(i % lineLength == 0 && i != 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
// user line
|
||||
m_user = removeCaption(lines[1], LicenseConstants::LICENSE_HOLDER);
|
||||
if (m_user.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// type line
|
||||
m_type = removeCaption(lines[2], LicenseConstants::LICENSE_TYPE);
|
||||
if (m_type.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// number of users
|
||||
std::string users = removeCaption(lines[3], LicenseConstants::LICENSED_USERS);
|
||||
if (users != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
try
|
||||
{
|
||||
sig += ss.str() + "\n";
|
||||
ss.str("");
|
||||
m_numberOfUsers = std::stoi(users);
|
||||
}
|
||||
ss << m_signature[i];
|
||||
catch (std::invalid_argument e)
|
||||
{
|
||||
m_numberOfUsers = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_numberOfUsers = 0;
|
||||
}
|
||||
|
||||
sig += ss.str();
|
||||
return sig;
|
||||
// expiration version
|
||||
m_expirationVersion = removeCaption(lines[4], LicenseConstants::LICENSED_VERSION);
|
||||
if (m_expirationVersion != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
m_expirationVersion = removeCaption(m_expirationVersion, LicenseConstants::VALID_UP_TO);
|
||||
if (!Version::fromString(m_expirationVersion).isValid())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// expiration date
|
||||
m_expirationDate = removeCaption(lines[5], LicenseConstants::LICENSED_PERIOD);
|
||||
if (m_expirationDate != LicenseConstants::VALID_UNLIMITED)
|
||||
{
|
||||
m_expirationDate = removeCaption(m_expirationDate, LicenseConstants::VALID_UNTIL);
|
||||
|
||||
if (m_expirationDate.size() != 11 || m_expirationDate[4] != '-' || m_expirationDate[8] != '-')
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// separator line
|
||||
if (lines[6] != LicenseConstants::SEPARATOR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// hash line
|
||||
m_hashLine = lines[7];
|
||||
if (m_hashLine.length() != 55)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// signature
|
||||
m_signature = lines[8] + lines[9] + lines[10] + lines[11] + lines[12] + lines[13] + lines[14];
|
||||
if (m_signature.length() != 344)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void License::setSignature(const std::string& signature)
|
||||
bool License::loadFromLinesOld(const std::vector<std::string>& lines)
|
||||
{
|
||||
m_signature = signature;
|
||||
if (lines.size() != 13)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// sourcetrail line
|
||||
if (lines[0] != LicenseConstants::PRODUCT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// user line
|
||||
m_user = removeCaption(lines[1], LicenseConstants::LICENSED_TO_OLD);
|
||||
if (m_user.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// type line
|
||||
{
|
||||
std::string line = removeCaption(lines[2], LicenseConstants::LICENSE_TYPE);
|
||||
size_t pos = line.find("(");
|
||||
|
||||
if (pos != line.npos)
|
||||
{
|
||||
m_type = line.substr(0, pos - 1);
|
||||
try
|
||||
{
|
||||
m_numberOfUsers = std::stoi(line.substr(pos+1));
|
||||
}
|
||||
catch (std::invalid_argument e)
|
||||
{
|
||||
m_numberOfUsers = 0;
|
||||
}
|
||||
|
||||
if (toLowerCase(line).find("seat") != line.npos)
|
||||
{
|
||||
m_createdWithSeats = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_type = line;
|
||||
m_numberOfUsers = 0;
|
||||
}
|
||||
|
||||
if (m_type.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// expire line
|
||||
m_expirationVersion = removeCaption(lines[3], LicenseConstants::VALID_UP_TO_OLD);
|
||||
m_expirationDate = removeCaption(lines[3], LicenseConstants::VALID_UNTIL_OLD);
|
||||
if (m_expirationVersion.empty() && m_expirationDate.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_expirationVersion.empty())
|
||||
{
|
||||
m_expirationVersion = LicenseConstants::VALID_UNLIMITED;
|
||||
}
|
||||
|
||||
if (m_expirationDate.empty())
|
||||
{
|
||||
m_expirationDate = LicenseConstants::VALID_UNLIMITED;
|
||||
}
|
||||
|
||||
// separator line
|
||||
if (lines[4] != LicenseConstants::SEPARATOR)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// hash line
|
||||
m_hashLine = lines[5];
|
||||
if (m_hashLine.length() != 55)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// signature
|
||||
m_signature = lines[6] + lines[7] + lines[8] + lines[9] + lines[10] + lines[11] + lines[12];
|
||||
if (m_signature.length() != 344)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
+52
-81
@@ -4,130 +4,101 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
namespace Botan
|
||||
{
|
||||
class RSA_PublicKey;
|
||||
class RSA_PrivateKey;
|
||||
class AutoSeeded_RNG;
|
||||
}
|
||||
|
||||
namespace LicenseConstants {
|
||||
const char BEGIN_LICENSE_STRING[] = "-----BEGIN LICENSE-----";
|
||||
const char END_LICENSE_STRING[] = "-----END LICENSE-----";
|
||||
const char TEST_LICENSE_STRING[] = "Test License";
|
||||
const char PRODUCT_STRING[] = "Product: Sourcetrail";
|
||||
const char LICENSED_TO_STRING[] = "Licensed to: ";
|
||||
const char LICENSE_TYPE_STRING[] = "License type: ";
|
||||
const char VALID_UNTIL_STRING[] = "Valid until: ";
|
||||
const char VALID_UP_TO_STRING[] = "Valid up to version: ";
|
||||
const char SEPARATOR_STRING[] = "-";
|
||||
const int MINOR_VERSIONS_PER_YEAR = 4;
|
||||
namespace LicenseConstants
|
||||
{
|
||||
const char BEGIN_LICENSE[] = "-----BEGIN LICENSE-----";
|
||||
const char END_LICENSE[] = "-----END LICENSE-----";
|
||||
|
||||
const char TEST_LICENSE[] = "Test License";
|
||||
|
||||
const char PRODUCT[] = "Product: Sourcetrail";
|
||||
|
||||
const char LICENSE_HOLDER[] = "License holder: ";
|
||||
const char LICENSE_TYPE[] = "License type: ";
|
||||
const char LICENSED_USERS[] = "Licensed number of users: ";
|
||||
const char LICENSED_VERSION[] = "Licensed product version: ";
|
||||
const char LICENSED_PERIOD[] = "Licensed usage period: ";
|
||||
|
||||
const char VALID_UNTIL[] = "until ";
|
||||
const char VALID_UP_TO[] = "up to ";
|
||||
const char VALID_UNLIMITED[] = "unlimited";
|
||||
|
||||
const char LICENSED_TO_OLD[] = "Licensed to: ";
|
||||
const char VALID_UNTIL_OLD[] = "Valid for: ";
|
||||
const char VALID_UP_TO_OLD[] = "Valid up to version: ";
|
||||
|
||||
const char SEPARATOR[] = "-";
|
||||
}
|
||||
|
||||
class License
|
||||
{
|
||||
public:
|
||||
enum LICENSE_LINE
|
||||
{
|
||||
BEGIN_LICENSE_LINE = 0,
|
||||
SOURCETRAIL_LINE = 1,
|
||||
USER_LINE = 2,
|
||||
TYPE_LINE = 3,
|
||||
EXPIRE_LINE = 4,
|
||||
SEPARATOR_LINE=5,
|
||||
HASH_LINE = 6,
|
||||
FIRST_SIGNATURE_LINE = 7,
|
||||
LAST_SIGNATURE_LINE = 13,
|
||||
END_LICENSE_LINE = 14,
|
||||
LICENSE_LINES = 15
|
||||
};
|
||||
|
||||
License();
|
||||
~License();
|
||||
|
||||
std::string getMessage(bool withNewlines = false) const;
|
||||
std::string getSignature() const;
|
||||
std::string getVersionLineWithoutPrefix() const;
|
||||
std::string getLine(std::istream& stream);
|
||||
std::string getLineWithoutDescription(LICENSE_LINE line) const;
|
||||
|
||||
void setLine(const LICENSE_LINE line, const std::string& value);
|
||||
void setHashLine(const std::string& hash);
|
||||
void setTypeAndNumberOfUsers(const std::string& line);
|
||||
|
||||
std::string getLicenseInfo() const;
|
||||
std::string getPublicKeyFilename() const;
|
||||
std::string getVersion() const;
|
||||
std::string getType() const;
|
||||
std::string getUser() const;
|
||||
size_t getNumberOfUsers() const;
|
||||
std::string getLicenseInfo() const;
|
||||
|
||||
void createHeader(
|
||||
std::string getMessage(bool withNewlines) const;
|
||||
void setMessage(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
const std::string& expiration,
|
||||
bool expiresAtDate,
|
||||
size_t numberOfUsers = 0
|
||||
size_t numberOfUsers,
|
||||
const std::string& expirationVersion,
|
||||
const std::string& expirationDate
|
||||
);
|
||||
std::string getExpireLine() const;
|
||||
std::string getExpireLineUI() const;
|
||||
|
||||
/// if Test License return >=0 or -1 if expired
|
||||
/// for non Test License -2
|
||||
int getTimeLeft() const;
|
||||
const std::string& getSignature() const;
|
||||
void setSignature(const std::string& signature);
|
||||
|
||||
std::string getLicenseString() const;
|
||||
std::string getLicenseEncodedString(const std::string& applicationLocation) const;
|
||||
std::string getHashedLicense() const;
|
||||
|
||||
void writeToFile(const std::string& filename);
|
||||
bool load(std::istream& stream);
|
||||
|
||||
bool loadFromString(const std::string& licenseText);
|
||||
bool loadFromFile(const std::string& filename);
|
||||
bool loadFromEncodedString(const std::string& encodedLicense, const std::string& applicationLocation);
|
||||
|
||||
bool loadPublicKey();
|
||||
|
||||
bool loadPublicKeyFromFile(const std::string&);
|
||||
bool loadPublicKeyFromString(const std::string&);
|
||||
|
||||
void setSignature(const std::string&);
|
||||
|
||||
bool isValid() const;
|
||||
bool isEmpty() const;
|
||||
bool isComplete() const;
|
||||
bool isExpired() const;
|
||||
bool isTestLicense() const;
|
||||
bool isNonCommercialLicenseType() const;
|
||||
|
||||
// if Test License return >=0 or -1 if expired
|
||||
// for non Test License -2
|
||||
int getTimeLeft() const;
|
||||
|
||||
void print();
|
||||
|
||||
std::string hashLocation(const std::string&) const;
|
||||
static bool checkLocation(const std::string&, const std::string&);
|
||||
std::string generateHash(const std::string& str) const;
|
||||
static bool checkHash(const std::string& str, const std::string& hash);
|
||||
|
||||
private:
|
||||
std::string getEncodeKey(const std::string applicationLocation) const;
|
||||
bool extractData(const std::string& data, LICENSE_LINE line);
|
||||
std::string removeCaption(const std::string& line, const std::string& caption) const;
|
||||
bool load(std::istream& stream);
|
||||
bool loadFromLines(const std::vector<std::string>& lines);
|
||||
bool loadFromLinesOld(const std::vector<std::string>& lines);
|
||||
|
||||
std::string m_publicKeyFilename;
|
||||
std::shared_ptr<Botan::RSA_PublicKey> m_publicKey;
|
||||
std::unique_ptr<Botan::AutoSeeded_RNG> m_rng;
|
||||
|
||||
std::shared_ptr<Botan::AutoSeeded_RNG> m_rng;
|
||||
// message
|
||||
std::string m_user;
|
||||
std::string m_type;
|
||||
size_t m_numberOfUsers;
|
||||
bool m_createdWithSeats;
|
||||
std::string m_expire;
|
||||
bool m_expiresAtDate;
|
||||
std::string m_hashLine;
|
||||
size_t m_numberOfUsers = 0;
|
||||
bool m_createdWithSeats = false;
|
||||
|
||||
std::string m_expirationVersion;
|
||||
std::string m_expirationDate;
|
||||
|
||||
std::string m_hashLine;
|
||||
std::string m_signature;
|
||||
|
||||
const std::string KEY_FILEENDING = ".pem";
|
||||
|
||||
const std::vector<std::string> NON_COMMERCIAL_LICENSE_TYPES = { { "Private/Academic Single User License" } };
|
||||
bool m_isOldFormat = false;
|
||||
};
|
||||
|
||||
#endif // SOURCETRAIL_LICENSE_H
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
#include "LicenseChecker.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
// #include <botan_all.h>
|
||||
#include <botan/auto_rng.h>
|
||||
#include <botan/base64.h>
|
||||
#include <botan/cryptobox.h>
|
||||
#include <botan/pbkdf.h>
|
||||
#include <botan/pk_keys.h>
|
||||
#include <botan/pubkey.h>
|
||||
#include <botan/rsa.h>
|
||||
|
||||
#include "License.h"
|
||||
#include "PublicKey.h"
|
||||
|
||||
std::string LicenseChecker::s_encodeKey;
|
||||
std::unique_ptr<Botan::RSA_PublicKey> LicenseChecker::s_publicKey;
|
||||
std::unique_ptr<License> LicenseChecker::s_currentLicense;
|
||||
|
||||
void LicenseChecker::setEncodeKey(const std::string& key)
|
||||
{
|
||||
if (key.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Botan::PBKDF *pbkdf = Botan::get_pbkdf("PBKDF2(SHA-256)");
|
||||
Botan::secure_vector<Botan::byte> salt = Botan::base64_decode("34zA54n60v4CxjY5n20k3J40c976n690", 32);
|
||||
s_encodeKey = pbkdf->derive_key(32, key, &salt[0], salt.size(), 10000).as_string();
|
||||
}
|
||||
|
||||
bool LicenseChecker::loadPublicKeyFromFile(std::string fileName)
|
||||
{
|
||||
if (!boost::filesystem::exists(fileName))
|
||||
{
|
||||
std::cout << "Public key file does not exist: " << fileName << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return createPublicKey(dynamic_cast<Botan::RSA_PublicKey*>(Botan::X509::load_key(fileName)));
|
||||
}
|
||||
|
||||
bool LicenseChecker::loadPublicKeyFromString(const std::string& publicKey)
|
||||
{
|
||||
if (publicKey.empty())
|
||||
{
|
||||
std::cout << "Public key is empty" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
Botan::DataSource_Memory in(publicKey);
|
||||
return createPublicKey(dynamic_cast<Botan::RSA_PublicKey *>(Botan::X509::load_key(in)));
|
||||
}
|
||||
|
||||
bool LicenseChecker::loadPublicKey()
|
||||
{
|
||||
return loadPublicKeyFromString(PUBLIC_KEY);
|
||||
}
|
||||
|
||||
const License* LicenseChecker::getCurrentLicense()
|
||||
{
|
||||
return s_currentLicense.get();
|
||||
}
|
||||
|
||||
std::string LicenseChecker::getCurrentLicenseString()
|
||||
{
|
||||
if (s_currentLicense)
|
||||
{
|
||||
return s_currentLicense->getLicenseString();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string LicenseChecker::getCurrentLicenseStringEncoded()
|
||||
{
|
||||
if (!s_currentLicense)
|
||||
{
|
||||
std::cout << "No current license" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
if (s_encodeKey.empty())
|
||||
{
|
||||
std::cout << "No encode key" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
Botan::AutoSeeded_RNG rng;
|
||||
std::vector<Botan::byte> fileContents;
|
||||
std::stringstream input(s_currentLicense->getLicenseString());
|
||||
|
||||
// prepare the license string to work with the botan cryptobox
|
||||
while (input.good())
|
||||
{
|
||||
Botan::byte filebuffer[4096] = { 0 };
|
||||
input.read((char*)filebuffer, sizeof(filebuffer));
|
||||
size_t got = input.gcount();
|
||||
|
||||
fileContents.insert(fileContents.end(), filebuffer, filebuffer + got);
|
||||
}
|
||||
|
||||
if (fileContents.size() <= 0)
|
||||
{
|
||||
std::cout << "Failed to read license string" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string result = Botan::CryptoBox::encrypt(&fileContents[0], fileContents.size(), s_encodeKey, rng);
|
||||
|
||||
// remove Botan Cryptobox begin and end
|
||||
// should not be in the application settings
|
||||
const int cryptoboxBeginLength = 40;
|
||||
const int cryptoboxEndLength = 38;
|
||||
|
||||
if (result.length() < cryptoboxBeginLength + cryptoboxEndLength)
|
||||
{
|
||||
std::cout << "Invalid result" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
result = result.substr(cryptoboxBeginLength, result.length() - (cryptoboxBeginLength + cryptoboxEndLength));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
LicenseChecker::LicenseState LicenseChecker::setCurrentLicenseString(const std::string& licenseStr)
|
||||
{
|
||||
s_currentLicense = nullptr;
|
||||
|
||||
if (licenseStr.empty())
|
||||
{
|
||||
return LicenseState::EMPTY;
|
||||
}
|
||||
|
||||
s_currentLicense = std::make_unique<License>();
|
||||
if (!s_currentLicense->loadFromString(licenseStr))
|
||||
{
|
||||
s_currentLicense = nullptr;
|
||||
return LicenseState::MALFORMED;
|
||||
}
|
||||
|
||||
return checkCurrentLicense();
|
||||
}
|
||||
|
||||
LicenseChecker::LicenseState LicenseChecker::setCurrentLicenseStringEncoded(const std::string& licenseStr)
|
||||
{
|
||||
s_currentLicense = nullptr;
|
||||
|
||||
if (licenseStr.empty())
|
||||
{
|
||||
return LicenseState::EMPTY;
|
||||
}
|
||||
|
||||
if (s_encodeKey.empty())
|
||||
{
|
||||
std::cout << "No key available" << std::endl;
|
||||
return LicenseState::EMPTY;
|
||||
}
|
||||
|
||||
s_currentLicense = std::make_unique<License>();
|
||||
|
||||
try
|
||||
{
|
||||
// add cryptobox begin and end to loaded string
|
||||
std::string cryptoboxInput = "-----BEGIN BOTAN CRYPTOBOX MESSAGE-----\n";
|
||||
cryptoboxInput += licenseStr;
|
||||
cryptoboxInput += "-----END BOTAN CRYPTOBOX MESSAGE-----";
|
||||
|
||||
// decrypt license
|
||||
if (!s_currentLicense->loadFromString(Botan::CryptoBox::decrypt(cryptoboxInput, s_encodeKey)))
|
||||
{
|
||||
s_currentLicense = nullptr;
|
||||
return LicenseState::MALFORMED;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
s_currentLicense = nullptr;
|
||||
return LicenseState::MALFORMED;
|
||||
}
|
||||
|
||||
return checkCurrentLicense();
|
||||
}
|
||||
|
||||
LicenseChecker::LicenseState LicenseChecker::checkLicense(const License& license)
|
||||
{
|
||||
if (license.isEmpty())
|
||||
{
|
||||
return LicenseState::EMPTY;
|
||||
}
|
||||
|
||||
if (!license.isComplete())
|
||||
{
|
||||
return LicenseState::INCOMPLETE;
|
||||
}
|
||||
|
||||
std::string message = license.getMessage(false);
|
||||
std::string signature = license.getSignature();
|
||||
if (message.empty() || signature.empty())
|
||||
{
|
||||
return LicenseState::INCOMPLETE;
|
||||
}
|
||||
|
||||
if (!s_publicKey)
|
||||
{
|
||||
std::cout << "No public key loaded" << std::endl;
|
||||
return LicenseState::INCOMPLETE;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Botan::PK_Verifier verifier(*s_publicKey.get(), "EMSA4(SHA-256)");
|
||||
Botan::DataSource_Memory in(message);
|
||||
Botan::byte buffer[4096] = { 0 };
|
||||
|
||||
while (size_t got = in.read(buffer, sizeof(buffer)))
|
||||
{
|
||||
verifier.update(buffer, got);
|
||||
}
|
||||
|
||||
Botan::secure_vector<Botan::byte> sig = Botan::base64_decode(signature);
|
||||
if (!verifier.check_signature(sig))
|
||||
{
|
||||
return LicenseState::INVALID;
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "Invalid character in Licensekey" << std::endl;
|
||||
return LicenseState::MALFORMED;
|
||||
}
|
||||
|
||||
if (license.isExpired())
|
||||
{
|
||||
return LicenseState::EXPIRED;
|
||||
}
|
||||
|
||||
return LicenseState::VALID;
|
||||
}
|
||||
|
||||
LicenseChecker::LicenseState LicenseChecker::checkLicenseString(const std::string& licenseString)
|
||||
{
|
||||
if (licenseString.size() == 0)
|
||||
{
|
||||
return LicenseState::EMPTY;
|
||||
}
|
||||
|
||||
License license;
|
||||
bool isLoaded = license.loadFromString(licenseString);
|
||||
if (!isLoaded)
|
||||
{
|
||||
return LicenseState::MALFORMED;
|
||||
}
|
||||
|
||||
return checkLicense(license);
|
||||
}
|
||||
|
||||
LicenseChecker::LicenseState LicenseChecker::checkCurrentLicense()
|
||||
{
|
||||
if (!s_currentLicense)
|
||||
{
|
||||
return LicenseState::EMPTY;
|
||||
}
|
||||
|
||||
return checkLicense(*s_currentLicense.get());
|
||||
}
|
||||
|
||||
LicenseType LicenseChecker::getCurrentLicenseType()
|
||||
{
|
||||
if (!s_currentLicense)
|
||||
{
|
||||
return LicenseType::NON_COMMERCIAL;
|
||||
}
|
||||
|
||||
LicenseState state = checkLicense(*s_currentLicense.get());
|
||||
if (state != LicenseState::VALID)
|
||||
{
|
||||
return LicenseType::NON_COMMERCIAL;
|
||||
}
|
||||
else if (s_currentLicense->isTestLicense())
|
||||
{
|
||||
return LicenseType::TEST;
|
||||
}
|
||||
|
||||
return LicenseType::COMMERCIAL;
|
||||
}
|
||||
|
||||
std::string LicenseChecker::getCurrentLicenseTypeString()
|
||||
{
|
||||
// WARNING: Don't change these strings. The analytics API on the server relies on them.
|
||||
switch (getCurrentLicenseType())
|
||||
{
|
||||
case LicenseType::NON_COMMERCIAL:
|
||||
return "private";
|
||||
case LicenseType::TEST:
|
||||
return "test";
|
||||
case LicenseType::COMMERCIAL:
|
||||
return "commercial";
|
||||
}
|
||||
|
||||
return "private";
|
||||
}
|
||||
|
||||
std::string LicenseChecker::getLicenseErrorForState(LicenseState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case LicenseState::EMPTY:
|
||||
return "No license key was entered.";
|
||||
case LicenseState::INCOMPLETE:
|
||||
return "The license key is incomplete.";
|
||||
case LicenseState::MALFORMED:
|
||||
return "The license key is malformed.";
|
||||
case LicenseState::INVALID:
|
||||
return "The license key is invalid.";
|
||||
case LicenseState::EXPIRED:
|
||||
return "The license key is expired.";
|
||||
case LicenseState::VALID:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
bool LicenseChecker::createPublicKey(Botan::RSA_PublicKey *rsaPublicKey)
|
||||
{
|
||||
if (!rsaPublicKey)
|
||||
{
|
||||
std::cout << "The loaded key is not a RSA key" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
s_publicKey = std::unique_ptr<Botan::RSA_PublicKey>(rsaPublicKey);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
#ifndef LICENSE_CHECKER_H
|
||||
#define LICENSE_CHECKER_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "License.h"
|
||||
#include "LicenseType.h"
|
||||
|
||||
namespace Botan
|
||||
{
|
||||
class RSA_PublicKey;
|
||||
class AutoSeeded_RNG;
|
||||
}
|
||||
|
||||
class LicenseChecker
|
||||
{
|
||||
public:
|
||||
enum class LicenseState
|
||||
{
|
||||
EMPTY,
|
||||
INCOMPLETE,
|
||||
MALFORMED,
|
||||
INVALID,
|
||||
EXPIRED,
|
||||
VALID
|
||||
};
|
||||
|
||||
static void setEncodeKey(const std::string& key);
|
||||
|
||||
static bool loadPublicKeyFromFile(std::string fileName);
|
||||
static bool loadPublicKeyFromString(const std::string& publicKey);
|
||||
static bool loadPublicKey();
|
||||
|
||||
static const License* getCurrentLicense();
|
||||
|
||||
static std::string getCurrentLicenseString();
|
||||
static std::string getCurrentLicenseStringEncoded();
|
||||
|
||||
static LicenseState setCurrentLicenseString(const std::string& licenseStr);
|
||||
static LicenseState setCurrentLicenseStringEncoded(const std::string& licenseStr);
|
||||
|
||||
static LicenseState checkLicense(const License& license);
|
||||
static LicenseState checkLicenseString(const std::string& licenseString);
|
||||
static LicenseState checkCurrentLicense();
|
||||
|
||||
static LicenseType getCurrentLicenseType();
|
||||
static std::string getCurrentLicenseTypeString();
|
||||
|
||||
static std::string getLicenseErrorForState(LicenseState state);
|
||||
|
||||
private:
|
||||
static bool createPublicKey(Botan::RSA_PublicKey *rsaPublicKey);
|
||||
|
||||
static std::string s_encodeKey;
|
||||
static std::unique_ptr<Botan::RSA_PublicKey> s_publicKey;
|
||||
static std::unique_ptr<License> s_currentLicense;
|
||||
};
|
||||
|
||||
#endif // LICENSE_CHECKER_H
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef LICENSE_TYPE_H
|
||||
#define LICENSE_TYPE_H
|
||||
|
||||
enum class LicenseType
|
||||
{
|
||||
TEST,
|
||||
NON_COMMERCIAL,
|
||||
COMMERCIAL
|
||||
};
|
||||
|
||||
#endif // LICENSE_TYPE_H
|
||||
@@ -1,8 +1,8 @@
|
||||
add_files(
|
||||
LICENSE_GENERATOR
|
||||
|
||||
Generator.cpp
|
||||
Generator.h
|
||||
LicenseGenerator.cpp
|
||||
LicenseGenerator.h
|
||||
)
|
||||
|
||||
# split for tests
|
||||
|
||||
@@ -1,291 +0,0 @@
|
||||
#include "Generator.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <botan/pk_keys.h>
|
||||
#include <botan/pkcs8.h>
|
||||
#include <botan/rsa.h>
|
||||
#include <botan/pbkdf.h>
|
||||
#include <botan/pubkey.h>
|
||||
#include <botan/passhash9.h>
|
||||
#include <botan/base64.h>
|
||||
#include <botan/auto_rng.h>
|
||||
|
||||
#include "License.h"
|
||||
#include "Version.h"
|
||||
#include "PrivateKey.h"
|
||||
#include "PublicKey.h"
|
||||
|
||||
const char PRIVATE_KEY_PASSWORD[] = "BA#jk5vbklAiKL9K3k$";
|
||||
const char PRIVATE_KEY_FILE[] = "private-sourcetrail.pem";
|
||||
const char PUBLIC_KEY_FILE[] = "public-sourcetrail.pem";
|
||||
|
||||
Generator::Generator()
|
||||
{
|
||||
loadPrivateKeyFromString(PRIVATE_KEY);
|
||||
}
|
||||
|
||||
Generator::~Generator()
|
||||
{
|
||||
}
|
||||
|
||||
void Generator::generateKeys()
|
||||
{
|
||||
m_privateKey = std::make_unique<Botan::RSA_PrivateKey>(m_rng, 2048);
|
||||
}
|
||||
|
||||
std::string Generator::getPrivateKeyFilename()
|
||||
{
|
||||
if(m_privateKeyFile.empty())
|
||||
{
|
||||
return PRIVATE_KEY_FILE;
|
||||
}
|
||||
return m_privateKeyFile;
|
||||
}
|
||||
|
||||
std::string Generator::getPublicKeyFilename()
|
||||
{
|
||||
if(m_publicKeyFile.empty())
|
||||
{
|
||||
return PUBLIC_KEY_FILE;
|
||||
}
|
||||
return m_publicKeyFile;
|
||||
}
|
||||
|
||||
std::string Generator::encodeLicenseByVersion(
|
||||
const std::string& user,
|
||||
const std::string& licenseType,
|
||||
size_t numberOfUsers,
|
||||
const std::string& version
|
||||
){
|
||||
m_license = nullptr;
|
||||
|
||||
if (user.size() <= 0)
|
||||
{
|
||||
std::cout << "No user given" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
if (licenseType.size() <= 0)
|
||||
{
|
||||
std::cout << "No license type given" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
if (version.empty())
|
||||
{
|
||||
std::cout << "No version given" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
Version tempVersion = Version::fromString(version);
|
||||
if (tempVersion.isValid())
|
||||
{
|
||||
createLicense(user, licenseType, tempVersion.toShortString(), false, numberOfUsers);
|
||||
}
|
||||
|
||||
return m_license->getLicenseString();
|
||||
}
|
||||
|
||||
std::string Generator::encodeLicenseByQuarters(
|
||||
const std::string& user,
|
||||
const std::string& licenseType,
|
||||
size_t numberOfUsers,
|
||||
size_t quarters
|
||||
){
|
||||
return encodeLicenseByVersion(user, licenseType, numberOfUsers, getExpireVersion(quarters));
|
||||
}
|
||||
|
||||
std::string Generator::encodeLicenseByDays(
|
||||
const std::string& user,
|
||||
const std::string& licenseType,
|
||||
size_t numberOfUsers,
|
||||
size_t days
|
||||
){
|
||||
boost::gregorian::date today = boost::gregorian::day_clock::local_day();
|
||||
boost::gregorian::days daysToTry(days);
|
||||
boost::gregorian::date expireDate = today + daysToTry;
|
||||
|
||||
createLicense(user, licenseType, boost::gregorian::to_simple_string(expireDate), true, numberOfUsers);
|
||||
|
||||
return m_license->getLicenseString();
|
||||
}
|
||||
|
||||
void Generator::printLicenseAndWriteItToFile()
|
||||
{
|
||||
if (m_license)
|
||||
{
|
||||
m_license->print();
|
||||
m_license->writeToFile("license.txt");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "nothing to print" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool Generator::verifyLicense(const std::string& filename)
|
||||
{
|
||||
License license;
|
||||
license.loadFromFile(filename);
|
||||
// license.loadPublicKeyFromString(PUBLIC_KEY);
|
||||
return license.isValid();
|
||||
}
|
||||
|
||||
void Generator::setCustomPrivateKeyFile(const std::string& file)
|
||||
{
|
||||
if(!file.empty())
|
||||
{
|
||||
m_privateKeyFile = file;
|
||||
}
|
||||
}
|
||||
|
||||
void Generator::setCustomPublicKeyFile(const std::string& file)
|
||||
{
|
||||
if(!file.empty())
|
||||
{
|
||||
m_publicKeyFile = file;
|
||||
}
|
||||
}
|
||||
|
||||
std::string Generator::getPublicKeyPEMFileAsString()
|
||||
{
|
||||
return Botan::X509::PEM_encode(*m_privateKey);
|
||||
}
|
||||
|
||||
std::string Generator::getPrivateKeyPEMFileAsString()
|
||||
{
|
||||
if (m_privateKey == NULL)
|
||||
{
|
||||
std::cout << "m_privateKey is NULL" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
return Botan::PKCS8::PEM_encode(*m_privateKey, m_rng, PRIVATE_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
void Generator::writeKeysToFiles()
|
||||
{
|
||||
std::string publicKeyFilename = getPublicKeyFilename();
|
||||
if (publicKeyFilename.size() <= 0)
|
||||
{
|
||||
std::cout << "Failed to retrieve file name for public key" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string privateKeyFilename = getPrivateKeyFilename();
|
||||
if (privateKeyFilename.size() <= 0)
|
||||
{
|
||||
std::cout << "Failed to retrieve file name for private key" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "public key filename: " << publicKeyFilename << std::endl;
|
||||
std::ofstream pub(publicKeyFilename);
|
||||
pub << getPublicKeyPEMFileAsString();
|
||||
std::cout << "public key created" << std::endl;
|
||||
|
||||
std::cout << "private key filename: " << privateKeyFilename << std::endl;
|
||||
std::ofstream priv(privateKeyFilename);
|
||||
priv << getPrivateKeyPEMFileAsString();
|
||||
std::cout << "private key created" << std::endl;
|
||||
}
|
||||
|
||||
bool Generator::loadPrivateKeyFromFile()
|
||||
{
|
||||
if (boost::filesystem::exists(getPrivateKeyFilename()) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Botan::Private_Key* privateKey = Botan::PKCS8::load_key(getPrivateKeyFilename(), m_rng, PRIVATE_KEY_PASSWORD);
|
||||
Botan::RSA_PrivateKey *rsaKey = dynamic_cast<Botan::RSA_PrivateKey *>(privateKey);
|
||||
|
||||
if (!rsaKey)
|
||||
{
|
||||
std::cout << "The key is not a RSA key" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_privateKey = std::unique_ptr<Botan::RSA_PrivateKey>(rsaKey);
|
||||
|
||||
return (m_privateKey != NULL);
|
||||
}
|
||||
|
||||
bool Generator::loadPrivateKeyFromString(const std::string& key)
|
||||
{
|
||||
if (key.size() <= 0)
|
||||
{
|
||||
std::cout << "No key string given" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
Botan::DataSource_Memory in(key);
|
||||
Botan::Private_Key* privateKey= Botan::PKCS8::load_key(in, m_rng, PRIVATE_KEY_PASSWORD);
|
||||
Botan::RSA_PrivateKey *rsaKey = dynamic_cast<Botan::RSA_PrivateKey *>(privateKey);
|
||||
|
||||
if (!rsaKey)
|
||||
{
|
||||
std::cout << "The key is not a RSA key" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_privateKey = std::unique_ptr<Botan::RSA_PrivateKey>(rsaKey);
|
||||
|
||||
return (m_privateKey != NULL);
|
||||
}
|
||||
|
||||
Botan::RSA_PrivateKey *Generator::getPrivateKey() const
|
||||
{
|
||||
return m_privateKey.get();
|
||||
}
|
||||
|
||||
void Generator::createLicense(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
const std::string& expiration,
|
||||
bool expiresAtDate,
|
||||
size_t numberOfUsers
|
||||
){
|
||||
m_license = std::make_unique<License>();
|
||||
|
||||
m_license->createHeader(
|
||||
user, type.size() ? type : LicenseConstants::TEST_LICENSE_STRING, expiration, expiresAtDate, numberOfUsers);
|
||||
|
||||
Botan::AutoSeeded_RNG rng;
|
||||
std::string pass9 = Botan::generate_passhash9(m_license->getExpireLine(), m_rng);
|
||||
m_license->setHashLine(pass9);
|
||||
|
||||
//encode message
|
||||
const std::string emsa = "EMSA4(SHA-256)";
|
||||
Botan::PK_Signer signer(*(m_privateKey.get()), rng, emsa);
|
||||
Botan::DataSource_Memory in(m_license->getMessage());
|
||||
Botan::byte buffer[4096] = {0};
|
||||
|
||||
while (size_t got = in.read(buffer, sizeof(buffer)))
|
||||
{
|
||||
signer.update(buffer, got);
|
||||
}
|
||||
|
||||
const std::string signature = Botan::base64_encode(signer.signature(rng));
|
||||
m_license->setSignature(signature);
|
||||
}
|
||||
|
||||
int Generator::mapMonthToVersion(int month)
|
||||
{
|
||||
return (month-1)/3+1;
|
||||
}
|
||||
|
||||
std::string Generator::getExpireVersion(int quarters)
|
||||
{
|
||||
boost::gregorian::date today = boost::gregorian::day_clock::local_day();
|
||||
int monthNumber = today.month().as_number();
|
||||
Version version(today.year(), mapMonthToVersion(monthNumber));
|
||||
version += quarters;
|
||||
return version.toShortString();
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
#ifndef KEYGEN_H
|
||||
#define KEYGEN_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <botan/auto_rng.h>
|
||||
|
||||
namespace Botan
|
||||
{
|
||||
class RSA_PrivateKey;
|
||||
}
|
||||
class License;
|
||||
|
||||
class Generator
|
||||
{
|
||||
public:
|
||||
Generator();
|
||||
~Generator();
|
||||
|
||||
std::string encodeLicenseByVersion(
|
||||
const std::string& user,
|
||||
const std::string& licenseType,
|
||||
size_t numberOfUsers,
|
||||
const std::string& version
|
||||
);
|
||||
std::string encodeLicenseByQuarters(
|
||||
const std::string& user,
|
||||
const std::string& licenseType,
|
||||
size_t numberOfUsers,
|
||||
size_t quarters
|
||||
);
|
||||
std::string encodeLicenseByDays(
|
||||
const std::string& user,
|
||||
const std::string& licenseType,
|
||||
size_t numberOfUsers,
|
||||
size_t days
|
||||
);
|
||||
|
||||
void printLicenseAndWriteItToFile();
|
||||
bool verifyLicense(const std::string& filename = "license.txt");
|
||||
void generateKeys();
|
||||
void writeKeysToFiles();
|
||||
void setCustomPrivateKeyFile(const std::string& file);
|
||||
void setCustomPublicKeyFile(const std::string& file);
|
||||
|
||||
std::string getPublicKeyPEMFileAsString();
|
||||
std::string getPrivateKeyPEMFileAsString();
|
||||
bool loadPrivateKeyFromFile();
|
||||
bool loadPrivateKeyFromString(const std::string& key);
|
||||
|
||||
Botan::RSA_PrivateKey* getPrivateKey() const;
|
||||
void createLicense(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
const std::string& expiration,
|
||||
bool expiresAtDate,
|
||||
size_t numberOfUsers
|
||||
);
|
||||
|
||||
std::string getExpireVersion(int quarters);
|
||||
void setVersionLine(int year, int minorVersion);
|
||||
private:
|
||||
int mapMonthToVersion(int month);
|
||||
std::string getPrivateKeyFilename();
|
||||
std::string getPublicKeyFilename();
|
||||
|
||||
//Botan
|
||||
Botan::AutoSeeded_RNG m_rng;
|
||||
|
||||
std::string m_privateKeyFile;
|
||||
std::string m_publicKeyFile;
|
||||
std::unique_ptr<License> m_license;
|
||||
std::unique_ptr<Botan::RSA_PrivateKey> m_privateKey;
|
||||
|
||||
};
|
||||
|
||||
#endif // KEYGEN_H
|
||||
@@ -0,0 +1,243 @@
|
||||
#include "LicenseGenerator.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/date_time/gregorian/gregorian.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <botan/auto_rng.h>
|
||||
#include <botan/base64.h>
|
||||
#include <botan/passhash9.h>
|
||||
#include <botan/pbkdf.h>
|
||||
#include <botan/pk_keys.h>
|
||||
#include <botan/pkcs8.h>
|
||||
#include <botan/pubkey.h>
|
||||
#include <botan/rsa.h>
|
||||
|
||||
#include "Version.h"
|
||||
|
||||
const char PRIVATE_KEY_PASSWORD[] = "BA#jk5vbklAiKL9K3k$";
|
||||
|
||||
LicenseGenerator::LicenseGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
LicenseGenerator::~LicenseGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
void LicenseGenerator::generatePrivateKey()
|
||||
{
|
||||
m_privateKey = std::make_unique<Botan::RSA_PrivateKey>(m_rng, 2048);
|
||||
}
|
||||
|
||||
std::unique_ptr<License> LicenseGenerator::createLicenseByVersion(
|
||||
const std::string& user,
|
||||
const std::string& licenseType,
|
||||
size_t numberOfUsers,
|
||||
const std::string& version
|
||||
){
|
||||
if (version.empty())
|
||||
{
|
||||
std::cout << "No version given" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Version tempVersion = Version::fromString(version);
|
||||
if (tempVersion.isValid())
|
||||
{
|
||||
return createLicense(user, licenseType, numberOfUsers, tempVersion.toShortString(), LicenseConstants::VALID_UNLIMITED);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<License> LicenseGenerator::createLicenseByQuarters(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers,
|
||||
size_t quarters
|
||||
){
|
||||
boost::gregorian::date today = boost::gregorian::day_clock::local_day();
|
||||
int quarter = (today.month().as_number() - 1) / 3 + 1;
|
||||
Version version(today.year(), quarter);
|
||||
version += quarters;
|
||||
|
||||
return createLicenseByVersion(user, type, numberOfUsers, version.toShortString());
|
||||
}
|
||||
|
||||
std::unique_ptr<License> LicenseGenerator::createLicenseByDays(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers,
|
||||
size_t days
|
||||
){
|
||||
boost::gregorian::date today = boost::gregorian::day_clock::local_day();
|
||||
boost::gregorian::days daysToTry(days);
|
||||
boost::gregorian::date expireDate = today + daysToTry;
|
||||
|
||||
return createLicense(
|
||||
user,
|
||||
(type.size() ? type : LicenseConstants::TEST_LICENSE), numberOfUsers,
|
||||
LicenseConstants::VALID_UNLIMITED,
|
||||
boost::gregorian::to_simple_string(expireDate)
|
||||
);
|
||||
}
|
||||
|
||||
std::unique_ptr<License> LicenseGenerator::createLicenseLifelong(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers
|
||||
){
|
||||
if (numberOfUsers == 0)
|
||||
{
|
||||
std::cout << "No user count given" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return createLicense(user, type, numberOfUsers, LicenseConstants::VALID_UNLIMITED, LicenseConstants::VALID_UNLIMITED);
|
||||
}
|
||||
|
||||
std::string LicenseGenerator::getPublicKeyPEMFileAsString()
|
||||
{
|
||||
if (!m_privateKey)
|
||||
{
|
||||
std::cout << "No private key loaded" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
return Botan::X509::PEM_encode(*m_privateKey);
|
||||
}
|
||||
|
||||
std::string LicenseGenerator::getPrivateKeyPEMFileAsString()
|
||||
{
|
||||
if (!m_privateKey)
|
||||
{
|
||||
std::cout << "No private key loaded" << std::endl;
|
||||
return "";
|
||||
}
|
||||
|
||||
return Botan::PKCS8::PEM_encode(*m_privateKey, m_rng, PRIVATE_KEY_PASSWORD);
|
||||
}
|
||||
|
||||
void LicenseGenerator::writeKeysToFiles(const std::string& publicKeyFilename, const std::string& privateKeyFilename)
|
||||
{
|
||||
if (publicKeyFilename.size() <= 0)
|
||||
{
|
||||
std::cout << "Public key file path is empty" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (privateKeyFilename.size() <= 0)
|
||||
{
|
||||
std::cout << "Private key file path is empty" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "public key filename: " << publicKeyFilename << std::endl;
|
||||
std::ofstream pub(publicKeyFilename);
|
||||
pub << getPublicKeyPEMFileAsString();
|
||||
pub.close();
|
||||
std::cout << "public key created" << std::endl;
|
||||
|
||||
std::cout << "private key filename: " << privateKeyFilename << std::endl;
|
||||
std::ofstream priv(privateKeyFilename);
|
||||
priv << getPrivateKeyPEMFileAsString();
|
||||
priv.close();
|
||||
std::cout << "private key created" << std::endl;
|
||||
}
|
||||
|
||||
bool LicenseGenerator::loadPrivateKeyFromFile(const std::string& file)
|
||||
{
|
||||
if (!boost::filesystem::exists(file))
|
||||
{
|
||||
std::cout << "Private key not found: " << file << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return createPrivateKey(dynamic_cast<Botan::RSA_PrivateKey *>(Botan::PKCS8::load_key(file, m_rng, PRIVATE_KEY_PASSWORD)));
|
||||
}
|
||||
|
||||
bool LicenseGenerator::loadPrivateKeyFromString(const std::string& key)
|
||||
{
|
||||
if (key.empty())
|
||||
{
|
||||
std::cout << "No key string given" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
Botan::DataSource_Memory in(key);
|
||||
return createPrivateKey(dynamic_cast<Botan::RSA_PrivateKey *>(Botan::PKCS8::load_key(in, m_rng, PRIVATE_KEY_PASSWORD)));
|
||||
}
|
||||
|
||||
Botan::RSA_PrivateKey* LicenseGenerator::getPrivateKey() const
|
||||
{
|
||||
return m_privateKey.get();
|
||||
}
|
||||
|
||||
bool LicenseGenerator::createPrivateKey(Botan::RSA_PrivateKey* rsaPrivateKey)
|
||||
{
|
||||
if (!rsaPrivateKey)
|
||||
{
|
||||
std::cout << "The key is not a RSA key" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_privateKey = std::unique_ptr<Botan::RSA_PrivateKey>(rsaPrivateKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<License> LicenseGenerator::createLicense(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers,
|
||||
const std::string& expirationVersion,
|
||||
const std::string& expirationDate
|
||||
){
|
||||
if (user.empty())
|
||||
{
|
||||
std::cout << "No user given" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (type.empty())
|
||||
{
|
||||
std::cout << "No license type given" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (expirationVersion.empty())
|
||||
{
|
||||
std::cout << "No expiration version given" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (expirationDate.empty())
|
||||
{
|
||||
std::cout << "No expiration date given" << std::endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<License> license = std::make_unique<License>();
|
||||
license->setMessage(user, type, numberOfUsers, expirationVersion, expirationDate);
|
||||
|
||||
Botan::AutoSeeded_RNG rng;
|
||||
|
||||
// encode message
|
||||
const std::string emsa = "EMSA4(SHA-256)";
|
||||
Botan::PK_Signer signer(*(m_privateKey.get()), rng, emsa);
|
||||
Botan::DataSource_Memory in(license->getMessage(false));
|
||||
|
||||
Botan::byte buffer[4096] = {0};
|
||||
while (size_t got = in.read(buffer, sizeof(buffer)))
|
||||
{
|
||||
signer.update(buffer, got);
|
||||
}
|
||||
|
||||
const std::string signature = Botan::base64_encode(signer.signature(rng));
|
||||
license->setSignature(signature);
|
||||
|
||||
return license;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#ifndef LICENSE_GENERATOR_H
|
||||
#define LICENSE_GENERATOR_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include <botan/auto_rng.h>
|
||||
|
||||
#include "License.h"
|
||||
|
||||
namespace Botan
|
||||
{
|
||||
class RSA_PrivateKey;
|
||||
}
|
||||
|
||||
class License;
|
||||
|
||||
class LicenseGenerator
|
||||
{
|
||||
public:
|
||||
LicenseGenerator();
|
||||
~LicenseGenerator();
|
||||
|
||||
void generatePrivateKey();
|
||||
bool loadPrivateKeyFromFile(const std::string& file);
|
||||
bool loadPrivateKeyFromString(const std::string& key);
|
||||
|
||||
Botan::RSA_PrivateKey* getPrivateKey() const;
|
||||
|
||||
std::string getPublicKeyPEMFileAsString();
|
||||
std::string getPrivateKeyPEMFileAsString();
|
||||
|
||||
void writeKeysToFiles(const std::string& publicKeyFilename, const std::string& privateKeyFilename);
|
||||
|
||||
std::unique_ptr<License> createLicenseByVersion(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers,
|
||||
const std::string& version
|
||||
);
|
||||
|
||||
std::unique_ptr<License> createLicenseByQuarters(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers,
|
||||
size_t quarters
|
||||
);
|
||||
|
||||
std::unique_ptr<License> createLicenseByDays(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers,
|
||||
size_t days
|
||||
);
|
||||
|
||||
std::unique_ptr<License> createLicenseLifelong(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers
|
||||
);
|
||||
|
||||
private:
|
||||
bool createPrivateKey(Botan::RSA_PrivateKey* rsaPrivateKey);
|
||||
|
||||
std::unique_ptr<License> createLicense(
|
||||
const std::string& user,
|
||||
const std::string& type,
|
||||
size_t numberOfUsers,
|
||||
const std::string& expirationVersion,
|
||||
const std::string& expirationDate
|
||||
);
|
||||
|
||||
//Botan
|
||||
Botan::AutoSeeded_RNG m_rng;
|
||||
std::unique_ptr<Botan::RSA_PrivateKey> m_privateKey;
|
||||
};
|
||||
|
||||
#endif // KEYGEN_H
|
||||
@@ -5,7 +5,8 @@
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include "Generator.h"
|
||||
#include "LicenseChecker.h"
|
||||
#include "LicenseGenerator.h"
|
||||
#include "PrivateKey.h"
|
||||
#include "PublicKey.h"
|
||||
|
||||
@@ -17,9 +18,9 @@ bool process_command_line(int argc, char** argv)
|
||||
{
|
||||
std::string user;
|
||||
std::string version;
|
||||
std::string privateKeyFile;
|
||||
std::string publicKeyFile;
|
||||
std::string licenseFile = "";
|
||||
std::string privateKeyFile = "private-sourcetrail.pem";
|
||||
std::string publicKeyFile = "public-sourcetrail.pem";
|
||||
std::string licenseFile = "license.txt";
|
||||
std::string type = "";
|
||||
int quarters = 4;
|
||||
int days = 0;
|
||||
@@ -31,32 +32,28 @@ bool process_command_line(int argc, char** argv)
|
||||
("generate,g", po::value<std::string>(&user), "Generate a License, USERNAME as value")
|
||||
("check,c", "Validate a License");
|
||||
|
||||
po::options_description keygen_description("Options Keygeneration");
|
||||
po::options_description keygen_description("Options License Generation");
|
||||
keygen_description.add_options()
|
||||
("version,v", po::value<std::string>(&version), "Versionnumber (in format 20xx.x) until Sourcetrail valid")
|
||||
("quarters,q", po::value<int>(&quarters), "Number of quarters Sourcetrail is valid from now")
|
||||
("users,u", po::value<int>(&numberOfUsers), "Number of users")
|
||||
("licenseType,t", po::value<std::string>(&type), "License Type of ")
|
||||
("expiration,e", po::value<int>(&days), "Valid for <value> days");
|
||||
("expiration,e", po::value<int>(&days), "Valid for <value> days")
|
||||
("lifelong,l", "Valid perpetually");
|
||||
|
||||
po::options_description hidden_description("Hidden Options");
|
||||
hidden_description.add_options()
|
||||
po::options_description advanced_description("Advanced Options");
|
||||
advanced_description.add_options()
|
||||
("public-file", po::value<std::string>(&publicKeyFile), "Custom public key file")
|
||||
("private-file", po::value<std::string>(&privateKeyFile), "Custom private key file")
|
||||
("license-file", po::value<std::string>(&licenseFile), "Custom license")
|
||||
("hidden", "Print this help message");
|
||||
("license-file", po::value<std::string>(&licenseFile), "Custom license (default: license.txt)");
|
||||
|
||||
|
||||
po::options_description desc("Sourcetrail Generator");
|
||||
desc.add_options()
|
||||
("help,h", "Print this help message");
|
||||
desc.add(modes_description).add(keygen_description);
|
||||
|
||||
po::options_description allDescriptions("Sourcetrail Generator");
|
||||
allDescriptions.add_options();
|
||||
allDescriptions.add(modes_description).add(keygen_description).add(hidden_description);
|
||||
desc.add(modes_description).add(keygen_description).add(advanced_description);
|
||||
|
||||
po::variables_map vm;
|
||||
|
||||
po::store(po::parse_command_line(argc,argv,desc), vm);
|
||||
po::notify(vm);
|
||||
|
||||
@@ -64,7 +61,7 @@ bool process_command_line(int argc, char** argv)
|
||||
if (vm.count("help"))
|
||||
{
|
||||
std::cout << desc << std::endl;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
// no mode chosen -> display help
|
||||
@@ -73,42 +70,21 @@ bool process_command_line(int argc, char** argv)
|
||||
std::cout << "*****************************\nNo mode chosen, display help: "
|
||||
<< "\n*****************************\n\n" << desc << std::endl;
|
||||
|
||||
return 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (vm.count("hidden"))
|
||||
{
|
||||
std::cout << allDescriptions << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Generator keygen;
|
||||
|
||||
// make sure there are no negative amount of users
|
||||
if (vm.count("users"))
|
||||
{
|
||||
if (numberOfUsers < 0)
|
||||
{
|
||||
std::cout << "Invalid amount of users. (Must be > 0)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
LicenseGenerator keygen;
|
||||
|
||||
if (vm.count("key"))
|
||||
{
|
||||
keygen.generateKeys();
|
||||
keygen.writeKeysToFiles();
|
||||
}
|
||||
|
||||
if (vm.count("public-file"))
|
||||
{
|
||||
keygen.setCustomPublicKeyFile(publicKeyFile);
|
||||
keygen.generatePrivateKey();
|
||||
keygen.writeKeysToFiles(publicKeyFile, privateKeyFile);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (vm.count("private-file"))
|
||||
{
|
||||
keygen.setCustomPrivateKeyFile(privateKeyFile);
|
||||
keygen.loadPrivateKeyFromFile(privateKeyFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -117,30 +93,71 @@ bool process_command_line(int argc, char** argv)
|
||||
|
||||
if (vm.count("generate"))
|
||||
{
|
||||
if (days > 0)
|
||||
// make sure there is no negative amount of users
|
||||
if (vm.count("users"))
|
||||
{
|
||||
keygen.encodeLicenseByDays(user, type, numberOfUsers, days);
|
||||
if (numberOfUsers < 0)
|
||||
{
|
||||
std::cout << "Invalid amount of users. (Must be > 0)" << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<License> license;
|
||||
|
||||
if (vm.count("lifelong"))
|
||||
{
|
||||
license = keygen.createLicenseLifelong(user, type, numberOfUsers);
|
||||
}
|
||||
else if (vm.count("expiration"))
|
||||
{
|
||||
license = keygen.createLicenseByDays(user, type, numberOfUsers, days);
|
||||
}
|
||||
else if (!version.empty())
|
||||
{
|
||||
keygen.encodeLicenseByVersion(user, type, numberOfUsers, version);
|
||||
license = keygen.createLicenseByVersion(user, type, numberOfUsers, version);
|
||||
}
|
||||
else
|
||||
{
|
||||
keygen.encodeLicenseByQuarters(user, type, numberOfUsers, quarters);
|
||||
license = keygen.createLicenseByQuarters(user, type, numberOfUsers, quarters);
|
||||
}
|
||||
|
||||
if (license)
|
||||
{
|
||||
license->print();
|
||||
license->writeToFile(licenseFile);
|
||||
}
|
||||
keygen.printLicenseAndWriteItToFile();
|
||||
}
|
||||
|
||||
if (vm.count("check"))
|
||||
{
|
||||
if (keygen.verifyLicense())
|
||||
if (vm.count("public-file"))
|
||||
{
|
||||
LicenseChecker::loadPublicKeyFromFile(publicKeyFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
LicenseChecker::loadPublicKey();
|
||||
}
|
||||
|
||||
License license;
|
||||
LicenseChecker::LicenseState state = LicenseChecker::LicenseState::EMPTY;
|
||||
if (license.loadFromFile(licenseFile))
|
||||
{
|
||||
state = LicenseChecker::checkLicense(license);
|
||||
}
|
||||
else
|
||||
{
|
||||
state = LicenseChecker::LicenseState::MALFORMED;
|
||||
}
|
||||
|
||||
if (state == LicenseChecker::LicenseState::VALID)
|
||||
{
|
||||
std::cout << "License valid" << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "License not valid" << std::endl;
|
||||
std::cout << LicenseChecker::getLicenseErrorForState(state) << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -153,7 +170,8 @@ bool process_command_line(int argc, char** argv)
|
||||
return true;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
process_command_line(argc, argv);
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -18,8 +18,9 @@ add_files(
|
||||
FilePathFilterTestSuite.h
|
||||
FilePathTestSuite.h
|
||||
FileSystemTestSuite.h
|
||||
GeneratorTestSuite.h
|
||||
GraphTestSuite.h
|
||||
LicenseCheckerTestSuite.h
|
||||
LicenseGeneratorTestSuite.h
|
||||
LogManagerTestSuite.h
|
||||
LowMemoryStringMapTestSuite.h
|
||||
MatrixBaseTestSuite.h
|
||||
|
||||
@@ -0,0 +1,634 @@
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include "License.h"
|
||||
#include "LicenseChecker.h"
|
||||
#include "Version.h"
|
||||
|
||||
class LicenseCheckerTestSuite : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
|
||||
void test_check_empty_license()
|
||||
{
|
||||
LicenseChecker::loadPublicKey();
|
||||
LicenseChecker::LicenseState state = LicenseChecker::checkLicenseString("");
|
||||
TS_ASSERT_EQUALS(state, LicenseChecker::LicenseState::EMPTY);
|
||||
}
|
||||
|
||||
void test_check_malformed_license()
|
||||
{
|
||||
LicenseChecker::loadPublicKey();
|
||||
LicenseChecker::LicenseState state = LicenseChecker::checkLicenseString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 3
|
||||
Licensed usage period: until 2021-Dec-10
|
||||
-
|
||||
$9$AQAKpvMMWlY7aWaMQY/AScwUo/nhqFdj+skS46v+7QHoj7X6qS+W
|
||||
IErtt71WhVoqM8eki8IS+BDuO+TyLCAKhpNYQhvgykgfAx16T3ypD4A
|
||||
4/DKGZbm/ZzZ3J5KD30Ko7pZfsgCnBMZu+VHSkoxtntDCzmhNySF4yo
|
||||
fiDVhR9NYeWjgd0jtj1+dpBfjmQeXLgf4DqtYvgW446pUfEIIur174y
|
||||
ffYziDA9VhIpgx2ZEYfFFXWNY+0esAkN389UxZ5UgQcs0LHTdEBphYO
|
||||
oZJKdZdPbF+zSPwUeRej9SkCOpionrJ9lvVMo3p2pro0boeM4/bAs/p
|
||||
MyEDaYFJdoazS3T8CXB0oPdEoyvYR6kOBZCw9YeW1Ud0azN8BeMx68c
|
||||
gwitGhNQeI9A==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT_EQUALS(state, LicenseChecker::LicenseState::MALFORMED);
|
||||
}
|
||||
|
||||
void test_check_invalid_license()
|
||||
{
|
||||
LicenseChecker::loadPublicKey();
|
||||
LicenseChecker::LicenseState state = LicenseChecker::checkLicenseString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 3
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2021-Dec-10
|
||||
-
|
||||
$9$AQAKpvMMWlY7aWaMQY/AScwUo/nhqFdj+skS46v+7QHoj7X6qS+W
|
||||
IErtt71WhVoqM8eki8IS+BDuO+TyLCAKhpNYQhvgykgfAx16T3ypD4A
|
||||
4/DKGZbm/ZzZ3J5KD30Ko7pZfsgCnBMZu+VHSkoxtntDCzmhNySF4yo
|
||||
fiDVhR9NYeWjgd0jtj1+dpBfjmQeXLgf4DqtYvgW446pUfEIIur174y
|
||||
ffYziDA9VhIpgx2ZEYfFFXWNY+0esAkN389UxZ5UgQcs0LHTdEBphYO
|
||||
oZJKdZdPbF+zSPwUeRej9SkCOpionrJ9lvVMo3p2pro0boeM4/bAs/p
|
||||
MyEDaYFJdoazS3T8CXB0oPdEoyvYR6kOBZCw9YeW1Ud0azN8BeMx68C
|
||||
gwitGhNQeI9A==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT_EQUALS(state, LicenseChecker::LicenseState::INVALID);
|
||||
}
|
||||
|
||||
void test_check_license_without_start_end()
|
||||
{
|
||||
LicenseChecker::loadPublicKey();
|
||||
LicenseChecker::LicenseState state = LicenseChecker::checkLicenseString(
|
||||
R"(
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 3
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2021-Dec-10
|
||||
-
|
||||
$9$AQAKpvMMWlY7aWaMQY/AScwUo/nhqFdj+skS46v+7QHoj7X6qS+W
|
||||
IErtt71WhVoqM8eki8IS+BDuO+TyLCAKhpNYQhvgykgfAx16T3ypD4A
|
||||
4/DKGZbm/ZzZ3J5KD30Ko7pZfsgCnBMZu+VHSkoxtntDCzmhNySF4yo
|
||||
fiDVhR9NYeWjgd0jtj1+dpBfjmQeXLgf4DqtYvgW446pUfEIIur174y
|
||||
ffYziDA9VhIpgx2ZEYfFFXWNY+0esAkN389UxZ5UgQcs0LHTdEBphYO
|
||||
oZJKdZdPbF+zSPwUeRej9SkCOpionrJ9lvVMo3p2pro0boeM4/bAs/p
|
||||
MyEDaYFJdoazS3T8CXB0oPdEoyvYR6kOBZCw9YeW1Ud0azN8BeMx68c
|
||||
gwitGhNQeI9A==
|
||||
)"
|
||||
);
|
||||
|
||||
TS_ASSERT_EQUALS(state, LicenseChecker::LicenseState::VALID);
|
||||
}
|
||||
|
||||
void test_license_encoding()
|
||||
{
|
||||
LicenseChecker::loadPublicKey();
|
||||
LicenseChecker::setCurrentLicenseString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 3
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2021-Dec-10
|
||||
-
|
||||
$9$AQAKpvMMWlY7aWaMQY/AScwUo/nhqFdj+skS46v+7QHoj7X6qS+W
|
||||
IErtt71WhVoqM8eki8IS+BDuO+TyLCAKhpNYQhvgykgfAx16T3ypD4A
|
||||
4/DKGZbm/ZzZ3J5KD30Ko7pZfsgCnBMZu+VHSkoxtntDCzmhNySF4yo
|
||||
fiDVhR9NYeWjgd0jtj1+dpBfjmQeXLgf4DqtYvgW446pUfEIIur174y
|
||||
ffYziDA9VhIpgx2ZEYfFFXWNY+0esAkN389UxZ5UgQcs0LHTdEBphYO
|
||||
oZJKdZdPbF+zSPwUeRej9SkCOpionrJ9lvVMo3p2pro0boeM4/bAs/p
|
||||
MyEDaYFJdoazS3T8CXB0oPdEoyvYR6kOBZCw9YeW1Ud0azN8BeMx68c
|
||||
gwitGhNQeI9A==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
LicenseChecker::LicenseState state = LicenseChecker::checkCurrentLicense();
|
||||
TS_ASSERT_EQUALS(state, LicenseChecker::LicenseState::VALID);
|
||||
|
||||
LicenseChecker::setEncodeKey("test_key");
|
||||
std::string encodedLicenseString = LicenseChecker::getCurrentLicenseStringEncoded();
|
||||
|
||||
LicenseChecker::setEncodeKey("test_key_new");
|
||||
state = LicenseChecker::setCurrentLicenseStringEncoded(encodedLicenseString);
|
||||
|
||||
TS_ASSERT_EQUALS(state, LicenseChecker::LicenseState::MALFORMED);
|
||||
|
||||
LicenseChecker::setEncodeKey("test_key");
|
||||
state = LicenseChecker::setCurrentLicenseStringEncoded(encodedLicenseString);
|
||||
|
||||
TS_ASSERT_EQUALS(state, LicenseChecker::LicenseState::VALID);
|
||||
}
|
||||
|
||||
void test_check_version_license()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 1
|
||||
Licensed product version: up to 2020.2
|
||||
Licensed usage period: unlimited
|
||||
-
|
||||
$9$AQAKrGHpbkd9I+FVXZ8YtKK7rJePuPqJcWwaLoNYze14fRNiIBQV
|
||||
QcelksnNcsztdUVCSp1MPkEbuWHkhR74m5qJ3wECnMekfVmP3GhbvwL
|
||||
cqAEyrpR4PrZCRM2oxEgcRVk6QrPM9pHYPaPHe8sV74odOGQtHUrEW6
|
||||
N8ZNL0NMLzSxurD/hXdDLdgxya9UptYIJ6c2Bbu33xJ87Ofs07pptc0
|
||||
4VzBXJYG5iKIbmQAnrU6KOBL5iIZ11/sM8VbkTw+nSySI4yr3/f8BWe
|
||||
7PhDAmhvDTX9aMMfpaXXeL3PyC/023FwyAqimB1vzoo28Pm1p1tN9mF
|
||||
l7Ci+UazTnVY34DLVoXYUaDVlt8t8VYq05Z7f6sfcGtqpthuevGatM0
|
||||
e6G8hqqTc+CQ==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
Version version = Version::getApplicationVersion();
|
||||
Version::setApplicationVersion(Version(2020, 2, 11, "asdfasdf"));
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 1);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -2);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(!license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::VALID);
|
||||
|
||||
Version::setApplicationVersion(version);
|
||||
}
|
||||
|
||||
void test_check_version_license_expired()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 1
|
||||
Licensed product version: up to 2018.2
|
||||
Licensed usage period: unlimited
|
||||
-
|
||||
$9$AQAKshj0tavIV6xR/dL9nXxaxib80g8Kxho0CGpvdypb4xujP5nw
|
||||
mIQi3TiVrBTCszJLONCdnhyzotj1R370JPHWa/FFbGqABhexI5PGdIb
|
||||
3Pa1EqQP9otCJZvDhQTxkm2Ev3zFEgDsA8njBQjr09Blcbt6F9F5zpJ
|
||||
Ld75PRPLgvVmrxJfwOOg0tYQ/WrKzmm68gcF7XUHS1N7QDSrxjkqihu
|
||||
xvHd6PoQSmX8pbNpYbkNF6N1T7rR5B8o7BnCc1PEw13J6k8CsomyQ4Q
|
||||
qg2qAz0IOXk+r7ZagNvR9XedqcytIu6e0u48ujpEUv+1TSj7VBrOq1a
|
||||
5La45aDoFn2XgdX/mlJh4RPeTEtg6u06PHf4pHFWiOXyKcvvAWuy7GT
|
||||
YeDldWiy3iwA==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
Version version = Version::getApplicationVersion();
|
||||
Version::setApplicationVersion(Version(2018, 3, 11, "asdfasdf"));
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 1);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -2);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::EXPIRED);
|
||||
|
||||
Version::setApplicationVersion(version);
|
||||
}
|
||||
|
||||
void test_check_period_license()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 3
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2021-Dec-10
|
||||
-
|
||||
$9$AQAKpvMMWlY7aWaMQY/AScwUo/nhqFdj+skS46v+7QHoj7X6qS+W
|
||||
IErtt71WhVoqM8eki8IS+BDuO+TyLCAKhpNYQhvgykgfAx16T3ypD4A
|
||||
4/DKGZbm/ZzZ3J5KD30Ko7pZfsgCnBMZu+VHSkoxtntDCzmhNySF4yo
|
||||
fiDVhR9NYeWjgd0jtj1+dpBfjmQeXLgf4DqtYvgW446pUfEIIur174y
|
||||
ffYziDA9VhIpgx2ZEYfFFXWNY+0esAkN389UxZ5UgQcs0LHTdEBphYO
|
||||
oZJKdZdPbF+zSPwUeRej9SkCOpionrJ9lvVMo3p2pro0boeM4/bAs/p
|
||||
MyEDaYFJdoazS3T8CXB0oPdEoyvYR6kOBZCw9YeW1Ud0azN8BeMx68c
|
||||
gwitGhNQeI9A==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 3);
|
||||
TS_ASSERT(license.getTimeLeft() >= 0);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(!license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::VALID);
|
||||
}
|
||||
|
||||
void test_check_period_license_expired()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 3
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2018-Dec-06
|
||||
-
|
||||
$9$AQAKkgTBy1koMv8CusfbUVWyMQtbTc67dSMTv+96bnVWSQdc/Bti
|
||||
O8300TO2SWEVuyMo/BQkmXTnEFWLtwnAPqtAJXLR4oDTqlHUNs8Ur5q
|
||||
iL6dMVsiyp41EHrzuof1/u+pgX03kCyIgD6TAn42En3+2pgo1zhDxnx
|
||||
vaBxQTUcUW8+kJyNdSlJ6E2DgwGX2uXmf8MF8nsJtwHhOe/3qyV6fm0
|
||||
PtXmWwjesNX7qGA8L+pcZKsB6AdC4dEJ71iFr8u/O1i8ab0v5xorJM3
|
||||
zJ40jE0kcucpag5sW43ch0eX6PntXSwXuFfaQ7gTUH6qYTvxqIFUZGW
|
||||
r0TrPuhiyxHS80ki5QApv9AShXlt3LRM41SJSCuv71Z30kGIVV6Itoo
|
||||
+rtjllrh9TBA==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 3);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -1);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::EXPIRED);
|
||||
}
|
||||
|
||||
void test_check_site_license()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: unlimited
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2021-Dec-10
|
||||
-
|
||||
$9$AQAKM0lWahp0xKiqVObgsjtpg9LNh+knuPSDbbv/6LuJqbZYA2F2
|
||||
ibdICkHLfDTIiUjqXdmLbNWbavWwcrtOnzw7zxExIyCcJPXrQxUjmRU
|
||||
kvVe+mPlN+4Re1jFBmCY18X13fb9JSShOjWGEnpCR/o6Fq1EKoOoYg1
|
||||
NyWoVDy+Jv/Tr0Zr1/xFyhQJMw3dr0LiCrmYG0+J9P4lndI7MI4QG3z
|
||||
0e625imrkJVDJsRUk3V9YXu8XxJTpSfc8tZjolzxCpaAKNzzCQeghdh
|
||||
hwAEZEqUd3+ULN6lY36laCzRSMOts6506wMMhv4wzT65h8RRrrgJJjw
|
||||
lnOALOwf+YcHvMpHWBBL18utvvxn1dWUdywBXPfmJnncglP7Cg+/B6q
|
||||
gPxec/V8S5mA==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 0);
|
||||
TS_ASSERT(license.getTimeLeft() >= 0);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(!license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::VALID);
|
||||
}
|
||||
|
||||
void test_check_site_license_expired()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: unlimited
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2018-Dec-08
|
||||
-
|
||||
$9$AQAKi2K2OESpqYwzOE6EPg5ltiYYNV3FYzGT9O/mf8fp8+ovGL5T
|
||||
aJjHkXuWYsZ71yG4SH7DKrtSKc3nSHT6eBKpxkGeQ/50KMIqbFHUNWm
|
||||
qsv7mzFeKeoA7e9Hf2X/RfWqBmHTV8eIhaE4qqMKF5DY+fG9Y1qlHEs
|
||||
oeKJCM6BaxYiPZjG4sMKG2K/6AkT4TbNaHjrBktlE1l4ad8mW1xBXn5
|
||||
p6ph0waObobOioNZINvLuRrIModAnfjCFVdKtL+HzM8Kg/2Tx7ZPCQV
|
||||
4Tvj6Jm61OiXAdgZcIoL1DYsZWqIb3HFIJQw7Q+IGsKFgh64oNwh/WP
|
||||
LZi4XroeDeOJnhX5+sfr0WZoV2BKCsNCsvKNHTtEG9ZGtKSgp8ktgBt
|
||||
XCElsg55RjkQ==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 0);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -1);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::EXPIRED);
|
||||
}
|
||||
|
||||
void test_check_test_license()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Test License
|
||||
Licensed number of users: unlimited
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2021-Dec-10
|
||||
-
|
||||
$9$AQAKrvzvSMvN038BfcgVNT8rN6/X4pFbYKpU0gMSeH62+Vsd55MC
|
||||
E6rIwc+vMlHlLzHZsn6+YpSsPX2Hs31JUpkRTAb2X2ln0SZU2mZUL/V
|
||||
SD4trO/jCUoTaC7FbaXD6F1A8DWuJos706g/MaNWyXc0tUnd3N6HSnZ
|
||||
UEX0HHQXaKatZh5imexO5NncQtdhObU9PFo0UhXTxQ9wFxrKFzgyIIl
|
||||
EQqQq4ExHzMz41wDD/476lf43W8O6tfbSRaO2aSlALy/3IqnrZBjllm
|
||||
girrswPR5tAq8JCL8hxenkajWK7plnlg4tUuvpvnj/fif/2Km5v7Xls
|
||||
+MDZZ7EC7hRX2UUHmIWAnCaiv25k/NHfu1GBQ19mS8mWYnRmxXOccAO
|
||||
qCavX9fMG6pQ==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Test License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 0);
|
||||
TS_ASSERT(license.getTimeLeft() >= 0);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(!license.isExpired());
|
||||
TS_ASSERT(license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::VALID);
|
||||
}
|
||||
|
||||
void test_check_test_license_expired()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Test License
|
||||
Licensed number of users: unlimited
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: until 2018-Dec-06
|
||||
-
|
||||
$9$AQAKML9uOsAwGbhR/GdF+idZBjBwcvYuNvym5yLvTweDEOs70IHy
|
||||
NQBPgvq3TOUPtmKc3DE1lHLB7Fe2/8VNwcg1hkncle9fKh44WGuNIRX
|
||||
dFPJ40Hl+be8ekrjyKwz1x9fb85mkzheiDQUEC8QOHUUdJJoETgp3Il
|
||||
dcLDe/UL7Sq3/GpPDH+SaThMM5y+3tluf7yO/4qqRuzbV68YW/DTHEL
|
||||
47/LvlW1iAypllpeJD7igpCzUEiRYa2m2pSmpOiS0FoXaZ0jhr0LNXm
|
||||
C6/zLqHZ4xRnUmhDlmTf1mfybi86xOiPeZFfvSVnv5HPtf5Nsk2wGkW
|
||||
pwim1/hpoCxGJ4hiN9a3cbgnjtqG7yTbfMIiBAxM4JcHt2Dzhs3+r6d
|
||||
gabQRg1nODDw==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Test License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 0);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -1);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(license.isExpired());
|
||||
TS_ASSERT(license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::EXPIRED);
|
||||
}
|
||||
|
||||
void test_check_lifelong_license()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Jane Doe
|
||||
License type: Commercial License
|
||||
Licensed number of users: 2
|
||||
Licensed product version: unlimited
|
||||
Licensed usage period: unlimited
|
||||
-
|
||||
$9$AQAKIZaofFkJU73SLfokexujrBlm792b2tF+oQksC40P+Z8vUtgT
|
||||
hesYyYrRxFXK2OALm7zLkdeJYNwC60+oJx0wA19D6PLQo09d5Tf3hHx
|
||||
0pkdV0J+2NwidLoJX6ZHWB2KQxg1Vg0yvczZs4uzNLLd6JRdBubN3XF
|
||||
0hO9m/sYLMRzeh5sn7WJjV2M/BR1bGmgmY0itW0UXw+hYGZaViiDo1f
|
||||
7erXFcZq5TJwhYM447TjoWa+KDjPd/hCohO8SKKtJ33qWWuTfJNPL5q
|
||||
7iqyQemOnBOtW+nXHmg/89F+YXoyGeICxinnFs1kmqMey94s/08OUcB
|
||||
GSlQ649gX2BuuACmHR/JW/0SY4ik/DgkesVHuRWXD8VTq8cOBMCKjOe
|
||||
YHCqvUCFHVMA==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 2);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -2);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(!license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::VALID);
|
||||
}
|
||||
|
||||
void test_check_long_name()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
License holder: Janestanasolinaria Doestopolstiminikovasotanibanastovic
|
||||
License type: Commercial License
|
||||
Licensed number of users: 2
|
||||
Licensed product version: up to 2023.4
|
||||
Licensed usage period: unlimited
|
||||
-
|
||||
$9$AQAKD2gin+JhXldRL5AkVpoTgNHibszdfWpKSgm+p5zC5wCYiGWd
|
||||
Vtd8nzkj4Gys3liNW5K1Yu/bfgcoOwjBOh6ZpNXCs9MQaNtfHTNeNXA
|
||||
6vKwBCyrKruO1Ez1y+63pYN+erVtrxIpy6bTxuSIuD115j++V7sDE6f
|
||||
oMCTYVAtMoPBxkIDrMB/dRDVu+ZPffAtPl9qA/1Okl697UpFLIC5kOP
|
||||
YoJmSgwXC0k0lOvF7OyzR95oKUjQifdWgnEH5kpPJ3DqcKsAvSh0bQj
|
||||
Rmk10RSZo1OmjgYEssKlD04BZMWsgKEeNHVAkovY6mxR4160wOuELxP
|
||||
Y8odKqEzRcdV/ZWysqZEGPpdeBIqeBd4ZVgN6kEDZqpGktGZL0LThEB
|
||||
Muf9wa0CwXuw==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Janestanasolinaria Doestopolstiminikovasotanibanastovic");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 2);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -2);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(!license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::VALID);
|
||||
}
|
||||
|
||||
void test_check_old_format_license()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
Licensed to: Jane Doe
|
||||
License type: Commercial License (5 users)
|
||||
Valid up to version: 2020.2
|
||||
-
|
||||
$9$AQAKDowaE3jU5qows5JQrqt6iEfM+BKO0uCgN8lYCIAy/qUzfDsI
|
||||
S8pZMKD9fBNP0QHK1RNAaiwD8qszcnksDHcURUelnCBk2fpAd4YdR2a
|
||||
IU6CBwkPWAT92K7KE5OfWV2h2odlSTirPb99WqWYnEngibVeBA4cGZD
|
||||
k+fSpsPz3Dwg66dNUKajf+snii5wE9qa/2XYhV3gLm3Utls2jhpom31
|
||||
9Ri0uP/5b8Zx8ZWtlT5BDoS8LvVBsOtBe788DSmmF+7hA8xLel+VRvt
|
||||
mNzs/MWbKg+m0JrIdwaqhDlx+Fpc+rlhb0uWTJxKO2ruRkLcXkZ4ZbS
|
||||
fnOHl2FZZgsRjnT0AbI9hHNf3clXuJsu85ymGa9ZESBvKRmYWvjpdcs
|
||||
0yeCOCcxABmw==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
Version version = Version::getApplicationVersion();
|
||||
Version::setApplicationVersion(Version(2019, 1, 11, "asdfasdf"));
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 5);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -2);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(!license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::VALID);
|
||||
|
||||
Version::setApplicationVersion(version);
|
||||
}
|
||||
|
||||
void test_check_old_format_license_expired()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
Licensed to: Jane Doe
|
||||
License type: Commercial License (3 users)
|
||||
Valid up to version: 2018.1
|
||||
-
|
||||
$9$AQAK2j5OkBlxfT/3y0XTbMUu/tRchYJxfD1dHgSFXJMXeFPN9h1N
|
||||
RVewaFTRWub12WkRSq4rHaEt6MKZCtO3ntj8bGJxuvH4ggridXBoJjP
|
||||
nkHGPMlUvrdbhs/O7uaWvVXf+n7YrZPxeBBdHiXEUI2AaNbig5FzCeS
|
||||
Gt31yDkLjSkNwdR4zJGoAB2zWfhxFLIzBXv6z+rToBy71hzMbRHnUX2
|
||||
B8zkBAt12QVCZszbV1XJ8LqOhxkGKdo6RsieBc5s2HJB16IFf0gcxkL
|
||||
2FRzN6wMlTqs4K4pk8+kxwzB+Ywm+griLgzZo1jbg0JUm4Ou9nppaht
|
||||
m4mgTH3FBGtob6Spi7H8hGNGgrT1gRmnHLyomwPfKXKuO/snvK3CZCB
|
||||
yBAHSwjidKqg==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
Version version = Version::getApplicationVersion();
|
||||
Version::setApplicationVersion(Version(2019, 1, 11, "asdfasdf"));
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 3);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -2);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::EXPIRED);
|
||||
|
||||
Version::setApplicationVersion(version);
|
||||
}
|
||||
|
||||
void test_check_one_hundred_year_testimonial_license()
|
||||
{
|
||||
License license;
|
||||
bool ok = license.loadFromString(
|
||||
R"(-----BEGIN LICENSE-----
|
||||
Product: Sourcetrail
|
||||
Licensed to: Jane Doe
|
||||
License type: Commercial License (1 Seat)
|
||||
Valid up to version: 2117.2
|
||||
-
|
||||
$9$AQAKhOnW2QeCuuNbHLpUN7CT7DE/FRuOvEOEcHDNOn7yGs0CUIMS
|
||||
Ox9zCpz0xH/XsNmL6NTyS3P4DOm9snvaJZM90ttr3nxy4Dv3IRWVXvg
|
||||
OsvwbkYYC+N2WUKJ+ahk8zU7Uz179tdX2FLbce6/xcOi8Utv3thWWWs
|
||||
EbV62Ja3DS7Qt9Oq7ui+9PrpvPmsc81yK5g993vOsZkPuOuoE8KNX1m
|
||||
Dhl9UxaBZfmfQVtiAWx1vP8zCJ4nnANgfAAKPBXfYyuvf8/+GDC7CLo
|
||||
9e5e0swhcMt0z0DfKdwR59sQPZnXSZyouW5GzTUi2E8nw5IStxi3/GX
|
||||
z3TR0g8ERzP07KrzdYklfYv+cxtlev/H869p0USn5kPBwW8+ZFX+5Id
|
||||
8CVzujNAz//w==
|
||||
-----END LICENSE-----)"
|
||||
);
|
||||
|
||||
Version version = Version::getApplicationVersion();
|
||||
Version::setApplicationVersion(Version(2019, 1, 11, "asdfasdf"));
|
||||
|
||||
TS_ASSERT(ok);
|
||||
TS_ASSERT_EQUALS(license.getUser(), "Jane Doe");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Commercial License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 1);
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -2);
|
||||
TS_ASSERT(license.isComplete());
|
||||
TS_ASSERT(!license.isEmpty());
|
||||
TS_ASSERT(!license.isExpired());
|
||||
TS_ASSERT(!license.isTestLicense());
|
||||
|
||||
LicenseChecker::loadPublicKey();
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(license), LicenseChecker::LicenseState::VALID);
|
||||
|
||||
Version::setApplicationVersion(version);
|
||||
}
|
||||
};
|
||||
@@ -1,16 +1,17 @@
|
||||
#include <cxxtest/TestSuite.h>
|
||||
|
||||
#include "License.h"
|
||||
#include "Generator.h"
|
||||
#include "LicenseChecker.h"
|
||||
#include "LicenseGenerator.h"
|
||||
|
||||
class GeneratorTestSuite : public CxxTest::TestSuite
|
||||
class LicenseGeneratorTestSuite : public CxxTest::TestSuite
|
||||
{
|
||||
public:
|
||||
|
||||
void test_create_Keys_with_Version_and_check()
|
||||
{
|
||||
Generator generator;
|
||||
generator.generateKeys();
|
||||
LicenseGenerator generator;
|
||||
generator.generatePrivateKey();
|
||||
|
||||
std::string privateKey = generator.getPrivateKeyPEMFileAsString();
|
||||
std::string publicKey = generator.getPublicKeyPEMFileAsString();
|
||||
@@ -24,16 +25,15 @@ public:
|
||||
|
||||
void test_load_private_Key_from_file()
|
||||
{
|
||||
Generator generator;
|
||||
generator.setCustomPrivateKeyFile("./data/GeneratorTestSuite/private-v2.pem");
|
||||
bool ok = generator.loadPrivateKeyFromFile();
|
||||
LicenseGenerator generator;
|
||||
bool ok = generator.loadPrivateKeyFromFile("./data/LicenseGeneratorTestSuite/private-v2.pem");
|
||||
|
||||
TS_ASSERT(ok);
|
||||
}
|
||||
|
||||
void test_load_private_key_from_string()
|
||||
{
|
||||
Generator generator;
|
||||
LicenseGenerator generator;
|
||||
bool ok = generator.loadPrivateKeyFromString(m_privateKey);
|
||||
|
||||
TS_ASSERT(ok);
|
||||
@@ -41,71 +41,83 @@ public:
|
||||
|
||||
void test_create_volume_license_and_validate()
|
||||
{
|
||||
Generator generator;
|
||||
generator.generateKeys();
|
||||
generator.loadPrivateKeyFromString(generator.getPrivateKeyPEMFileAsString());
|
||||
LicenseGenerator generator;
|
||||
generator.generatePrivateKey();
|
||||
|
||||
License license;
|
||||
license.loadFromString(generator.encodeLicenseByQuarters("TestUser", "VolumeLicense", 20, 4));
|
||||
std::unique_ptr<License> license = generator.createLicenseByQuarters("TestUser", "VolumeLicense", 20, 4);
|
||||
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 20);
|
||||
TS_ASSERT(license.get());
|
||||
TS_ASSERT_EQUALS(license->getUser(), "TestUser");
|
||||
TS_ASSERT_EQUALS(license->getType(), "VolumeLicense");
|
||||
TS_ASSERT_EQUALS(license->getNumberOfUsers(), 20);
|
||||
TS_ASSERT_EQUALS(license->isEmpty(), false);
|
||||
TS_ASSERT_EQUALS(license->isComplete(), true);
|
||||
TS_ASSERT_EQUALS(license->isExpired(), false);
|
||||
TS_ASSERT_EQUALS(license->isTestLicense(), false);
|
||||
TS_ASSERT_EQUALS(license->getTimeLeft(), -2);
|
||||
|
||||
TS_ASSERT(LicenseChecker::loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString()));
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(*license.get()), LicenseChecker::LicenseState::VALID);
|
||||
}
|
||||
|
||||
void test_create_test_license_and_validate()
|
||||
{
|
||||
Generator generator;
|
||||
generator.generateKeys();
|
||||
generator.loadPrivateKeyFromString(generator.getPrivateKeyPEMFileAsString());
|
||||
LicenseGenerator generator;
|
||||
generator.generatePrivateKey();
|
||||
|
||||
License license;
|
||||
license.loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString());
|
||||
license.loadFromString(generator.encodeLicenseByDays("User", "", 0, 10));
|
||||
std::unique_ptr<License> license = generator.createLicenseByDays("User", "", 0, 10);
|
||||
|
||||
TS_ASSERT(license.isValid());
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), 10);
|
||||
TS_ASSERT(license.get());
|
||||
TS_ASSERT_EQUALS(license->getUser(), "User");
|
||||
TS_ASSERT_EQUALS(license->getType(), "Test License");
|
||||
TS_ASSERT_EQUALS(license->getNumberOfUsers(), 0);
|
||||
TS_ASSERT_EQUALS(license->isEmpty(), false);
|
||||
TS_ASSERT_EQUALS(license->isComplete(), true);
|
||||
TS_ASSERT_EQUALS(license->isExpired(), false);
|
||||
TS_ASSERT_EQUALS(license->isTestLicense(), true);
|
||||
TS_ASSERT_EQUALS(license->getTimeLeft(), 10);
|
||||
|
||||
license.loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString());
|
||||
license.loadFromString(generator.encodeLicenseByDays("User", "", 0, -10));
|
||||
TS_ASSERT(LicenseChecker::loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString()));
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(*license.get()), LicenseChecker::LicenseState::VALID);
|
||||
|
||||
TS_ASSERT(!license.isValid());
|
||||
// -1 and not -10 since it means it is expired
|
||||
TS_ASSERT_EQUALS(license.getTimeLeft(), -1);
|
||||
license = generator.createLicenseByDays("User", "", 0, -10);
|
||||
|
||||
TS_ASSERT(license.get());
|
||||
TS_ASSERT_EQUALS(license->getUser(), "User");
|
||||
TS_ASSERT_EQUALS(license->getType(), "Test License");
|
||||
TS_ASSERT_EQUALS(license->getNumberOfUsers(), 0);
|
||||
TS_ASSERT_EQUALS(license->isEmpty(), false);
|
||||
TS_ASSERT_EQUALS(license->isComplete(), true);
|
||||
TS_ASSERT_EQUALS(license->isExpired(), true);
|
||||
TS_ASSERT_EQUALS(license->isTestLicense(), true);
|
||||
TS_ASSERT_EQUALS(license->getTimeLeft(), -1);
|
||||
TS_ASSERT_EQUALS(LicenseChecker::checkLicense(*license.get()), LicenseChecker::LicenseState::EXPIRED);
|
||||
}
|
||||
|
||||
void test_create_licenses_and_check_the_license_info()
|
||||
{
|
||||
Generator generator;
|
||||
generator.generateKeys();
|
||||
LicenseGenerator generator;
|
||||
generator.generatePrivateKey();
|
||||
|
||||
License license;
|
||||
std::unique_ptr<License> license = generator.createLicenseByVersion("TestUser", "Private License", 1, "2017.4");
|
||||
std::string testInfo = "TestUser\nPrivate License\n1 user\nvalid up to version 2017.4";
|
||||
TS_ASSERT(license.get());
|
||||
TS_ASSERT_EQUALS(license->getLicenseInfo(), testInfo);
|
||||
|
||||
license.loadFromString(generator.encodeLicenseByVersion("TestUser", "Private License", 1, "2017.4"));
|
||||
std::string testInfo = "TestUser\nPrivate License\n1 user\nvalid up to version: 2017.4";
|
||||
TS_ASSERT_EQUALS(license.getLicenseInfo(), testInfo);
|
||||
license = generator.createLicenseByVersion("TestUser", "Volume License", 20, "2017.3");
|
||||
testInfo = "TestUser\nVolume License\n20 users\nvalid up to version 2017.3";
|
||||
TS_ASSERT(license.get());
|
||||
TS_ASSERT_EQUALS(license->getLicenseInfo(), testInfo);
|
||||
|
||||
license.loadFromString(generator.encodeLicenseByVersion("TestUser", "Volume License", 20, "2017.3"));
|
||||
testInfo = "TestUser\nVolume License\n20 users\nvalid up to version: 2017.3";
|
||||
TS_ASSERT_EQUALS(license.getLicenseInfo(), testInfo);
|
||||
license = generator.createLicenseByVersion("TestUser", "Volume License", 0, "2018.3");
|
||||
testInfo = "TestUser\nVolume License\nunlimited users\nvalid up to version 2018.3";
|
||||
TS_ASSERT(license.get());
|
||||
TS_ASSERT_EQUALS(license->getLicenseInfo(), testInfo);
|
||||
|
||||
license.loadFromString(generator.encodeLicenseByVersion("TestUser", "Private/Academic Single User License", 0, "2018.1"));
|
||||
testInfo = "TestUser\nPrivate/Academic Single User License\nnot registered for commercial development\nvalid up to version: 2018.1";
|
||||
TS_ASSERT_EQUALS(license.getLicenseInfo(), testInfo);
|
||||
}
|
||||
|
||||
void test_create_license_and_validate()
|
||||
{
|
||||
Generator generator;
|
||||
generator.generateKeys();
|
||||
|
||||
generator.loadPrivateKeyFromString(generator.getPrivateKeyPEMFileAsString());
|
||||
License license;
|
||||
license.loadFromString(generator.encodeLicenseByVersion("TestUser", "Private License", 20, "2017.3"));
|
||||
license.loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString());
|
||||
|
||||
TS_ASSERT_EQUALS(license.getUser(), "TestUser");
|
||||
TS_ASSERT_EQUALS(license.getType(), "Private License");
|
||||
TS_ASSERT_EQUALS(license.getNumberOfUsers(), 20);
|
||||
TS_ASSERT(license.isValid());
|
||||
license = generator.createLicenseLifelong("TestUser", "Volume License", 1);
|
||||
testInfo = "TestUser\nVolume License\n1 user\nvalid perpetually";
|
||||
TS_ASSERT(license.get());
|
||||
TS_ASSERT_EQUALS(license->getLicenseInfo(), testInfo);
|
||||
}
|
||||
|
||||
private:
|
||||
Reference in New Issue
Block a user