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:
Eberhard Graether
2019-03-18 14:49:52 +01:00
parent 6ff7d22641
commit b02064a160
38 changed files with 2073 additions and 1538 deletions
+81 -45
View File
@@ -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 "
+6 -4
View File
@@ -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;
};
-4
View File
@@ -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
)
-189
View File
@@ -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;
}
-37
View File
@@ -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
+2 -1
View File
@@ -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;
-24
View File
@@ -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);
-3
View File
@@ -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