From 19ed6cb3729d4ebdff28428a4cb0290d4896e1aa Mon Sep 17 00:00:00 2001 From: Andreas Stallinger Date: Mon, 12 Jun 2017 09:14:21 +0200 Subject: [PATCH] logic: versioning --- .gitlab-ci.yml | 3 +- CMakeLists.txt | 19 +- cmake/PrivateKey.h.in | 10 + cmake/PublicKey.h.in | 2 +- ...LinuxPackage.cmake => linux_package.cmake} | 0 cmake/private_key.cmake | 22 ++ cmake/{publicKey.cmake => public_key.cmake} | 16 +- cmake/version.cmake | 13 +- cmake/version.h.in | 3 + setup/RSA_keys/private-sourcetrail.pem | 30 ++ setup/RSA_keys/public-sourcetrail.pem | 9 + setup/license.txt | 22 +- src/app/main.cpp | 10 +- src/lib/CMakeLists.txt | 2 - src/lib/LicenseChecker.cpp | 2 +- src/lib/utility/Version.cpp | 84 ----- .../utility/commandline/CommandLineParser.cpp | 2 +- src/lib/utility/utilityUuid.h | 2 +- src/lib_license/CMakeLists.txt | 5 +- src/lib_license/License.cpp | 327 +++++------------- src/lib_license/License.h | 46 ++- src/lib_license/utility/Version.cpp | 104 ++++++ src/{lib => lib_license}/utility/Version.h | 12 +- src/license_generator/CMakeLists.txt | 8 + .../Generator.cpp | 126 +++++-- .../Generator.h | 35 +- src/license_generator/main.cpp | 29 +- src/test/GeneratorTestSuite.h | 46 +-- 28 files changed, 536 insertions(+), 453 deletions(-) create mode 100644 cmake/PrivateKey.h.in rename cmake/{LinuxPackage.cmake => linux_package.cmake} (100%) create mode 100644 cmake/private_key.cmake rename cmake/{publicKey.cmake => public_key.cmake} (51%) create mode 100644 setup/RSA_keys/private-sourcetrail.pem create mode 100644 setup/RSA_keys/public-sourcetrail.pem delete mode 100644 src/lib/utility/Version.cpp create mode 100644 src/lib_license/utility/Version.cpp rename src/{lib => lib_license}/utility/Version.h (56%) rename src/{lib_license => license_generator}/Generator.cpp (56%) rename src/{lib_license => license_generator}/Generator.h (56%) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 439f739c..bc3ff391 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -50,10 +50,11 @@ Linux64_licenseGenerator: script: - ./script/setup.sh - ./script/buildonly.sh r keygen + - mv build/Release/license_generator/Sourcetrail_license_generator . artifacts: name: "$CI_JOB_NAME" paths: - - build/Release/license_generator/*_license_generator + - Sourcetrail_license_generator expire_in: 3 days Linux32: diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b65f417..ffab72b2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -106,7 +106,7 @@ elseif(UNIX AND APPLE) set(Boost_NO_SYSTEM_PATHS ON) else() STRING(REGEX REPLACE "\\\\" "/" BOOST_LIBRARYDIR ${BOOST_LIBRARYDIR}) - + if(${WINXXBITS} STREQUAL "Win32") set(BOOST_ROOT "${BOOST_LIBRARYDIR}/win32") else() @@ -402,11 +402,10 @@ configure_file( ) # configure public key for the sourcetrail version -include(cmake/publicKey.cmake) +include(cmake/public_key.cmake) set(CMAKE_AUTOMOC OFF) - # Indexer App ------------------------------------------------------------------ if (UNIX) @@ -583,6 +582,9 @@ endif () add_subdirectory(src/license_generator) +# configure private key for the sourcetrail version +include(cmake/private_key.cmake) + if (UNIX) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/license_generator/") else () @@ -592,7 +594,7 @@ else () endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) endif () -add_executable(${LICENSE_GENERATOR_PROJECT_NAME} ${LICENSE_GENERATOR_FILES}) +add_executable(${LICENSE_GENERATOR_PROJECT_NAME} ${LICENSE_GENERATOR_FILES} ${LICENSE_GENERATOR_MAIN}) create_source_groups(${LICENSE_GENERATOR_FILES}) @@ -600,6 +602,8 @@ set_property( TARGET ${LICENSE_GENERATOR_PROJECT_NAME} PROPERTY INCLUDE_DIRECTORIES "${CMAKE_SOURCE_DIR}/src/lib_license" + "${CMAKE_BINARY_DIR}/src/license_generator" + "${CMAKE_BINARY_DIR}/src/lib_license" ) target_include_directories(${LICENSE_GENERATOR_PROJECT_NAME} SYSTEM @@ -632,7 +636,7 @@ set(TESTGEN_FILE ${CMAKE_CURRENT_BINARY_DIR}/test_main.cpp) find_package(PythonInterp REQUIRED) -add_executable (${TEST_PROJECT_NAME} ${TESTGEN_FILE} ${TEST_FILES} ) +add_executable (${TEST_PROJECT_NAME} ${TESTGEN_FILE} ${TEST_FILES} ${LICENSE_GENERATOR_FILES}) create_source_groups(${TEST_FILES}) @@ -650,6 +654,9 @@ if (CXXTEST_FOUND) "${CMAKE_SOURCE_DIR}/src/lib_java" "${CMAKE_SOURCE_DIR}/src/external" "${CMAKE_SOURCE_DIR}/src/lib_license" + "${CMAKE_BINARY_DIR}/src/lib_license" + "${CMAKE_SOURCE_DIR}/src/license_generator" + "${CMAKE_BINARY_DIR}/src/license_generator" "${Boost_INCLUDE_DIRS}" ) endif (CXXTEST_FOUND) @@ -719,6 +726,6 @@ if (UNIX) ) # Linux package - include(cmake/LinuxPackage.cmake) + include(cmake/linux_package.cmake) endif () endif () diff --git a/cmake/PrivateKey.h.in b/cmake/PrivateKey.h.in new file mode 100644 index 00000000..4814520f --- /dev/null +++ b/cmake/PrivateKey.h.in @@ -0,0 +1,10 @@ +#ifndef PRIVATE_KEY_H +#define PRIVATE_KEY_H + +// This File(PrivateKey.h) is generated with CMake + +#include + +const std::string PRIVATE_KEY = "@KEY@"; + +#endif // PRIVATE_KEY_H diff --git a/cmake/PublicKey.h.in b/cmake/PublicKey.h.in index 4ffd7c7e..ba94e0a7 100644 --- a/cmake/PublicKey.h.in +++ b/cmake/PublicKey.h.in @@ -5,6 +5,6 @@ #include -static const std::string PublicKey = "@KEY@"; +const std::string PUBLIC_KEY = "@KEY@"; #endif // PUBLIC_KEY_H diff --git a/cmake/LinuxPackage.cmake b/cmake/linux_package.cmake similarity index 100% rename from cmake/LinuxPackage.cmake rename to cmake/linux_package.cmake diff --git a/cmake/private_key.cmake b/cmake/private_key.cmake new file mode 100644 index 00000000..68428b6d --- /dev/null +++ b/cmake/private_key.cmake @@ -0,0 +1,22 @@ +# searching for private key file of the Sourcetrail version in setup/RSA_keys +# if found the file will be put into a const string into the PrivateKey.h file + +string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" VERSION_MAJOR "${GIT_VERSION_NUMBER}") +message(STATUS "Get Public Key for Sourcetrail version: ${VERSION_MAJOR}") + +message(STATUS "${CMAKE_SOURCE_DIR}/setup/RSA_keys/private-sourcetrail.pem") + +set(privateKeyFile "${CMAKE_SOURCE_DIR}/setup/RSA_keys/private-sourcetrail.pem") + +if(EXISTS ${privateKeyFile}) + file(READ ${privateKeyFile} KEY) + STRING(REGEX REPLACE "\"" "\\\\\"" KEY "${KEY}") + STRING(REGEX REPLACE "\n" "\\\\n\"\n\t\"" KEY "${KEY}") +else() + message(FATAL_ERROR "private keyfile for Sourcetrail not found") +endif() + +configure_file( + ${CMAKE_SOURCE_DIR}/cmake/PrivateKey.h.in + ${CMAKE_BINARY_DIR}/src/license_generator/PrivateKey.h +) diff --git a/cmake/publicKey.cmake b/cmake/public_key.cmake similarity index 51% rename from cmake/publicKey.cmake rename to cmake/public_key.cmake index 712b4507..04d2649a 100644 --- a/cmake/publicKey.cmake +++ b/cmake/public_key.cmake @@ -1,27 +1,23 @@ # searching for public key file of the Sourcetrail version in setup/RSA_keys -# if found the file will be put into a const string into the PubicKeh.h file +# if found the file will be put into a const string into the PubicKey.h file string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" VERSION_MAJOR "${GIT_VERSION_NUMBER}") message(STATUS "Get Public Key for Sourcetrail version: ${VERSION_MAJOR}") -# message(STATUS "${CMAKE_SOURCE_DIR}/setup/RSA_keys/public-${VERSION_MAJOR}.pem") -message(STATUS "${CMAKE_SOURCE_DIR}/setup/RSA_keys/public-0.pem") # explain in Readme.md how to get this to work first +message(STATUS "${CMAKE_SOURCE_DIR}/setup/RSA_keys/public-sourcetrail.pem") -# set(pubKeyFile "${CMAKE_SOURCE_DIR}/setup/RSA_keys/public-${VERSION_MAJOR}.pem") -set(pubKeyFile "${CMAKE_SOURCE_DIR}/setup/RSA_keys/public-0.pem") # explain in Readme.md how to get this to work first - -# message(STATUS "file: ${pubKeyFile}") +set(pubKeyFile "${CMAKE_SOURCE_DIR}/setup/RSA_keys/public-sourcetrail.pem") if(EXISTS ${pubKeyFile}) file(READ ${pubKeyFile} KEY) STRING(REGEX REPLACE "\"" "\\\\\"" KEY "${KEY}") STRING(REGEX REPLACE "\n" "\\\\n\"\n\t\"" KEY "${KEY}") - # message(STATUS "key: ${KEY}") else() - message(WARNING "public keyfile for this version of Sourcetrail not found") + message(FATAL_ERROR "public keyfile for Sourcetrail not found") + #message(WARNING "public keyfile for Sourcetrail not found") endif() configure_file( ${CMAKE_SOURCE_DIR}/cmake/PublicKey.h.in ${CMAKE_BINARY_DIR}/src/lib_license/PublicKey.h -) \ No newline at end of file +) diff --git a/cmake/version.cmake b/cmake/version.cmake index 140179e2..608f89ca 100644 --- a/cmake/version.cmake +++ b/cmake/version.cmake @@ -24,7 +24,7 @@ if(EXISTS "${CMAKE_SOURCE_DIR}/.git") ) execute_process( - COMMAND ${GIT_EXECUTABLE} describe --long --match "[0-9]*" --abbrev=7 HEAD + COMMAND ${GIT_EXECUTABLE} describe --long --match "[0-9]*" HEAD WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GIT_VERSION_NUMBER OUTPUT_STRIP_TRAILING_WHITESPACE @@ -37,10 +37,17 @@ else(EXISTS "${CMAKE_SOURCE_DIR}/.git") endif(EXISTS "${CMAKE_SOURCE_DIR}/.git") +string(REGEX REPLACE "^([0-9]+)\\..*" "\\1" VERSION_YEAR "${GIT_VERSION_NUMBER}") +string(REGEX REPLACE "^[0-9]+\\.([0-9]+).*" "\\1" VERSION_MINOR "${GIT_VERSION_NUMBER}") +string(REGEX REPLACE "^[0-9]+\\.[0-9]+-([0-9]+).*" "\\1" VERSION_COMMIT "${GIT_VERSION_NUMBER}") + message(STATUS "Git current branch: ${GIT_BRANCH}") -message(STATUS "Git commit hash: ${GIT_COMMIT_HASH}") -message(STATUS "Git commit time: ${GIT_COMMIT_TIME}") message(STATUS "Git version number: " ${GIT_VERSION_NUMBER} ) +message(STATUS "Git commit hash: ${GIT_COMMIT_HASH}") +message(STATUS "Version year: ${VERSION_YEAR}") +message(STATUS "Version minor: ${VERSION_MINOR}") +message(STATUS "Version commit: ${VERSION_COMMIT}") +message(STATUS "Git commit time: ${GIT_COMMIT_TIME}") configure_file( ${CMAKE_SOURCE_DIR}/cmake/version.h.in diff --git a/cmake/version.h.in b/cmake/version.h.in index 50b17aac..8705cb61 100644 --- a/cmake/version.h.in +++ b/cmake/version.h.in @@ -5,5 +5,8 @@ #define GIT_VERSION_NUMBER "@GIT_VERSION_NUMBER@" #define GIT_COMMIT_HASH "@GIT_COMMIT_HASH@" #define GIT_COMMIT_TIME "@GIT_COMMIT_TIME@" +#define VERSION_YEAR @VERSION_YEAR@ +#define VERSION_MINOR @VERSION_MINOR@ +#define VERSION_COMMIT @VERSION_COMMIT@ #endif // SOURCETRAIL_VERSION_H diff --git a/setup/RSA_keys/private-sourcetrail.pem b/setup/RSA_keys/private-sourcetrail.pem new file mode 100644 index 00000000..f27693a5 --- /dev/null +++ b/setup/RSA_keys/private-sourcetrail.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFNTBfBgkqhkiG9w0BBQ0wUjAxBgkqhkiG9w0BBQwwJAQMaL23TLlJPBcUKzOV +AgMDNFACASAwDAYIKoZIhvcNAgkFADAdBglghkgBZQMEASoEEGE6+JCRFOJ3gax9 +foofctUEggTQe8MrLN9r4JI+HyQbB1LgERCohoWW0DKhFaK56nnlWtG5mPJksGeF +F5jw2qwTgiHkDXR8swCqLpJbHQII0cAJ0XYrso7opAwdtSrUQTZ1v6PUdR50pgND ++UzbdRbcp/TLfPfpgYGU4484S0WoHWeP9AbeSs1s8244U36MZTfkQck18psH/c0+ +lnxJHsUurLuclEhlql5bTaIkslEc6bhiWWBH9hvY+o1wRDpoOtAmgn25UsFb7FSJ +PIjDBSJZe9tJPfuuQ8ltvtzz/eo03UJU0BNBalK5dibOoACCi9EGObFn8812DSOb +0ZqBafsNCRwavkdOMVJ9GwMfhTJROhz9d9/CTxeFjVzpE0d+UJ1zbGXQDUYswsvG +pA2udPvWVi8Sd8at1Mob47UXRkf5PLRXFNmcEwTE4Ui9maYGhA/KnhSPQq9cn2CF +HRBgOwRJFR7f4E7BVgAUs6WCrsCL/RhTjnR3dwKAgO/QehVFMd3T9kJwijbk30un +ksjMcjWtuDsDveBuldxRMlXbN5Ia3C9vNvWN4S7SIlJ7eUb9SQDcRmcj54tu5K41 +y8mrqgl9UtX7BxwgKUGP7O9vkQLTkBExNaI5xFLKRYgF0Xzz6xfAb2BawBD2LWZF +RpXPAoOexPN7fyUSPYnMZMzboPxyD30SE8uXXf4s00ZpBlnxNhzBnpUVTxohRJUV +Y4keHadJr6rmxZ/lfWEUIvTeKdVJdmfrExbGAnyEWUxUtZ/N5e1ufgPGy7V8ZuR3 +7ghotzx6HJYTajFD8VRbmJ1tIT5C/O2wEqg/yka8b7cQ8xoul8CPyQJ/hVSy9RXV +1q4Epc/oQ0dkuLb1oCRbgdJncOR02JnWniRrq8sn+yv8qgoxqtjAL4ng3nry4MWT +oo17kjXCEq/mAKHdXLX/dGIA4nGAyQC8xumpMKIiOUHXUJkiAfAjZXkocNu0UXxS +VW9aK9MOJjT1g2cYlo9Az1MJtfeOlsEx6oxRpVE8OyfUPa4tUzPMpE8zG6xiFpEw +v7cdAj8M9g+iMA5E6UkcA9gGw95wnkvif0AZUWWWXVQxNBelHB43yfvZ7hzANo2S +MOPbwDJOwrHFX//dFZJeaYT8voNpnznFlbNcg2LqD6N5l+pQzpDnA+MQ/XgBoL7c +4TRsUtIyvXEMFYV/3O9hIEr6GwvjbzOQdEIZfvWbGYV6KnmOnCD+rq10AlBbjmAC +8C2TS0R5nPUH/SWPSp2m6+GmO1xj/reAkvQvPgWyzDoOTfuLOm0B21esn5txvN/C +wAnTq0RvpnUi/gDnoX4H2lkks2YoU+1v1TKVLG0x+YbV0VH9g0EngGF4PsAV7/qN +yf8uBwJKPXPz43SF1GJNN6RcQftYAVbb0TqNMljGNh2fgY3N3echMIAOxHgis98f +/QBjYWA7GEc8WkI+EHVAdqMb4l7zI36tsPAg7sUiF2EXZVN9P9aTwkmc71NNUnt5 +x563kqnv0MFCOAZpq6zq+j7BVxUr6wJDO1Tzot4HfhKbiDeMPvkHUFQJep3UaVLk +fAYFD1I1fRZOufUBLcL01KD5RY9QbNI0ouUkQhpTZlDJsA8hSvOlQJyF54hJSkt3 +BDAkUNz0dqt4kag4GKXN89GOv5fEEMZSkedRBYY5VmwrI+4i6yuXHx0= +-----END ENCRYPTED PRIVATE KEY----- diff --git a/setup/RSA_keys/public-sourcetrail.pem b/setup/RSA_keys/public-sourcetrail.pem new file mode 100644 index 00000000..ed42a70c --- /dev/null +++ b/setup/RSA_keys/public-sourcetrail.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArAldN+gG7p94WgnKH2Wq +XOOqYUcyGUB7GQY66DINxGoZVR9wkawxqGHEOvBaG7Zc469m/0Ox8sCNIt8oGywe +le0XdyGnVwJdq02lDp4lLYur3jq15BsApsQCqcOG9zkBX0v9sQhKVxVY5+m0B4v4 +9i2kHB81k6A2yWvSduoswrBbCsUfAqRmcXwCwT1O6LKN6XRzuzKXXq440fOhZiGX +1MkkVTkVMDB/J3uSl63ZkeQIqKTA6mH6qiX0x+xF8VAEwMf/ZvxWtP3S1Ryxbszb +MrK/qJfc8Bzp+gJtM36ZgXFMNXL0DshdnI0qXh1+7P6UKekSUEvlbAi/UPnGGYwq +8wIDAQAB +-----END PUBLIC KEY----- diff --git a/setup/license.txt b/setup/license.txt index 7e903174..cdfbc7cc 100644 --- a/setup/license.txt +++ b/setup/license.txt @@ -1,13 +1,15 @@ -----BEGIN LICENSE----- builder -builder license -Coati 0 -$9$AQAKIJ1UwEq5cZQujDjiHaO9R7B/KN9a6JVxppbOcZ4VSvEFRlSn -hBa0BMnyCdcL95VDSSC13m+BC/GTxweqaR2lBrF6NzVlIDeCjhBGv80 -L5SBw8yaNRx9LOZAnwGWw2IG7lclSuraqECIqVE3o2ooFC4xSg9KC6F -4Xqq2Fw8rtPCJ3HwkLZzhMhQg208cdLlyOPXL/dPa1AqZiIar4cnF/0 -sJDjxpk5C8CvpD4dq0JOs6Xs6KF8Uc7Gwp0UfnwQ0nlOl8TL63ukb8T -/70Rmzm5cnwM4iz+BdzfCVnhBgyLwCzJe+/5dF4KlVJxiW/f0GinsmU -byuZAQUqcCuVSxZXHBthmsLCN9ZWeAsR+Xvv9WRCs018nuk67BnZ5Aq -sdDRu0Q4GBEg== +Sourcetrail +BuildingLicense +Valid until 2020.1 +- +$9$AQAKttB/yiIxt1mfkCY8m/k2g8SgiiC23v2BnavARxJf6g1py6lJ +oYqmp8TK/6ThpE1eNESel+MxBZ5mExT1zp3265FSpUlhI2fsxbxjWvz +KJsVSGXgv95A/q2K/dQRjtfGuInsujs+FdqyWh18YAF5NRm/PsKQtvj +J7d6sKNi23LWEBm4WRhYVYweu0T+GAzyMhOQdx9RvEZnjEYKTUZoy2E +fm+El5WO4kx0Q2SHt+yVz9+SBJCWymGu9eb5R6YIZV/aIdhTd+jqhOR +N94H0BKZ7L+4kmhPlarR98caQWrrCla9z9tv5B80LyhpgFiTEfHTsag +3CLI0S9Ez0iqi/d9uGQ0y7UbVZr2CFvnLJ4W8FLRuIqyF7esfgSx7IZ +GFsQa/6uNHVA== -----END LICENSE----- diff --git a/src/app/main.cpp b/src/app/main.cpp index 78dbb9fe..2e1c84dc 100644 --- a/src/app/main.cpp +++ b/src/app/main.cpp @@ -132,7 +132,15 @@ int main(int argc, char *argv[]) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true); } - Version version = Version::fromString(GIT_VERSION_NUMBER); + Version version( + // TODO: replace hard coded version +// VERSION_YEAR, +// VERSION_MINOR, + 2017, + 2, + VERSION_COMMIT, + GIT_COMMIT_HASH + ); QApplication::setApplicationVersion(version.toDisplayString().c_str()); MessageStatus("Starting Sourcetrail " + version.toDisplayString()).dispatch(); diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index b7b03a92..60ff87d2 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -492,8 +492,6 @@ add_files( utility/utilityUuid.h utility/utilityXml.cpp utility/utilityXml.h - utility/Version.cpp - utility/Version.h Application.cpp Application.h diff --git a/src/lib/LicenseChecker.cpp b/src/lib/LicenseChecker.cpp index f9608c11..692dcdff 100644 --- a/src/lib/LicenseChecker.cpp +++ b/src/lib/LicenseChecker.cpp @@ -166,7 +166,7 @@ void LicenseChecker::handleMessage(MessageEnteredLicense* message) LicenseChecker::LicenseState LicenseChecker::checkLicense(License& license) const { - license.loadPublicKeyFromString(PublicKey); + license.loadPublicKeyFromString(PUBLIC_KEY); if (license.isExpired()) { diff --git a/src/lib/utility/Version.cpp b/src/lib/utility/Version.cpp deleted file mode 100644 index d6a2faa3..00000000 --- a/src/lib/utility/Version.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include "utility/Version.h" - -#include "utility/utilityString.h" -#include "utility/logging/logging.h" - -Version Version::s_version; - -Version Version::fromString(const std::string& versionString) -{ - Version version; - std::vector components = utility::splitToVector(versionString, '-'); - - if (components.size() != 3) - { - LOG_ERROR("Version string is invalid: " + versionString); - return version; - } - - std::vector numbers = utility::splitToVector(components[0], '.'); - if (numbers.size() > 0) - { - version.m_majorNumber = std::stoi(numbers[0]); - } - if (numbers.size() > 1) - { - version.m_minorNumber = std::stoi(numbers[1]); - } - if (numbers.size() > 2) - { - version.m_refreshNumber = std::stoi(numbers[2]); - } - - version.m_commitNumber = std::stoi(components[1]); - version.m_commitHash = components[2]; - - return version; -} - -void Version::setApplicationVersion(const Version& version) -{ - s_version = version; -} - -const Version& Version::getApplicationVersion() -{ - return s_version; -} - -Version::Version() - : m_majorNumber(0) - , m_minorNumber(0) - , m_refreshNumber(-1) - , m_commitNumber(0) -{ -} - -bool Version::isEmpty() const -{ - return m_majorNumber == 0 && m_minorNumber == 0 && m_refreshNumber == -1 && m_commitNumber == 0; -} - -std::string Version::toString() const -{ - std::stringstream ss; - ss << m_majorNumber << '.' << m_minorNumber; - if (m_refreshNumber != -1) - { - ss << '.' << m_refreshNumber; - } - ss << '-' << m_commitNumber << '-' << m_commitHash; - return ss.str(); -} - -std::string Version::toDisplayString() const -{ - std::stringstream ss; - ss << m_majorNumber << '.' << m_minorNumber; - if (m_refreshNumber != -1) - { - ss << '.' << m_refreshNumber; - } - ss << '.' << m_commitNumber; - return ss.str(); -} diff --git a/src/lib/utility/commandline/CommandLineParser.cpp b/src/lib/utility/commandline/CommandLineParser.cpp index 8cc24ac5..94aad47e 100644 --- a/src/lib/utility/commandline/CommandLineParser.cpp +++ b/src/lib/utility/commandline/CommandLineParser.cpp @@ -110,7 +110,7 @@ void CommandLineParser::processLicense(const bool isLoaded) { std::cout << "Could not load License" << std::endl; } - m_license.loadPublicKeyFromString(PublicKey); + m_license.loadPublicKeyFromString(PUBLIC_KEY); if (!m_license.isValid()) { std::cout << "License is not valid" << std::endl; diff --git a/src/lib/utility/utilityUuid.h b/src/lib/utility/utilityUuid.h index cba25e3e..f30b4dcd 100644 --- a/src/lib/utility/utilityUuid.h +++ b/src/lib/utility/utilityUuid.h @@ -9,6 +9,6 @@ namespace utility boost::uuids::uuid getUuid(); std::string uuidToString(const boost::uuids::uuid& uuid); std::string getUuidString(); -}; +} #endif // UTILITY_UUID_H diff --git a/src/lib_license/CMakeLists.txt b/src/lib_license/CMakeLists.txt index 787521b9..d5b0a5b6 100644 --- a/src/lib_license/CMakeLists.txt +++ b/src/lib_license/CMakeLists.txt @@ -1,8 +1,9 @@ add_files( LIB_LICENSE_FILES - Generator.cpp - Generator.h + utility/Version.cpp + utility/Version.h + License.cpp License.h ) diff --git a/src/lib_license/License.cpp b/src/lib_license/License.cpp index e5f49f69..2e19ec88 100644 --- a/src/lib_license/License.cpp +++ b/src/lib_license/License.cpp @@ -10,6 +10,7 @@ //#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" @@ -20,6 +21,8 @@ #include "botan/auto_rng.h" #include "botan/pbkdf.h" +#include "utility/Version.h" + namespace { std::string trimWhiteSpaces(const std::string &str) @@ -30,42 +33,31 @@ namespace } } + License::License() : m_rng(std::make_shared()) { + m_lines[BEGIN_LICENSE_LINE] = BEGIN_LICENSE; + m_lines[SOURCETRAIL_LINE] = "Sourcetrail"; + m_lines[END_LICENSE_LINE] = END_LICENSE; } License::~License() { } -std::string License::getHashLine() const -{ - if (m_lines.size() >= 5) - { - return m_lines[4]; - } - else - { - return ""; - } -} - std::string License::getMessage() const { std::string message = ""; - if (m_lines.size() >= 5) - { - for (int i = 1; i < 5; ++i) - { - message += m_lines[i]; - } - } - else - { - message = ""; - } + for (int i = OWNER_LINE; i < FIRST_SIGNATURE_LINE; ++i) + { + message += m_lines[i]; + if (m_lines[i].empty()) + { + return ""; + } + } return message; } @@ -74,9 +66,9 @@ std::string License::getSignature() const { std::string signatue = ""; - if (m_lines.size() >= 12) + if (!m_lines[LAST_SIGNATURE_LINE].empty()) { - for (int i = 5; i < 12; ++i) + for (int i = FIRST_SIGNATURE_LINE; i <= LAST_SIGNATURE_LINE; ++i) { signatue += m_lines[i]; } @@ -89,92 +81,58 @@ std::string License::getSignature() const return signatue; } -std::string License::getVersionLine() const +std::string License::getLine(LICENSE_LINE line) const { - if (m_lines.size() >= 3) - { - return m_lines[3]; - } - else - { - return ""; - } + return m_lines[line]; } -std::string License::getOwnerLine() const +void License::setLine(const LICENSE_LINE line, const std::string& value) { - if (m_lines.size() >= 1) - { - return m_lines[1]; - } - else - { - return ""; - } + // only allow to set message lines + if (line < FIRST_SIGNATURE_LINE) + { + m_lines[line] = value; + } } -std::string License::getLicenseTypeLine() const +std::string License::getVersionLineWithoutPrefix() const { - if (m_lines.size() >= 2) - { - return m_lines[2]; - } - else - { - return ""; - } + return getLine(VERSION_LINE).substr(LicenseConstants::UNTIL_PREFIX.length()); } unsigned int License::getSeats() const { - std::string licenseTypeLine = getLicenseTypeLine(); - std::size_t found = licenseTypeLine.find(":"); - if (found != std::string::npos) + std::string line = getLine(SEATS_LINE); + if (!line.empty()) { - // +2 (": ") - std::stringstream seatsStream(licenseTypeLine.substr(found+2)); - int seats; - seatsStream>>seats; - return seats; + try + { + return std::stoi(line); + } + catch (std::invalid_argument e) + { + return 0; + } } return 0; } -std::string License::getLicenseType() const -{ - std::string licenseTypeLine = getLicenseTypeLine(); - std::size_t found = licenseTypeLine.find(":"); - if (found != licenseTypeLine.npos) - { - return licenseTypeLine.substr(0,found); - } - - const std::string testLicenseString = "Test License"; - found = licenseTypeLine.find(testLicenseString); - if (found != licenseTypeLine.npos) - { - return "Test License"; - } - - return licenseTypeLine; -} - std::string License::getLicenseInfo() const { - std::string info = getOwnerLine() + "\n"; + std::string info = getLine(OWNER_LINE) + "\n"; - const std::string typeString = getLicenseType(); - info += getLicenseType() + "\n"; + const std::string typeString = getLine(TYPE_LINE); + info += typeString + "\n"; + info += getLine(VERSION_LINE) + "\n"; // get info depending on license type - if (typeString == "Private/Academic Single User License") + if (isNonCommercialLicenseType(typeString)) { info += "not registered for commercial development"; } - else if (typeString == "Test License") + else if (typeString == LicenseConstants::TEST_LICENSE_STRING) { - const std::string t = "Test License - "; - info += getLicenseTypeLine().substr(t.length()) + "\nunlimited Seats"; + info += "unlimited Seats"; } else if (getSeats() > 1) { @@ -191,7 +149,9 @@ std::string License::getLicenseInfo() const bool License::isNonCommercialLicenseType(const std::string type) const { for ( const std::string nonCommercialLicenseType : NON_COMMERCIAL_LICENSE_TYPES) - { if (type == nonCommercialLicenseType) { + { + if (type == nonCommercialLicenseType) + { return true; } } @@ -200,72 +160,21 @@ bool License::isNonCommercialLicenseType(const std::string type) const int License::getTimeLeft() const { - const std::string testText = "Test License - valid till "; const std::string dateText = "YYYY-MMM-DD"; - std::string licenceType = getLicenseTypeLine(); - - if (licenceType.length() != (testText.length() + dateText.length())) - { - return -2; // well, since it's unclear what type of licence...?? - } - - if(licenceType.substr(0, testText.length()) == testText) - { - std::string dateString = licenceType.substr(testText.length(), dateText.length()); - - boost::gregorian::date expireDate( - boost::gregorian::from_simple_string(dateString)); - - boost::gregorian::date today = boost::gregorian::day_clock::local_day(); - boost::gregorian::days daysLeft = expireDate - today; - - return (daysLeft.days() < 0 ? -1 : daysLeft.days()); - } - else - { - return -2; - } -} - -void License::create( - const std::string& user, const std::string& version, - Botan::RSA_PrivateKey* privateKey, const std::string& type, const unsigned int seats) -{ - m_version = version; - if (seats > 0) + std::string dateString = getVersionLineWithoutPrefix(); + if (dateString.length() != dateText.length()) { - createMessage(user, version, type + ": " + std::to_string(seats) + " seats"); - } - else - { - createMessage(user, version, type); + return -2; } - //encode message - Botan::PK_Signer signer(*privateKey, *(m_rng.get()), "EMSA4(SHA-256)"); - Botan::DataSource_Memory in(getMessage()); - Botan::byte buffer[4096] = {0}; + boost::gregorian::date expireDate( + boost::gregorian::from_simple_string(dateString)); - while (size_t got = in.read(buffer, sizeof(buffer))) - { - signer.update(buffer, got); // the hell does 'got' stand for? - } + boost::gregorian::date today = boost::gregorian::day_clock::local_day(); + boost::gregorian::days daysLeft = expireDate - today; - std::string signature = Botan::base64_encode(signer.signature(*(m_rng.get()))); - addSignature(signature); -} - -void License::createMessage(const std::string& user, const std::string& version, const std::string& type) -{ - m_lines.clear(); - m_lines.push_back(BEGIN_LICENSE); - m_lines.push_back(user); - m_lines.push_back(type); - std::string versionstring = "Sourcetrail " + getVersion(); - m_lines.push_back(versionstring); - std::string pass9 = Botan::generate_passhash9(versionstring, *(m_rng.get())); - m_lines.push_back(pass9); + return (daysLeft.days() < 0 ? -1 : daysLeft.days()); } void License::writeToFile(const std::string& filename) @@ -279,23 +188,27 @@ void License::writeToFile(const std::string& filename) bool License::loadFromString(const std::string& licenseText) { - m_lines.clear(); std::istringstream license(licenseText); return load(license); } bool License::load(std::istream& stream) { - m_lines.clear(); + int currentLine = 1; std::string line; - while (getline(stream, line, '\n')) + while (getline(stream, line, '\n') && currentLine < END_LICENSE_LINE) { - std::string l = trimWhiteSpaces(line); - if (l.size()) + std::string l = trimWhiteSpaces(line); + if (l == BEGIN_LICENSE) + { + continue; + } + if (l.size()) { - m_lines.push_back(l); + m_lines[currentLine] = l; } + currentLine++; } if (m_lines.size() <= 0) @@ -304,29 +217,11 @@ bool License::load(std::istream& stream) return false; } - if (m_lines.front() != BEGIN_LICENSE) - { - std::cout << "No License Header" << std::endl; - m_lines.insert(m_lines.begin(), BEGIN_LICENSE); - } - - if (m_lines.back() != END_LICENSE) - { - std::cout << "No License Footer" << std::endl; - m_lines.push_back(END_LICENSE); - } - - if (m_lines.size() != 13) - { - return false; - } - return true; } bool License::loadFromFile(const std::string& filename) { - m_lines.clear(); std::ifstream sigfile(filename); return load(sigfile); } @@ -336,34 +231,6 @@ void License::print() std::cout << getLicenseString(); } -void License::addSignature(const std::string& signature) -{ - if(m_lines.size() > 5) - { - std::cout << "signature already there" << std::endl; - return; - } - if (signature.size() <= 0) - { - std::cout << "signature is empty." << std::endl; - return; - } - std::stringstream ss; - - const int lineLength = 55; - for (size_t i = 0; i < signature.size(); i++) - { - if(i % lineLength == 0 && i != 0) - { - m_lines.push_back(ss.str()); - ss.str(""); - } - ss << signature[i]; - } - - m_lines.push_back(ss.str()); - m_lines.push_back(END_LICENSE); // why is this done here? the function name indicates only adding of signature -} bool License::isValid() const { @@ -372,15 +239,8 @@ bool License::isValid() const std::cout << "No public key loaded" << std::endl; return false; } - try // lol, now we try to handle errors? + try { - // remove "Coati " in version 1 - if(!(Botan::check_passhash9("Coati "+ getVersion(), getHashLine()) - || Botan::check_passhash9("Sourcetrail " + getVersion(), getHashLine()))) - { - std::cout << "Wrong license version" << std::endl; - return false; - } std::string signatureString = getSignature(); if (signatureString.size() <= 0) @@ -422,42 +282,27 @@ bool License::isValid() const bool License::isExpired() const { - return (getTimeLeft()==-1); + std::string expire = getVersionLineWithoutPrefix(); + if ( getLine(TYPE_LINE) == LicenseConstants::TEST_LICENSE_STRING) + { + return (getTimeLeft()==-1); + } + else + { + Version version = Version::fromShortString(expire); + return Version::getApplicationVersion() > version; + } } std::string License::getPublicKeyFilename() const { if(m_publicKeyFilename.empty()) { - return "public-" + getVersion() + KEY_FILEENDING; + return "public-sourcetrail" + KEY_FILEENDING; } return m_publicKeyFilename; } -std::string License::getVersion() const -{ - if(m_version.empty()) - { - - std::string line = getVersionLine(); - - //TODO: remove "Coati " in version 1 - const std::array appNames = {{ "Coati ", "Sourcetrail " }}; - - for ( std::string appName : appNames) - { - if (line.substr(0,appName.length()) == appName) - { - return line.substr(appName.length()); - } - } - - return "x"; - } - return m_version; -} - - bool License::loadPublicKeyFromFile(const std::string& filename) { if (!filename.empty()) @@ -638,3 +483,21 @@ std::string License::getEncodeKey(const std::string applicationLocation) const Botan::AutoSeeded_RNG rng; return pbkdf->derive_key(32, applicationLocation, &salt[0], salt.size(), 10000).as_string(); } + +void License::setSignature(const std::string& signature) +{ + std::stringstream ss; + int line = FIRST_SIGNATURE_LINE; + const int lineLength = 55; + for (size_t i = 0; i < signature.size(); i++) + { + if(i % lineLength == 0 && i != 0) + { + m_lines[line++] = ss.str(); + ss.str(""); + } + ss << signature[i]; + } + + m_lines[line] = ss.str(); +} diff --git a/src/lib_license/License.h b/src/lib_license/License.h index 9cb353fb..032c9744 100644 --- a/src/lib_license/License.h +++ b/src/lib_license/License.h @@ -4,6 +4,7 @@ #include #include #include +#include namespace Botan { @@ -12,19 +13,39 @@ namespace Botan class AutoSeeded_RNG; } +namespace LicenseConstants { + const std::string UNTIL_PREFIX = "Valid until "; + const std::string TEST_LICENSE_STRING = "Test License"; + const int MINOR_VERSIONS_PER_YEAR = 4; +} + class License { public: + enum LICENSE_LINE + { + BEGIN_LICENSE_LINE = 0, + OWNER_LINE = 1, + SOURCETRAIL_LINE = 2, + TYPE_LINE = 3, + VERSION_LINE = 4, + SEATS_LINE=5, + HASH_LINE = 6, + FIRST_SIGNATURE_LINE = 7, + LAST_SIGNATURE_LINE = 13, + END_LICENSE_LINE = 14, + LICENSE_LINES = 15 + }; + License(); ~License(); - std::string getHashLine() const; std::string getMessage() const; std::string getSignature() const; - std::string getVersionLine() const; - std::string getOwnerLine() const; - std::string getLicenseTypeLine() const; - std::string getLicenseType() const; + std::string getVersionLineWithoutPrefix() const; + std::string getLine(LICENSE_LINE line) const; + + void setLine(const LICENSE_LINE line, const std::string& value); std::string getLicenseInfo() const; std::string getPublicKeyFilename() const; @@ -35,12 +56,6 @@ public: /// for non Test License -2 int getTimeLeft() const; - void create( - const std::string& user, const std::string& version, - Botan::RSA_PrivateKey* privateKey, const std::string& type="Private License", - const unsigned int seats = 0 - ); - std::string getLicenseString() const; std::string getLicenseEncodedString(const std::string& applicationLocation) const; std::string getHashedLicense() const; @@ -55,6 +70,7 @@ public: bool loadPublicKeyFromString(const std::string&); void setVersion(const std::string&); + void setSignature(const std::string&); bool isValid() const; bool isExpired() const; @@ -66,7 +82,8 @@ public: private: void createMessage(const std::string& user, const std::string& version, const std::string& type = 0); - void addSignature(const std::string&); + void pushTodaysVersion(); + void pushVersionLine(int year, int minorVersion); std::string getEncodeKey(const std::string applicationLocation) const; bool isNonCommercialLicenseType(const std::string type) const; @@ -74,8 +91,9 @@ private: std::string m_version; std::string m_publicKeyFilename; std::shared_ptr m_publicKey; - std::vector m_lines; - std::shared_ptr m_rng; // range? +// std::vector m_lines; + std::array m_lines; + std::shared_ptr m_rng; const std::string KEY_FILEENDING = ".pem"; const std::string BEGIN_LICENSE = "-----BEGIN LICENSE-----"; diff --git a/src/lib_license/utility/Version.cpp b/src/lib_license/utility/Version.cpp new file mode 100644 index 00000000..6e115d1e --- /dev/null +++ b/src/lib_license/utility/Version.cpp @@ -0,0 +1,104 @@ +#include "utility/Version.h" + +#include + +// since there are 4 version per year it is on digit +const int MINOR_VERSION_SHIFT = 10; + +Version Version::s_version; + +#include +Version Version::fromShortString(const std::string& versionString) +{ + Version version; + if (versionString.length() != 6 || versionString[4] != '.') + { + return version; + } + + try + { + version.m_year = std::stoi(versionString.substr(0,4)); + version.m_minorNumber = std::stoi(versionString.substr(5)); + } + catch (std::invalid_argument e) + { + return Version(); + } + + return version; +} + +bool Version::operator<(const Version& other) const +{ + return (m_year * MINOR_VERSION_SHIFT + m_minorNumber) < (other.m_year * MINOR_VERSION_SHIFT + other.m_minorNumber); +} + +bool Version::operator>(const Version& other) const +{ + return (m_year * MINOR_VERSION_SHIFT + m_minorNumber) > (other.m_year * MINOR_VERSION_SHIFT + other.m_minorNumber); +} + +Version& Version::operator +=(const int& number) +{ + int minor = this->m_minorNumber - 1 + number; + this->m_year += minor/4; + this->m_minorNumber = (minor%4) + 1; + return *this; +} + +bool Version::isValid() +{ + if (m_minorNumber < 5 && m_minorNumber > 0 + && m_year > 2016) + { + return true; + } + return false; +} + +void Version::setApplicationVersion(const Version& version) +{ + s_version = version; +} + +const Version& Version::getApplicationVersion() +{ + return s_version; +} + +Version::Version(int year, int minor, int commit, const std::string& hash) + : m_year(year) + , m_minorNumber(minor) + , m_commitNumber(commit) + , m_commitHash(hash) +{ +} + +bool Version::isEmpty() const +{ + return m_year == 0 && m_minorNumber == 0 && m_commitNumber == 0; +} + +std::string Version::toShortString() const +{ + std::stringstream ss; + ss << m_year << '.' << m_minorNumber; + return ss.str(); +} + +std::string Version::toString() const +{ + std::stringstream ss; + ss << m_year << '.' << m_minorNumber; + ss << '-' << m_commitNumber << '-' << m_commitHash; + return ss.str(); +} + +std::string Version::toDisplayString() const +{ + std::stringstream ss; + ss << m_year << '.' << m_minorNumber; + ss << '.' << m_commitNumber; + return ss.str(); +} diff --git a/src/lib/utility/Version.h b/src/lib_license/utility/Version.h similarity index 56% rename from src/lib/utility/Version.h rename to src/lib_license/utility/Version.h index 95c05f6b..8fe33ff4 100644 --- a/src/lib/utility/Version.h +++ b/src/lib_license/utility/Version.h @@ -3,27 +3,33 @@ #include + class Version { public: static Version fromString(const std::string& versionString); + static Version fromShortString(const std::string& versionString); static void setApplicationVersion(const Version& version); static const Version& getApplicationVersion(); - Version(); + Version(int year = 0, int minor = 0, int commit = 0, const std::string& hash = ""); bool isEmpty() const; std::string toString() const; + std::string toShortString() const; std::string toDisplayString() const; + bool operator<(const Version& other) const; + bool operator>(const Version& other) const; + Version& operator+=(const int& number); + bool isValid(); private: static Version s_version; - int m_majorNumber; + int m_year; int m_minorNumber; - int m_refreshNumber; // deprecated since switch to storage_version, left for downward compatibility int m_commitNumber; std::string m_commitHash; diff --git a/src/license_generator/CMakeLists.txt b/src/license_generator/CMakeLists.txt index 94bb9ec6..18bdd1da 100644 --- a/src/license_generator/CMakeLists.txt +++ b/src/license_generator/CMakeLists.txt @@ -1,5 +1,13 @@ add_files( LICENSE_GENERATOR_FILES + Generator.cpp + Generator.h +) + +# split for tests +add_files( + LICENSE_GENERATOR_MAIN + main.cpp ) diff --git a/src/lib_license/Generator.cpp b/src/license_generator/Generator.cpp similarity index 56% rename from src/lib_license/Generator.cpp rename to src/license_generator/Generator.cpp index 8e960ec6..37256d7e 100644 --- a/src/lib_license/Generator.cpp +++ b/src/license_generator/Generator.cpp @@ -9,12 +9,25 @@ #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 "utility/Version.h" +#include "PrivateKey.h" +#include "PublicKey.h" -Generator::Generator(const std::string& version) - : m_version(version) +const std::string KEY_FILEENDING = ".pem"; +const std::string 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() @@ -23,14 +36,14 @@ Generator::~Generator() void Generator::generateKeys() { - m_privateKey = std::make_shared(m_rng, 2048); + m_privateKey = std::unique_ptr(new Botan::RSA_PrivateKey(m_rng, 2048)); } std::string Generator::getPrivateKeyFilename() { if(m_privateKeyFile.empty()) { - return "private-" + m_version + KEY_FILEENDING; + return PRIVATE_KEY_FILE; } return m_privateKeyFile; } @@ -39,31 +52,30 @@ std::string Generator::getPublicKeyFilename() { if(m_publicKeyFile.empty()) { - return "public-" + m_version + KEY_FILEENDING; + return PUBLIC_KEY_FILE; } return m_publicKeyFile; } -void Generator::setVersion(const std::string& version) -{ - if(!version.empty()) - { - m_version = version; - } -} - std::string Generator::encodeLicense(const std::string& user, const int days) { boost::gregorian::date today = boost::gregorian::day_clock::local_day(); boost::gregorian::days daysToTry(days); boost::gregorian::date expireDate = today + daysToTry; - std::string testLicenseTypeString = "Test License - valid till " + boost::gregorian::to_simple_string(expireDate); - return encodeLicense(user, testLicenseTypeString); + createLicense(user, LicenseConstants::TEST_LICENSE_STRING, boost::gregorian::to_simple_string(expireDate), 0); + + return m_license->getLicenseString(); } -std::string Generator::encodeLicense(const std::string& user, const std::string& licenseType, const int seats) +std::string Generator::encodeLicense( + const std::string& user, + const std::string& licenseType, + const int seats, + const std::string& version +) { + m_license = nullptr; if (user.size() <= 0) { std::cout << "No user given" << std::endl; @@ -76,23 +88,21 @@ std::string Generator::encodeLicense(const std::string& user, const std::string& return ""; } - //load private key - if (!m_privateKey) + if (!version.empty()) { - std::cout << "No private key. Trying to load from file." << std::endl; - loadPrivateKeyFromFile(); + Version tempVersion = Version::fromShortString(version); + if (tempVersion.isValid()) + { + createLicense(user, licenseType, tempVersion.toShortString(), seats); + } } - if (!m_privateKey) + if (!m_license) { - std::cout << "No private key. Load from file or string." << std::endl; - return ""; + createLicense(user, licenseType, getExpireVersion(), seats); } - m_license = std::make_shared(); - m_license->create(user, m_version, m_privateKey.get(), licenseType, seats); - return m_license->getLicenseString(); } @@ -113,8 +123,7 @@ bool Generator::verifyLicense(const std::string& filename) { License license; license.loadFromFile(filename); - license.setVersion(m_version); - license.loadPublicKeyFromFile(getPublicKeyFilename()); + license.loadPublicKeyFromString(PUBLIC_KEY); return license.isValid(); } @@ -194,7 +203,7 @@ bool Generator::loadPrivateKeyFromFile() return false; } - m_privateKey = std::shared_ptr(rsaKey); + m_privateKey = std::unique_ptr(rsaKey); return (m_privateKey != NULL); } @@ -217,7 +226,7 @@ bool Generator::loadPrivateKeyFromString(const std::string& key) return false; } - m_privateKey = std::shared_ptr(rsaKey); + m_privateKey = std::unique_ptr(rsaKey); return (m_privateKey != NULL); } @@ -227,3 +236,60 @@ 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, + const unsigned int seats +) +{ + m_license = std::unique_ptr(new License()); + + m_license->setLine(License::OWNER_LINE, user); + m_license->setLine(License::TYPE_LINE, type); + m_license->setLine(License::VERSION_LINE, LicenseConstants::UNTIL_PREFIX + expiration); + if (seats > 1) + { + m_license->setLine(License::SEATS_LINE, std::to_string(seats) + " Seats"); + } + else if (seats == 1) + { + m_license->setLine(License::SEATS_LINE, "1 Seat"); + } + else + { + m_license->setLine(License::SEATS_LINE, "-"); + } + Botan::AutoSeeded_RNG rng; + std::string pass9 = Botan::generate_passhash9(m_license->getLine(License::VERSION_LINE), m_rng); + m_license->setLine(License::HASH_LINE, 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 versions) +{ + boost::gregorian::date today = boost::gregorian::day_clock::local_day(); + int monthNumber = today.month().as_number(); + Version version(today.year(), mapMonthToVersion(monthNumber)); + version += versions; + return version.toShortString(); +} + diff --git a/src/lib_license/Generator.h b/src/license_generator/Generator.h similarity index 56% rename from src/lib_license/Generator.h rename to src/license_generator/Generator.h index 25c78394..01e3cfc9 100644 --- a/src/lib_license/Generator.h +++ b/src/license_generator/Generator.h @@ -2,8 +2,8 @@ #define KEYGEN_H #include +#include -//#include "botan_all.h" #include "botan/auto_rng.h" namespace Botan @@ -15,16 +15,23 @@ class License; class Generator { public: - Generator(const std::string& version = "x"); + Generator(); ~Generator(); - std::string encodeLicense(const std::string& user, const std::string& licenseType, const int seats = 0); - std::string encodeLicense(const std::string& user, const int days); + std::string encodeLicense( + const std::string& user, + const std::string& licenseType, + const int seats = 0, + const std::string& version = "" + ); + std::string encodeLicense( + const std::string& user, + const int days + ); void printLicenseAndWriteItToFile(); bool verifyLicense(const std::string& filename = "license.txt"); void generateKeys(); void writeKeysToFiles(); - void setVersion(const std::string& version); void setCustomPrivateKeyFile(const std::string& file); void setCustomPublicKeyFile(const std::string& file); @@ -33,25 +40,29 @@ public: bool loadPrivateKeyFromFile(); bool loadPrivateKeyFromString(const std::string& key); - // void PrintLicense(); // not implemented, is this deprecated or something? - Botan::RSA_PrivateKey* getPrivateKey() const; + void createLicense( + const std::string& user, + const std::string& type, + const std::string& expiration, + const unsigned int seates + ); + std::string getExpireVersion(int versions = 4); + 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_version; std::string m_privateKeyFile; std::string m_publicKeyFile; - std::shared_ptr m_license; - std::shared_ptr m_privateKey; + std::unique_ptr m_license; + std::unique_ptr m_privateKey; - const std::string PRIVATE_KEY_PASSWORD = "BA#jk5vbklAiKL9K3k$"; - const std::string KEY_FILEENDING = ".pem"; }; #endif // KEYGEN_H diff --git a/src/license_generator/main.cpp b/src/license_generator/main.cpp index 9a97fda0..12e8a7a3 100644 --- a/src/license_generator/main.cpp +++ b/src/license_generator/main.cpp @@ -6,6 +6,8 @@ #include "boost/program_options.hpp" #include "Generator.h" +#include "PrivateKey.h" +#include "PublicKey.h" namespace po = boost::program_options; @@ -28,12 +30,9 @@ bool process_command_line(int argc, char** argv) ("generate,g", po::value(&user), "Generate a License, USERNAME as value") ("check,c", "Validate a License"); - po::options_description required("Required Options"); - required.add_options() - ("version,v", po::value(&version), "Versionnumber of Sourcetrail"); - po::options_description keygen_description("Options Keygeneration"); keygen_description.add_options() + ("version,v", po::value(&version), "Versionnumber (in format 20xx.x) until Sourcetrail valid") ("seats,s", po::value(&seats), "Generate a License, USERNAME as value") ("licenseType,t", po::value(&type), "License Type of ") ("testLicense,e", po::value(&days), "Generates a test license for days"); @@ -48,11 +47,11 @@ bool process_command_line(int argc, char** argv) po::options_description desc("Sourcetrail Generator"); desc.add_options() ("help,h", "Print this help message"); - desc.add(modes_description).add(required).add(keygen_description); + desc.add(modes_description).add(keygen_description); po::options_description allDescriptions("Sourcetrail Generator"); allDescriptions.add_options(); - allDescriptions.add(modes_description).add(required).add(keygen_description).add(hidden_description); + allDescriptions.add(modes_description).add(keygen_description).add(hidden_description); po::variables_map vm; @@ -82,15 +81,7 @@ bool process_command_line(int argc, char** argv) return 1; } - // we need a version for all modes - // if no version is given there is nothing to do - if (!vm.count("version")) - { - std::cout << "No version specified" << std::endl; - return false; - } - - Generator keygen(version); + Generator keygen; // make sure there are no negative amount of seats if (vm.count("seats")) @@ -117,17 +108,21 @@ bool process_command_line(int argc, char** argv) { keygen.setCustomPrivateKeyFile(privateKeyFile); } + else + { + keygen.loadPrivateKeyFromString(PRIVATE_KEY); + } if(vm.count("generate")) { if(vm.count("testLicense")) { - keygen.encodeLicense(user,days); + keygen.encodeLicense(user,days); keygen.printLicenseAndWriteItToFile(); } else { - keygen.encodeLicense(user,type,seats); + keygen.encodeLicense(user,type,seats,version); keygen.printLicenseAndWriteItToFile(); } } diff --git a/src/test/GeneratorTestSuite.h b/src/test/GeneratorTestSuite.h index 5696eca2..2117fbdf 100644 --- a/src/test/GeneratorTestSuite.h +++ b/src/test/GeneratorTestSuite.h @@ -9,7 +9,7 @@ public: void test_create_Keys_with_Version_and_check() { - Generator generator("v0"); + Generator generator; generator.generateKeys(); std::string privateKey = generator.getPrivateKeyPEMFileAsString(); @@ -21,7 +21,7 @@ public: void test_load_private_Key_from_file() { - Generator generator("v2"); + Generator generator; generator.setCustomPrivateKeyFile("./data/GeneratorTestSuite/private-v2.pem"); bool ok = generator.loadPrivateKeyFromFile(); @@ -30,7 +30,7 @@ public: void test_load_private_key_from_string() { - Generator generator("v0"); + Generator generator; bool ok = generator.loadPrivateKeyFromString(m_privateKey); TS_ASSERT(ok); @@ -38,12 +38,14 @@ public: void test_create_volume_license_and_validate() { - Generator generator("v2"); + Generator generator; generator.generateKeys(); generator.loadPrivateKeyFromString(generator.getPrivateKeyPEMFileAsString()); - License license; - license.create("TestUser", "v2", generator.getPrivateKey(), "Volume License", 20); + License license; + license.loadFromString(generator.encodeLicense("TestUser", "VolumeLicense", 20)); + +// license.create(generator.getPrivateKey(), "TestUser", "v2", "Volume License", 20); license.loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString()); TS_ASSERT_EQUALS(license.getSeats(), 20); @@ -51,7 +53,7 @@ public: void test_create_test_license_and_validate() { - Generator generator("v2"); + Generator generator; generator.generateKeys(); generator.loadPrivateKeyFromString(generator.getPrivateKeyPEMFileAsString()); @@ -61,7 +63,7 @@ public: TS_ASSERT(license.isValid()); TS_ASSERT_EQUALS(license.getTimeLeft(), 10); - TS_ASSERT_EQUALS(license.getVersion(), "v2"); +// TS_ASSERT_EQUALS(license.getVersion(), "v2"); license.loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString()); license.loadFromString(generator.encodeLicense("User", -10)); @@ -73,39 +75,39 @@ public: void test_create_licenses_and_check_the_license_info() { - Generator generator("v2"); + Generator generator; generator.generateKeys(); - generator.loadPrivateKeyFromString(generator.getPrivateKeyPEMFileAsString()); License license; - license.loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString()); - license.create("TestUser", "v2", generator.getPrivateKey()); - std::string testInfo = "TestUser\nPrivate License\n1 Seat"; + license.loadFromString(generator.encodeLicense("TestUser", "Private License", 1, "2017.4")); +// license.create(generator.getPrivateKey(), "TestUser", "v2"); + std::string testInfo = "TestUser\nPrivate License\nValid until 2017.4\n1 Seat"; TS_ASSERT_EQUALS(license.getLicenseInfo(), testInfo); - license.create("TestUser", "v2", generator.getPrivateKey(), "Volume License", 20); - testInfo = "TestUser\nVolume License\n20 Seats"; +// license.create(generator.getPrivateKey(), "TestUser", "v2", "Volume License", 20); + license.loadFromString(generator.encodeLicense("TestUser", "Volume License", 20, "2017.3")); + testInfo = "TestUser\nVolume License\nValid until 2017.3\n20 Seats"; TS_ASSERT_EQUALS(license.getLicenseInfo(), testInfo); - license.create("TestUser", "v2", generator.getPrivateKey(), "Private/Academic Single User License", 20); - testInfo = "TestUser\nPrivate/Academic Single User License\nnot registered for commercial development"; +// license.create(generator.getPrivateKey(), "TestUser", "v2", "Private/Academic Single User License", 20); + license.loadFromString(generator.encodeLicense("TestUser", "Private/Academic Single User License", 0, "2018.1")); + testInfo = "TestUser\nPrivate/Academic Single User License\nValid until 2018.1\nnot registered for commercial development"; TS_ASSERT_EQUALS(license.getLicenseInfo(), testInfo); } void test_create_license_and_validate() { - Generator generator("v2"); + Generator generator; generator.generateKeys(); generator.loadPrivateKeyFromString(generator.getPrivateKeyPEMFileAsString()); License license; - license.create("TestUser", "v2", generator.getPrivateKey()); + license.loadFromString(generator.encodeLicense("TestUser", "Private License", 20, "2017.3")); license.loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString()); - TS_ASSERT_EQUALS(license.getOwnerLine(), "TestUser"); - TS_ASSERT_EQUALS(license.getLicenseTypeLine(), "Private License"); - TS_ASSERT_EQUALS(license.getVersion(), "v2"); + TS_ASSERT_EQUALS(license.getLine(License::OWNER_LINE), "TestUser"); + TS_ASSERT_EQUALS(license.getLine(License::TYPE_LINE), "Private License"); TS_ASSERT(license.isValid()); }