From eac48596ad7eac77422fea62823f537657ea7bd4 Mon Sep 17 00:00:00 2001 From: Andreas Stallinger Date: Mon, 27 Feb 2017 09:53:39 +0100 Subject: [PATCH] logic: Licenses with seats --- CMakeLists.txt | 2 +- src/lib_license/Generator.cpp | 4 +- src/lib_license/Generator.h | 2 +- src/lib_license/License.cpp | 31 +++++++++++- src/lib_license/License.h | 5 +- src/license_generator/main.cpp | 93 ++++++++++++++++++++++++---------- src/test/GeneratorTestSuite.h | 13 +++++ 7 files changed, 117 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d672a15d..c924f634 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -534,7 +534,7 @@ target_include_directories(${LICENSE_GENERATOR_PROJECT_NAME} SYSTEM ) if(UNIX AND NOT APPLE) - target_link_libraries(${LICENSE_GENERATOR_PROJECT_NAME} pthread dl rt) + target_link_libraries(${LICENSE_GENERATOR_PROJECT_NAME} pthread rt) endif() target_link_libraries(${LICENSE_GENERATOR_PROJECT_NAME} ${LIB_LICENSE_PROJECT_NAME} ${Boost_LIBRARIES} ) diff --git a/src/lib_license/Generator.cpp b/src/lib_license/Generator.cpp index 448a181a..d8cdb5b1 100644 --- a/src/lib_license/Generator.cpp +++ b/src/lib_license/Generator.cpp @@ -62,7 +62,7 @@ std::string Generator::encodeLicense(const std::string& user, const int days) return encodeLicense(user, testLicenseTypeString); } -std::string Generator::encodeLicense(const std::string& user, const std::string& licenseType) +std::string Generator::encodeLicense(const std::string& user, const std::string& licenseType, const int seats) { if (user.size() <= 0) { @@ -91,7 +91,7 @@ std::string Generator::encodeLicense(const std::string& user, const std::string& std::cout << "The key is not a RSA key" << std::endl; } - license.create(user, m_version, rsaKey, licenseType); + license.create(user, m_version, rsaKey, licenseType, seats); license.writeToFile("license.txt"); license.print(); diff --git a/src/lib_license/Generator.h b/src/lib_license/Generator.h index 6959b55c..5c0b9fb6 100644 --- a/src/lib_license/Generator.h +++ b/src/lib_license/Generator.h @@ -17,7 +17,7 @@ public: Generator(const std::string& version = "x"); ~Generator(); - std::string encodeLicense(const std::string& message, const std::string& licenseType); + std::string encodeLicense(const std::string& message, const std::string& licenseType, const int seats = 0); std::string encodeLicense(const std::string& message, const int days); bool verifyLicense(const std::string& filename = "license.txt"); void generateKeys(); diff --git a/src/lib_license/License.cpp b/src/lib_license/License.cpp index 6767dac9..398ef763 100644 --- a/src/lib_license/License.cpp +++ b/src/lib_license/License.cpp @@ -124,6 +124,21 @@ std::string License::getLicenseTypeLine() const } } +uint License::getSeats() const +{ + std::string licenseTypeLine = getLicenseTypeLine(); + std::size_t found = licenseTypeLine.find(":"); + if (found != std::string::npos) + { + // +2 (": ") + std::stringstream seatsStream(licenseTypeLine.substr(found+2)); + int seats; + seatsStream>>seats; + return seats; + } + return 0; +} + int License::getTimeLeft() const { const std::string testText = "Test License - valid till "; @@ -156,10 +171,17 @@ int License::getTimeLeft() const void License::create( const std::string& user, const std::string& version, - Botan::RSA_PrivateKey* privateKey, const std::string& type) + Botan::RSA_PrivateKey* privateKey, const std::string& type, const uint seats) { m_version = version; - createMessage(user, version, type); + if (seats > 0) + { + createMessage(user, version, type + ": " + std::to_string(seats) + " seats"); + } + else + { + createMessage(user, version, type); + } //encode message Botan::PK_Signer signer(*privateKey, *(m_rng.get()), "EMSA4(SHA-256)"); @@ -522,6 +544,11 @@ bool License::loadFromEncodedString(const std::string& encodedLicense, const std return true; } +std::string License::getHashedLicense() const +{ + return getEncodeKey("fakeKey"); +} + std::string License::getEncodeKey(const std::string applicationLocation) const { if (applicationLocation.size() <= 0) diff --git a/src/lib_license/License.h b/src/lib_license/License.h index 1012fe95..4b6ae641 100644 --- a/src/lib_license/License.h +++ b/src/lib_license/License.h @@ -27,6 +27,7 @@ public: std::string getPublicKeyFilename() const; std::string getVersion() const; + uint getSeats() const; /// if Test License return >=0 or -1 if expired /// for non Test License -2 @@ -34,11 +35,13 @@ public: void create( const std::string& user, const std::string& version, - Botan::RSA_PrivateKey* privateKey, const std::string& type="Private License" + Botan::RSA_PrivateKey* privateKey, const std::string& type="Private License", + const uint seats = 0 ); 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); diff --git a/src/license_generator/main.cpp b/src/license_generator/main.cpp index ad57c31e..4637bda0 100644 --- a/src/license_generator/main.cpp +++ b/src/license_generator/main.cpp @@ -15,38 +15,84 @@ bool process_command_line(int argc, char** argv) { std::string user; std::string version; - std::string privateKey; - std::string publicKey; - std::string license = ""; + std::string privateKeyFile; + std::string publicKeyFile; + std::string licenseFile = ""; std::string type = ""; int days = 0; - po::options_description desc("Coati Generator"); + int seats = 0; + po::options_description modes_description("Coati Generator Modes"); + modes_description.add_options() + ("key,k", "Generate the private and public key") + ("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 Coati"); + + po::options_description keygen_description("Options Keygeneration"); + keygen_description.add_options() + ("seats,s", po::value(&seats), "Generate a License, USERNAME as value") + ("version,v", po::value(&version), "Versionnumber of Coati") + ("licenseType,t", po::value(&type), "License Type of ") + ("testLicense,e", po::value(&days), "Generates a test license for days"); + + po::options_description hidden_description("Hidden Options"); + hidden_description.add_options() + ("public-file", po::value(&publicKeyFile), "Custom public key file") + ("private-file", po::value(&privateKeyFile), "Custom private key file") + ("license-file", po::value(&licenseFile), "Custom license") + ("hidden", "Print this help message"); + + po::options_description desc("Coati Generator"); desc.add_options() - ("help,h", "Print this help message") - ("key,k", "Generate the private and public key") - ("generate,g", po::value(&user), "Generate a License, USERNAME as value") - ("check,c", "Validate a License") - ("version,v", po::value(&version), "Versionnumber of Coati") - ("licenseType,t", po::value(&type), "License Type of ") - ("testLicense,e", po::value(&days), "Generates a test license for days") - ("public-file", po::value(&publicKey), "Custom public key file") - ("private-file", po::value(&privateKey), "Custom private key file") - ("license-file", po::value(&license), "Custom license") - ; + ("help,h", "Print this help message"); + desc.add(modes_description).add(required).add(keygen_description); + + po::options_description allDescriptions("Coati Generator"); + allDescriptions.add_options(); + allDescriptions.add(modes_description).add(required).add(keygen_description).add(hidden_description); + po::variables_map vm; po::store(po::parse_command_line(argc,argv,desc), vm); po::notify(vm); - Generator keygen(version); - - if(vm.count("help")) + // display help if no argument or the help argument is given + if (vm.count("help") || vm.size() == 0) { std::cout << desc << std::endl; return 1; } + if (vm.count("hidden")) + { + std::cout << allDescriptions << std::endl; + 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); + + // make sure there are no negative amount of seats + if (vm.count("seats")) + { + if (seats < 0) + { + std::cout << "Invalid amount of seats. (Must be > 0)" << std::endl; + return false; + } + } + if (vm.count("key")) { keygen.generateKeys(); @@ -55,28 +101,23 @@ bool process_command_line(int argc, char** argv) if (vm.count("public-file")) { - keygen.setCustomPublicKeyFile(publicKey); + keygen.setCustomPublicKeyFile(publicKeyFile); } if (vm.count("private-file")) { - keygen.setCustomPrivateKeyFile(privateKey); + keygen.setCustomPrivateKeyFile(privateKeyFile); } if(vm.count("generate")) { - if(!vm.count("version")) - { - std::cout << "Version of Coati is needed to generate a License" << std::endl; - return false; - } if(vm.count("testLicense")) { keygen.encodeLicense(user,days); } else { - keygen.encodeLicense(user,type); + keygen.encodeLicense(user,type,seats); } } diff --git a/src/test/GeneratorTestSuite.h b/src/test/GeneratorTestSuite.h index d24e6d7a..3db1704b 100644 --- a/src/test/GeneratorTestSuite.h +++ b/src/test/GeneratorTestSuite.h @@ -38,6 +38,19 @@ public: TS_ASSERT(ok); } + void test_create_volume_license_and_validate() + { + Generator generator("v2"); + generator.generateKeys(); + generator.loadPrivateKeyFromString(generator.getPrivateKeyPEMFileAsString()); + + License license; + license.create("TestUser", "v2", generator.getPrivateKey(), "Volume License", 20); + license.loadPublicKeyFromString(generator.getPublicKeyPEMFileAsString()); + + TS_ASSERT_EQUALS(license.getSeats(), 20); + } + void test_create_license_and_validate() { Generator generator("v2");