From 2a452307cd00181cc95a6e9e60124f6142bf0398 Mon Sep 17 00:00:00 2001 From: "Jerry (Xinyu Hou)" Date: Thu, 13 Oct 2016 17:55:09 +0100 Subject: [PATCH] #5657 Fleshed out the implementation of SerialKey --- src/lib/shared/SerialKey.cpp | 167 ++++++++++++++++++++++++++++++++--- src/lib/shared/SerialKey.h | 35 +++++++- 2 files changed, 185 insertions(+), 17 deletions(-) diff --git a/src/lib/shared/SerialKey.cpp b/src/lib/shared/SerialKey.cpp index 2b5f6040..5f50045e 100644 --- a/src/lib/shared/SerialKey.cpp +++ b/src/lib/shared/SerialKey.cpp @@ -17,44 +17,185 @@ #include "SerialKey.h" +#include + +using namespace std; + SerialKey::SerialKey(std::string serial) : m_userLimit(1), - m_warnTime(1), - m_expireTime(1), - m_trial(true) + m_warnTime(0), + m_expireTime(0), + m_edition(kBasic), + m_trial(true), + m_valid(false) { - m_userLimit = 1; - m_warnTime = 1; - m_expireTime = 1; - m_trial = true; + string plainText = decode(serial); + if (!plainText.empty()) { + parse(serial); + } } - + bool SerialKey::isValid(unsigned long long currentTime) const { - return true; + bool result = false; + + if (m_valid) { + if (m_trial) { + if (currentTime < m_expireTime) { + result = true; + } + } + else { + result = true; + } + } + + return result; } bool SerialKey::isExpiring(unsigned long long currentTime) const { - return true; + bool result = false; + + if (m_valid) { + if (m_warnTime < currentTime && currentTime < m_expireTime) { + result = true; + } + } + + return result; } bool SerialKey::isExpired(unsigned long long currentTime) const { - return true; + bool result = false; + + if (m_valid) { + if (currentTime > m_expireTime) { + result = true; + } + } + + return result; } bool SerialKey::isTrial() const { - return true; + return m_trial; } int SerialKey::edition() const { - return 1; + return m_edition; +} + +unsigned long long +SerialKey::dayLeft(unsigned long long currentTime) const +{ + unsigned long long timeLeft = 0; + if (m_expireTime > currentTime) { + timeLeft = m_expireTime - currentTime; + } + + unsigned long long day = 60 * 60 * 24; + + return timeLeft / day; +} + +std::string +SerialKey::decode(const std::string& serial) const +{ + static const char* const lut = "0123456789ABCDEF"; + string output; + size_t len = serial.length(); + if (len & 1) { + return output; + } + + output.reserve(len / 2); + for (size_t i = 0; i < len; i += 2) { + + char a = serial[i]; + char b = serial[i + 1]; + + const char* p = std::lower_bound(lut, lut + 16, a); + const char* q = std::lower_bound(lut, lut + 16, b); + + if (*q != b || *p != a) { + return output; + } + + output.push_back(static_cast(((p - lut) << 4) | (q - lut))); + } + + return output; +} + +void +SerialKey::parse(std::string plainSerial) +{ + string parityStart = plainSerial.substr(0, 1); + string parityEnd = plainSerial.substr(plainSerial.length() - 1, 1); + + // check for parity chars { and }, record parity result, then remove them. + if (parityStart == "{" && parityEnd == "}") { + plainSerial = plainSerial.substr(1, plainSerial.length() - 2); + + // tokenize serialised subscription. + vector parts; + std::string::size_type pos = 0; + bool look = true; + while (look) { + std::string::size_type start = pos; + pos = plainSerial.find(";", pos); + if (pos == string::npos) { + pos = plainSerial.length(); + look = false; + } + parts.push_back(plainSerial.substr(start, pos - start)); + pos += 1; + } + + if ((parts.size() == 8) + && (parts.at(0).find("v1") != string::npos)) { + // e.g.: {v1;basic;Bob;1;email;company name;1398297600;1398384000} + m_edition = getEdition(parts.at(1)); + m_name = parts.at(2); + sscanf(parts.at(3).c_str(), "%d", &m_userLimit); + m_email = parts.at(4); + m_company = parts.at(5); + sscanf(parts.at(6).c_str(), "%lld", &m_warnTime); + sscanf(parts.at(7).c_str(), "%lld", &m_expireTime); + m_valid = true; + } + else if ((parts.size() == 9) + && (parts.at(0).find("v2") != string::npos)) { + // e.g.: {v2;trial;basic;Bob;1;email;company name;1398297600;1398384000} + m_trial = parts.at(1) == "trial" ? true : false; + m_edition = getEdition(parts.at(2)); + m_name = parts.at(3); + sscanf(parts.at(4).c_str(), "%d", &m_userLimit); + m_email = parts.at(5); + m_company = parts.at(6); + sscanf(parts.at(7).c_str(), "%lld", &m_warnTime); + sscanf(parts.at(8).c_str(), "%lld", &m_expireTime); + m_valid = true; + } + } +} + +Edition +SerialKey::getEdition(std::string editionStr) +{ + Edition e = kBasic; + if (editionStr == "pro") { + e = kPro; + } + + return e; } diff --git a/src/lib/shared/SerialKey.h b/src/lib/shared/SerialKey.h index d9101f41..d920ba53 100644 --- a/src/lib/shared/SerialKey.h +++ b/src/lib/shared/SerialKey.h @@ -19,6 +19,15 @@ #include +#ifdef TEST_ENV +#include "gtest/gtest_prod.h" +#endif + +enum Edition{ + kBasic, + kPro +}; + class SerialKey { public: SerialKey(std::string serial); @@ -28,14 +37,32 @@ public: bool isExpired(unsigned long long currentTime) const; bool isTrial() const; int edition() const; - + unsigned long long dayLeft(unsigned long long currentTime) const; + +private: + std::string decode(const std::string& serial) const; + void parse(std::string plainSerial); + Edition getEdition(std::string editionStr); + +#ifdef TEST_ENV +private: + FRIEND_TEST(SerialKeyTests, decode_empty_returnEmptyString); + FRIEND_TEST(SerialKeyTests, decode_invalidDigit_returnEmptyString); + FRIEND_TEST(SerialKeyTests, decode_validSerial_returnPlainText); + FRIEND_TEST(SerialKeyTests, parse_noParty_invalid); + FRIEND_TEST(SerialKeyTests, parse_invalidPartsLenghth_invalid); + FRIEND_TEST(SerialKeyTests, parse_validV1Serial_valid); + FRIEND_TEST(SerialKeyTests, parse_validV2Serial_valid); +#endif + private: std::string m_name; - std::string m_edition; std::string m_email; std::string m_company; int m_userLimit; - int m_warnTime; - int m_expireTime; + unsigned long long m_warnTime; + unsigned long long m_expireTime; + Edition m_edition; bool m_trial; + bool m_valid; };