diff --git a/src/lib/synergy/SubscriptionKey.h b/src/lib/synergy/SubscriptionKey.h new file mode 100644 index 00000000..0d65a17c --- /dev/null +++ b/src/lib/synergy/SubscriptionKey.h @@ -0,0 +1,28 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2015 Synergy Seamless Inc. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "base/String.h" + +struct SubscriptionKey { + String m_name; + String m_type; + int m_userLimit; + int m_warnTime; + int m_expireTime; +}; diff --git a/src/lib/synergy/SubscriptionManager.cpp b/src/lib/synergy/SubscriptionManager.cpp new file mode 100644 index 00000000..e13cf4c7 --- /dev/null +++ b/src/lib/synergy/SubscriptionManager.cpp @@ -0,0 +1,210 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2015 Synergy Seamless Inc. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "synergy/SubscriptionManager.h" + +#include "synergy/XSynergy.h" +#include "arch/Arch.h" +#include "base/Log.h" +#include "base/String.h" +#include "common/Version.h" + +#include +#include +#include +#include +//#include + +#if SYSAPI_WIN32 +const char* kFile = "Synergy.subkey"; +#else +const char* kFile = ".synergy.subkey"; +#endif + +// +// SubscriptionManager +// + +SubscriptionManager::SubscriptionManager() : + m_key() +{ +} + +void +SubscriptionManager::checkFile(const String& filename_) +{ + String filename = filename_; + if (filename.empty()) { + filename = getFilename(); + } + + std::ifstream stream(filename.c_str()); + if (!stream.is_open()) { + throw XSubscription(synergy::string::sprintf( + "Could not open, path=%s", filename.c_str())); + } + + String serial; + stream >> serial; + + String plainText = decode(serial); + parsePlainSerial(plainText, m_key); + + LOG((CLOG_DEBUG "subscription is valid")); +} + +void +SubscriptionManager::activate(const String& serial) +{ + String plainText = decode(serial); + parsePlainSerial(plainText, m_key); + + String filename = getFilename(); + std::ofstream stream(filename.c_str()); + if (!stream.is_open()) { + throw XSubscription(synergy::string::sprintf( + "Could not open, file=%s", filename.c_str())); + } + + stream << serial << std::endl; + LOG((CLOG_DEBUG "subscription file created, path=%s", filename.c_str())); +} + +String +SubscriptionManager::decode(const String& input) +{ + static const char* const lut = "0123456789ABCDEF"; + size_t len = input.length(); + if (len & 1) { + throw XSubscription("Invalid serial, wrong length."); + } + + String output; + output.reserve(len / 2); + for (size_t i = 0; i < len; i += 2) { + + char a = input[i]; + char b = input[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) { + throw XSubscription("Invalid serial, unrecognized digit."); + } + + output.push_back(static_cast(((p - lut) << 4) | (q - lut))); + } + + return output; +} + +void +SubscriptionManager::parsePlainSerial(const String& plainText, SubscriptionKey& key) +{ + String serial; + bool parity = false; + String parityStart = plainText.substr(0, 1); + String parityEnd = plainText.substr(plainText.length() - 1, 1); + + // check for parity chars { and }, record parity result, then remove them. + if (parityStart == "{" && parityEnd == "}") { + parity = true; + serial = plainText.substr(1, plainText.length() - 2); + } + else { + serial = plainText; + } + + // tokenize serialised subscription. + std::vector parts; + std::string::size_type pos = 0; + bool look = true; + while (look) { + std::string::size_type start = pos; + pos = serial.find(";", pos); + if (pos == String::npos) { + pos = plainText.length(); + look = false; + } + parts.push_back(serial.substr(start, pos - start)); + pos += 1; + } + + // e.g.: {v1;trial;Bob;1;1398297600;1398384000} + if (parity + && (parts.size() == 6) + && (parts.at(0).find("v1") != String::npos)) { + key.m_type = parts.at(1); + key.m_name = parts.at(2); + sscanf(parts.at(3).c_str(), "%d", &key.m_userLimit); + sscanf(parts.at(4).c_str(), "%d", &key.m_warnTime); + sscanf(parts.at(5).c_str(), "%d", &key.m_expireTime); + + // TODO: use Arch time + if (time(0) > key.m_expireTime) { + throw XSubscription(synergy::string::sprintf( + "%s subscription has expired", + key.m_type.c_str())); + } + else if (time(0) > key.m_warnTime) { + LOG((CLOG_WARN "%s subscription will expire soon", + key.m_type.c_str())); + } + + const char* userText = (key.m_userLimit == 1) ? "user" : "users"; + LOG((CLOG_INFO "%s subscription valid is for %d %s, registered to %s", + key.m_type.c_str(), + key.m_userLimit, + userText, + key.m_name.c_str())); + + return; + } + else if ((parts.size() == 2) && (parts.at(1) == kApplication)) { + key.m_name = parts.at(0); + LOG((CLOG_INFO "subscription is valid, registered to %s", + key.m_name.c_str())); + return; + } + else if ((parts.size() == 2) && (parts.at(0) == kApplication)) { + key.m_name = parts.at(1); + LOG((CLOG_INFO "subscription is valid, registered to %s", + key.m_name.c_str())); + return; + } + + throw XSubscription(synergy::string::sprintf("Serial is invalid.")); +} + +String +SubscriptionManager::getFilename() +{ + String path = ARCH->getUserDirectory(); + path = ARCH->concatPath(path, kFile); + if (path.empty()) { + throw XSubscription("Could not get filename."); + } + + return path; +} + +void +SubscriptionManager::printFilename() +{ + std::cout << getFilename() << std::endl; +} diff --git a/src/lib/synergy/SubscriptionManager.h b/src/lib/synergy/SubscriptionManager.h new file mode 100644 index 00000000..bf86f7c1 --- /dev/null +++ b/src/lib/synergy/SubscriptionManager.h @@ -0,0 +1,42 @@ +/* + * synergy -- mouse and keyboard sharing utility + * Copyright (C) 2015 Synergy Seamless Inc. + * + * This package is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * found in the file LICENSE that should have accompanied this file. + * + * This package is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include "SubscriptionKey.h" +#include "common/common.h" + +class SubscriptionManager { +public: + SubscriptionManager(); + + //! Check the subscription activation file + void checkFile(const String& filename); + + //! Create a subscription activation file based on a serial + void activate(const String& serial); + + //! Use standard output to return subscription filename to gui + void printFilename(); + +private: + String decode(const String& input); + void parsePlainSerial(const String& plainText, SubscriptionKey& key); + String getFilename(); + + SubscriptionKey m_key; +}; diff --git a/src/lib/synergy/XSynergy.h b/src/lib/synergy/XSynergy.h index a6361d90..78d4d86f 100644 --- a/src/lib/synergy/XSynergy.h +++ b/src/lib/synergy/XSynergy.h @@ -23,6 +23,12 @@ //! Generic synergy exception XBASE_SUBCLASS(XSynergy, XBase); +//! Subscription error +/*! +Thrown when there is a problem with the subscription. +*/ +XBASE_SUBCLASS(XSubscription, XSynergy); + //! Client error exception /*! Thrown when the client fails to follow the protocol.