first prototype
This commit is contained in:
parent
d2051dcb28
commit
e36f85cc44
103
CMakePresets.json
Normal file
103
CMakePresets.json
Normal file
@ -0,0 +1,103 @@
|
||||
{
|
||||
"version": 3,
|
||||
"cmakeMinimumRequired": {
|
||||
"major": 3,
|
||||
"minor": 19,
|
||||
"patch": 0
|
||||
},
|
||||
"configurePresets": [
|
||||
{
|
||||
"name": "linux-gcc-debug",
|
||||
"displayName": "Linux GCC Debug",
|
||||
"description": "Sets Ninja generator, compilers, build and install directory, debug build type",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"CMAKE_C_COMPILER": "gcc",
|
||||
"CMAKE_CXX_COMPILER": "c++"
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||
"hostOS": [ "Linux" ]
|
||||
},
|
||||
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
|
||||
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-release",
|
||||
"displayName": "Linux GCC Release",
|
||||
"description": "Sets Ninja generator, compilers, build and install directory, debug build type",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Release",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"CMAKE_C_COMPILER": "gcc",
|
||||
"CMAKE_CXX_COMPILER": "c++"
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioSettings/CMake/1.0": {
|
||||
"hostOS": [ "Linux" ]
|
||||
},
|
||||
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": {
|
||||
"sourceDir": "$env{HOME}/.vs/$ms{projectDirName}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "WSL-gcc-debug",
|
||||
"displayName": "Linux Debug",
|
||||
"description": "Target the Windows Subsystem for Linux (WSL) or a remote Linux system.",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}"
|
||||
},
|
||||
"vendor": {
|
||||
"microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Linux" ] },
|
||||
"microsoft.com/VisualStudioRemoteSettings/CMake/1.0": { "sourceDir": "$env{HOME}/.vs/$ms{projectDirName}" }
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "win64-debug",
|
||||
"displayName": "Windows x64 Debug",
|
||||
"description": "Target Windows with the Visual Studio development environment.",
|
||||
"generator": "Ninja",
|
||||
"binaryDir": "${sourceDir}/out/build/${presetName}",
|
||||
"architecture": {
|
||||
"value": "x64",
|
||||
"strategy": "external"
|
||||
},
|
||||
"cacheVariables": {
|
||||
"CMAKE_BUILD_TYPE": "Debug",
|
||||
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
|
||||
"CMAKE_SYSTEM_VERSION": "8.1"
|
||||
},
|
||||
"vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Windows" ] } }
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
{
|
||||
"name": "linux-gcc-debug",
|
||||
"configurePreset": "linux-gcc-debug"
|
||||
},
|
||||
{
|
||||
"name": "linux-gcc-release",
|
||||
"configurePreset": "linux-gcc-release"
|
||||
},
|
||||
{
|
||||
"name": "win64-debug",
|
||||
"configurePreset": "win64-debug"
|
||||
}
|
||||
],
|
||||
"vendor": {
|
||||
"example.com/ExampleIDE/1.0": {
|
||||
"autoFormat": false
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -22,8 +22,15 @@ conan_cmake_run(CONANFILE conanfile.txt
|
||||
BUILD missing
|
||||
BASIC_SETUP)
|
||||
|
||||
if(UNIX)
|
||||
set_source_files_properties(OSUtils_win.cpp PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
set_source_files_properties(SystemParamsProvider_win.cpp PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
else(WIN32)
|
||||
set_source_files_properties(SystemParamsProvider_linux.cpp PROPERTIES HEADER_FILE_ONLY TRUE)
|
||||
endif()
|
||||
|
||||
# Add source to this project's executable.
|
||||
add_executable (CMakeProject1 "CCServer.cpp" "CCServer.h" "CryptoUtils.cpp" "CryptoUtils.h" "CMakeProject1.cpp" "CMakeProject1.h")
|
||||
add_executable (CMakeProject1 "CCServer.cpp" "CCServer.h" "CryptoUtils.cpp" "CryptoUtils.h" "CMakeProject1.cpp" "CMakeProject1.h" "HashUtils.cpp" "HashUtils.h" "JSONSerialization.cpp" "JSONSerialization.h" "LicenseClient.cpp" "LicenseClient.h" "SystemParams.cpp" "SystemParams.h" "SystemParamsProvider.h" "SystemParamsProvider_win.cpp" "SystemParamsProvider_win.h" "SystemParamsProvider_linux.cpp" "SystemParamsProvider_win.cpp" "OSUtils.h" "OSUtils_win.cpp")
|
||||
|
||||
target_link_libraries(CMakeProject1 ${CONAN_LIBS})
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#include "CCServer.h"
|
||||
|
||||
#include "LicenseClient.h"
|
||||
#include "SystemParamsProvider.h"
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/asio/signal_set.hpp>
|
||||
#include <iostream>
|
||||
@ -39,6 +42,16 @@ int main(int argc, const char* argv[])
|
||||
return 1;
|
||||
}
|
||||
|
||||
SystemParamsProvider systemParamsProvider;
|
||||
LicenseClient licenseClient(systemParamsProvider, "license.dat");
|
||||
licenseClient.init();
|
||||
|
||||
if (!licenseClient.isActivated()) {
|
||||
std::cerr << "Application is not activated. Please contact Catalogue of Currencies support. Exiting..." << std::endl;
|
||||
std::cout << "Activation request: " << licenseClient.buildActivationRequest() << std::endl;
|
||||
return -2;
|
||||
}
|
||||
|
||||
if (vm.count("port")) {
|
||||
std::cout << "Port "
|
||||
<< vm["port"].as<uint16_t>() << ".\n";
|
||||
|
||||
@ -29,14 +29,15 @@ std::string base64Decode(const std::string& encoded)
|
||||
return decoded;
|
||||
}
|
||||
|
||||
std::string base64Encode(const std::string& source)
|
||||
std::string base64Encode(const std::string& source, std::optional<int> maxLineLength)
|
||||
{
|
||||
std::string encoded;
|
||||
|
||||
StringSource ss(source, true,
|
||||
new Base64Encoder(
|
||||
new StringSink(encoded),
|
||||
false /* no line breaks */
|
||||
maxLineLength.has_value() /* no line breaks */,
|
||||
maxLineLength.value_or(64)
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
std::string base64Decode(const std::string& encoded);
|
||||
std::string base64Encode(const std::string& source);
|
||||
std::string base64Encode(const std::string& source, std::optional<int> maxLineLength = {});
|
||||
std::unique_ptr<uint8_t[]> base64Encode(const uint8_t * source, size_t sourceSize);
|
||||
std::string base32Decode(const std::string& encoded);
|
||||
std::string base32Encode(const std::string& data);
|
||||
|
||||
44
CMakeProject1/HashUtils.cpp
Normal file
44
CMakeProject1/HashUtils.cpp
Normal file
@ -0,0 +1,44 @@
|
||||
#include "HashUtils.h"
|
||||
|
||||
#include <cryptopp/sha.h>
|
||||
#include <cryptopp/files.h>
|
||||
#include <cryptopp/hex.h>
|
||||
|
||||
using CryptoPP::SHA256;
|
||||
using CryptoPP::FileSource;
|
||||
using CryptoPP::HashFilter;
|
||||
using CryptoPP::HexEncoder;
|
||||
using CryptoPP::StringSink;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
std::string calcSHA256(const fs::path& file)
|
||||
{
|
||||
SHA256 hash;
|
||||
std::string digest;
|
||||
|
||||
FileSource f(
|
||||
file.native().c_str(),
|
||||
true,
|
||||
new HashFilter(
|
||||
hash,
|
||||
new HexEncoder(
|
||||
new StringSink(
|
||||
digest))));
|
||||
|
||||
return digest;
|
||||
}
|
||||
|
||||
uint64_t fletcher64(uint32_t *data, int count)
|
||||
{
|
||||
uint64_t sum1 = 0;
|
||||
uint64_t sum2 = 0;
|
||||
int index;
|
||||
|
||||
for (index = 0; index < count; ++index)
|
||||
{
|
||||
sum1 = (sum1 + data[index]) % std::numeric_limits<uint32_t>::max();
|
||||
sum2 = (sum2 + sum1) % std::numeric_limits<uint32_t>::max();
|
||||
}
|
||||
|
||||
return (sum2 << std::numeric_limits<uint32_t>::digits) | sum1;
|
||||
}
|
||||
7
CMakeProject1/HashUtils.h
Normal file
7
CMakeProject1/HashUtils.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <string>
|
||||
|
||||
std::string calcSHA256(const boost::filesystem::path& file);
|
||||
uint64_t fletcher64(uint32_t * data, int count);
|
||||
15
CMakeProject1/JSONSerialization.cpp
Normal file
15
CMakeProject1/JSONSerialization.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "JSONSerialization.h"
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
void serialize(std::ostream & os, const std::string & str)
|
||||
{
|
||||
os << '"'
|
||||
<< str
|
||||
<< '"';
|
||||
}
|
||||
|
||||
void deserialize(const pt::ptree & tree, std::string & stringVal)
|
||||
{
|
||||
stringVal = tree.get_value<std::string>();
|
||||
}
|
||||
118
CMakeProject1/JSONSerialization.h
Normal file
118
CMakeProject1/JSONSerialization.h
Normal file
@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
void serialize(std::ostream& os, const std::string& str);
|
||||
|
||||
template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
|
||||
void serialize(std::ostream& os, T intVal)
|
||||
{
|
||||
os << intVal;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void serialize(std::ostream& os, const std::vector<T>& vec)
|
||||
{
|
||||
os << "[";
|
||||
if (vec.size() > 0)
|
||||
{
|
||||
serialize(os, vec[0]);
|
||||
std::for_each(std::begin(vec) + 1, std::end(vec), [&os](const auto& el)
|
||||
{
|
||||
os << ',';
|
||||
serialize(os, el);
|
||||
});
|
||||
}
|
||||
os << "]";
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void serialize(std::ostream& os, const std::set<T>& setVal)
|
||||
{
|
||||
bool first = true;
|
||||
os << "[";
|
||||
std::for_each(std::begin(setVal), std::end(setVal), [&os, &first](const auto& el)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
os << ',';
|
||||
}
|
||||
serialize(os, el);
|
||||
first = false;
|
||||
});
|
||||
os << "]";
|
||||
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void serialize(std::ostream& os, const std::map<std::string, T>& m)
|
||||
{
|
||||
bool first = true;
|
||||
os << "{";
|
||||
std::for_each(std::begin(m), std::end(m), [&os, &first](const auto& pair)
|
||||
{
|
||||
if (!first)
|
||||
{
|
||||
os << ',';
|
||||
}
|
||||
serialize(os, pair.first);
|
||||
os << ':';
|
||||
serialize(os, pair.second);
|
||||
first = false;
|
||||
});
|
||||
os << "}";
|
||||
}
|
||||
|
||||
void deserialize(const boost::property_tree::ptree& tree, std::string& stringVal);
|
||||
|
||||
template<class T, typename std::enable_if<std::is_integral<T>::value, int>::type = 0>
|
||||
void deserialize(const boost::property_tree::ptree & tree, T& intVal)
|
||||
{
|
||||
intVal = tree.get_value<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deserialize(const boost::property_tree::ptree& tree, std::vector<T>& vec)
|
||||
{
|
||||
vec.clear();
|
||||
for (const boost::property_tree::ptree::value_type &el : tree)
|
||||
{
|
||||
// el.first contain the string "" if it was JSON array
|
||||
T val;
|
||||
deserialize(el.second, val);
|
||||
vec.push_back(std::move(val));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deserialize(const boost::property_tree::ptree& tree, std::set<T>& setVal)
|
||||
{
|
||||
setVal.clear();
|
||||
for (const boost::property_tree::ptree::value_type &el : tree)
|
||||
{
|
||||
// el.first contain the string "" if it was JSON array
|
||||
T val;
|
||||
deserialize(el.second, val);
|
||||
setVal.insert(std::move(val));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deserialize(const boost::property_tree::ptree& tree, std::map<std::string, T>& mapVal)
|
||||
{
|
||||
mapVal.clear();
|
||||
for (const boost::property_tree::ptree::value_type &el : tree)
|
||||
{
|
||||
std::string key;
|
||||
T val;
|
||||
key = el.first;
|
||||
deserialize(el.second, val);
|
||||
mapVal.insert(std::make_pair(std::move(key), std::move(val)));
|
||||
}
|
||||
}
|
||||
533
CMakeProject1/LicenseClient.cpp
Normal file
533
CMakeProject1/LicenseClient.cpp
Normal file
@ -0,0 +1,533 @@
|
||||
#include "LicenseClient.h"
|
||||
|
||||
#include "CryptoUtils.h"
|
||||
#include "HashUtils.h"
|
||||
#include "JSONSerialization.h"
|
||||
|
||||
#include <cryptopp/cryptlib.h>
|
||||
#include <cryptopp/aes.h>
|
||||
#include <cryptopp/gcm.h>
|
||||
#include <cryptopp/osrng.h>
|
||||
#include <cryptopp/eccrypto.h>
|
||||
#include <cryptopp/oids.h>
|
||||
#include <cryptopp/files.h>
|
||||
#include <cryptopp/hex.h>
|
||||
#include <cryptopp/dsa.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/iostreams/device/array.hpp>
|
||||
#include <boost/iostreams/filtering_stream.hpp>
|
||||
#include <boost/iostreams/filter/zlib.hpp>
|
||||
#include <boost/iostreams/copy.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
|
||||
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <streambuf>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pt = boost::property_tree;
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
using CryptoPP::AES;
|
||||
using CryptoPP::GCM;
|
||||
using CryptoPP::byte;
|
||||
using CryptoPP::SecByteBlock;
|
||||
using CryptoPP::AutoSeededRandomPool;
|
||||
using CryptoPP::AuthenticatedEncryptionFilter;
|
||||
using CryptoPP::AuthenticatedDecryptionFilter;
|
||||
using CryptoPP::StringSink;
|
||||
using CryptoPP::StringSource;
|
||||
using CryptoPP::FileSource;
|
||||
using CryptoPP::Redirector;
|
||||
using CryptoPP::ECDSA;
|
||||
using CryptoPP::EC2N;
|
||||
using CryptoPP::SHA256;
|
||||
using CryptoPP::HexDecoder;
|
||||
namespace ASN1 = CryptoPP::ASN1;
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
static const std::string productId = "coc";
|
||||
|
||||
static const uint32_t initializationVectorSize = AES::BLOCKSIZE;
|
||||
static const uint32_t macTagSize = 16;
|
||||
static const uint32_t ecdsaSignatureSize = 72;
|
||||
|
||||
template< typename T >
|
||||
std::string intToHex(T i)
|
||||
{
|
||||
std::stringstream stream;
|
||||
stream
|
||||
<< std::setfill('0') << std::setw(sizeof(T) * 2)
|
||||
<< std::hex << i;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
typedef std::string ParamHash;
|
||||
ParamHash fletcher64(const std::string& input)
|
||||
{
|
||||
std::vector<uint32_t> buf((input.size() + sizeof(uint32_t) - 1) / sizeof(uint32_t), 0);
|
||||
std::memcpy((std::string::pointer)buf.data(), input.data(), input.size());
|
||||
auto resInt = ::fletcher64(buf.data(), static_cast<int>(buf.size()));
|
||||
return intToHex(resInt);
|
||||
}
|
||||
|
||||
int countUniqueCharacters(std::string_view str)
|
||||
{
|
||||
std::set<char> chars;
|
||||
for (auto ch : str)
|
||||
{
|
||||
chars.insert(ch);
|
||||
}
|
||||
return static_cast<int>(chars.size());
|
||||
}
|
||||
|
||||
std::string filterPunctuation(std::string input)
|
||||
{
|
||||
boost::remove_erase_if(input, boost::is_any_of(". :;-_/"));
|
||||
return input;
|
||||
}
|
||||
|
||||
SystemParams skipEmptyParams(const SystemParams& systemParams)
|
||||
{
|
||||
SystemParams result;
|
||||
for (const auto& entry : systemParams)
|
||||
{
|
||||
if (!entry.second.empty() && entry.second.length() > 1 && countUniqueCharacters(filterPunctuation(entry.second)) > 1)
|
||||
{
|
||||
result[entry.first] = entry.second;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
SystemParams hashParams(const SystemParams& systemParams)
|
||||
{
|
||||
SystemParams result;
|
||||
for (const auto& entry : systemParams)
|
||||
{
|
||||
result[entry.first] = fletcher64(entry.second);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
typedef std::string Signature;
|
||||
|
||||
struct SignedData
|
||||
{
|
||||
std::string data;
|
||||
std::string signature;
|
||||
};
|
||||
|
||||
std::string readBinaryFile(const std::string& filename)
|
||||
{
|
||||
std::ifstream t(filename, std::istream::binary);
|
||||
std::string str;
|
||||
|
||||
t.seekg(0, std::ios::end);
|
||||
str.reserve(static_cast<size_t>(t.tellg()));
|
||||
t.seekg(0, std::ios::beg);
|
||||
|
||||
str.assign((std::istreambuf_iterator<char>(t)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
struct PreactivationRequest
|
||||
{
|
||||
std::string productId = productId;
|
||||
SystemParams systemParams;
|
||||
};
|
||||
|
||||
struct ActivationRequest
|
||||
{
|
||||
std::string productId = productId;
|
||||
SystemParams systemParams;
|
||||
std::string licenseNumber;
|
||||
};
|
||||
|
||||
struct ActivationResponse
|
||||
{
|
||||
bool success;
|
||||
std::optional<std::string> licenseFile;
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void serialize(std::ostream& os, const ActivationData& a)
|
||||
{
|
||||
os << "{";
|
||||
os << "\"activationId\":";
|
||||
serialize(os, a.activationId);
|
||||
os << ",\"productId\":";
|
||||
serialize(os, a.productId);
|
||||
os << ",\"systemParams\":";
|
||||
serialize(os, a.systemParams);
|
||||
os << ",\"licensedModules\":";
|
||||
serialize(os, a.licensedModules);
|
||||
os << "}";
|
||||
}
|
||||
|
||||
void deserialize(const pt::ptree& tree, ActivationData& a)
|
||||
{
|
||||
deserialize(tree.get_child("activationId"), a.activationId);
|
||||
deserialize(tree.get_child("productId"), a.productId);
|
||||
deserialize(tree.get_child("systemParams"), a.systemParams);
|
||||
deserialize(tree.get_child("licensedModules"), a.licensedModules);
|
||||
}
|
||||
|
||||
void serialize(std::ostream& os, const SignedData& d)
|
||||
{
|
||||
os << "{";
|
||||
os << "\"data\":";
|
||||
serialize(os, d.data);
|
||||
os << ",\"signature\":";
|
||||
serialize(os, d.signature);
|
||||
os << "}";
|
||||
}
|
||||
|
||||
void deserialize(const pt::ptree& tree, SignedData& d)
|
||||
{
|
||||
deserialize(tree.get_child("data"), d.data);
|
||||
deserialize(tree.get_child("signature"), d.signature);
|
||||
}
|
||||
|
||||
void serialize(std::ostream& os, const PreactivationRequest& a)
|
||||
{
|
||||
os << "{";
|
||||
os << "\"productId\":";
|
||||
::serialize(os, a.productId);
|
||||
os << ",\"systemParams\":";
|
||||
::serialize(os, a.systemParams);
|
||||
os << "}";
|
||||
}
|
||||
|
||||
void serialize(std::ostream& os, const ActivationRequest& a)
|
||||
{
|
||||
os << "{";
|
||||
os << "\"productId\":";
|
||||
::serialize(os, a.productId);
|
||||
os << ",\"systemParams\":";
|
||||
::serialize(os, a.systemParams);
|
||||
os << ",\"licenseNumber\":";
|
||||
::serialize(os, a.licenseNumber);
|
||||
os << "}";
|
||||
}
|
||||
|
||||
void deserialize(const pt::ptree& tree, ActivationResponse& a)
|
||||
{
|
||||
deserialize(tree.get_child("success"), a.success);
|
||||
auto licenseFileOpt = tree.get_child_optional("licenseFile");
|
||||
if (licenseFileOpt)
|
||||
{
|
||||
std::string res;
|
||||
deserialize(licenseFileOpt.value(), res);
|
||||
a.licenseFile = base64Decode(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
a.licenseFile = {};
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> validateLicenseKey(const std::string& licenseKey)
|
||||
{
|
||||
auto result = base32Decode(licenseKey);
|
||||
if (result.size() != 15)
|
||||
return {};
|
||||
return base32Encode(result);
|
||||
}
|
||||
|
||||
LicenseClient::LicenseClient(SystemParamsProvider& systemParamsProvider, const std::string& licenseFile)
|
||||
: m_systemParamsProvider(systemParamsProvider)
|
||||
, m_licenseFile(licenseFile)
|
||||
{
|
||||
}
|
||||
|
||||
LicenseClient::~LicenseClient()
|
||||
{
|
||||
}
|
||||
|
||||
void LicenseClient::init()
|
||||
{
|
||||
const auto systemParams = skipEmptyParams(m_systemParamsProvider.retrieveSystemParams());
|
||||
|
||||
std::cout << "Collected params: " << std::endl;
|
||||
for (const auto& entry : systemParams)
|
||||
{
|
||||
std::cout << "\t" << entry.first << " = " << entry.second << " ~= " << fletcher64(entry.second) << std::endl;
|
||||
}
|
||||
|
||||
m_systemParams = hashParams(systemParams);
|
||||
|
||||
loadActivationData();
|
||||
}
|
||||
|
||||
std::string LicenseClient::buildActivationRequest()
|
||||
{
|
||||
PreactivationRequest req{ productId, m_systemParams };
|
||||
|
||||
std::string jsonReq;
|
||||
{
|
||||
std::ostringstream ss1;
|
||||
serialize(ss1, req);
|
||||
jsonReq = ss1.str();
|
||||
}
|
||||
|
||||
boost::iostreams::array_source src{ jsonReq.data(), jsonReq.size() };
|
||||
boost::iostreams::filtering_istream is;
|
||||
boost::iostreams::zlib_params zlibParams;
|
||||
zlibParams.noheader = true;
|
||||
is.push(boost::iostreams::zlib_compressor{ zlibParams });
|
||||
is.push(src);
|
||||
std::string out;
|
||||
|
||||
AutoSeededRandomPool prng;
|
||||
|
||||
unsigned char password[] = {
|
||||
0xe7, 0x3d, 0xb5, 0x72, 0x34, 0x90, 0x05, 0xf1, 0xc4, 0x19, 0x79, 0xba, 0xf8, 0x16, 0x6a, 0x09,
|
||||
0x00, 0x74, 0x51, 0x19, 0xfa, 0x09, 0x6b, 0x9c, 0x3e, 0xfb, 0xce, 0xe1, 0x1d, 0xdd, 0x8b, 0x88 };
|
||||
|
||||
SecByteBlock key(sizeof(password));
|
||||
key.Assign(password, sizeof(password));
|
||||
|
||||
CryptoPP::byte iv[initializationVectorSize] = { 0 };
|
||||
prng.GenerateBlock(iv, sizeof(iv));
|
||||
GCM<AES>::Encryption e;
|
||||
e.SetKeyWithIV(key, key.size(), iv, initializationVectorSize);
|
||||
|
||||
std::string cipher;
|
||||
|
||||
std::string compressed(std::istreambuf_iterator<char>(is), {});
|
||||
StringSource stringSource(compressed, true,
|
||||
new AuthenticatedEncryptionFilter(e,
|
||||
new StringSink(cipher), false, macTagSize
|
||||
) // AuthenticatedEncryptionFilter
|
||||
); // StringSource
|
||||
|
||||
return std::string("-----BEGIN ACTIVATION REQUEST-----\n") +
|
||||
base64Encode(cipher, std::make_optional(64)) +
|
||||
std::string("-----END ACTIVATION REQUEST-----\n");
|
||||
}
|
||||
|
||||
bool LicenseClient::loadActivationData()
|
||||
{
|
||||
if (fs::is_regular_file(m_licenseFile))
|
||||
{
|
||||
// Encrypt in nodejs
|
||||
/*
|
||||
let activationData = {
|
||||
activationId: '1234567890',
|
||||
systemParams: {
|
||||
biosSerialNum: '1234567797980980',
|
||||
diskSerialNum: '1234567857845764'
|
||||
},
|
||||
licensedModules: ['ccengine', 'cc-data-usd', 'cc-data-rub']
|
||||
};
|
||||
|
||||
let algorithm = 'aes-256-gcm';
|
||||
let password = Buffer.from('e73db572349005f1c41979baf8166a0900745119fa096b9c3efbcee11ddd8b88', 'hex');
|
||||
let privateKey = '-----BEGIN EC PRIVATE KEY-----' + "\n" +
|
||||
'MIGAAgEBBCQBPIZnOt/mEsgtH3S9XZMGRuHkB5hYbMJ/BxcGmAc/pZLdxDWgBwYF' + "\n" +
|
||||
'K4EEABGhTANKAAQHyyrnJFywb+B0pcaVRHIOcEao3OtSMSJJZiluIMme1aE+20UA' + "\n" +
|
||||
'0c0+2u+M6bMi072XrXLf8KudcAxihG/aqCqbVVZS6i10SSM=' + "\n" +
|
||||
'-----END EC PRIVATE KEY-----';
|
||||
crypto.randomBytes(16, (err, nonce) => {
|
||||
activationData.nonce = nonce.toString('base64');
|
||||
let data = JSON.stringify(activationData);
|
||||
let sign = crypto.createSign('SHA256');
|
||||
sign.write(data);
|
||||
sign.end();
|
||||
let signature = sign.sign(privateKey, 'hex');
|
||||
data = JSON.stringify({ data, signature });
|
||||
crypto.randomBytes(16, (err, iv) => {
|
||||
zlib.deflateRaw(data, (err, compressed) => {
|
||||
let cipher = crypto.createCipheriv(algorithm, password, iv);
|
||||
let encrypted = cipher.update(compressed);
|
||||
encrypted = Buffer.concat([encrypted, cipher.final()]);
|
||||
let tag = cipher.getAuthTag();
|
||||
let output = Buffer.concat([iv, tag, encrypted]);
|
||||
console.log(output.toString('hex'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
*/
|
||||
|
||||
/*unsigned char publicKey[] = {
|
||||
0x04, 0x07, 0xcb, 0x2a, 0xe7, 0x24, 0x5c, 0xb0, 0x6f, 0xe0, 0x74, 0xa5, 0xc6, 0x95, 0x44, 0x72,
|
||||
0x0e, 0x70, 0x46, 0xa8, 0xdc, 0xeb, 0x52, 0x31, 0x22, 0x49, 0x66, 0x29, 0x6e, 0x20, 0xc9, 0x9e,
|
||||
0xd5, 0xa1, 0x3e, 0xdb, 0x45, 0x00, 0xd1, 0xcd, 0x3e, 0xda, 0xef, 0x8c, 0xe9, 0xb3, 0x22, 0xd3,
|
||||
0xbd, 0x97, 0xad, 0x72, 0xdf, 0xf0, 0xab, 0x9d, 0x70, 0x0c, 0x62, 0x84, 0x6f, 0xda, 0xa8, 0x2a,
|
||||
0x9b, 0x55, 0x56, 0x52, 0xea, 0x2d, 0x74, 0x49, 0x23 }; */
|
||||
|
||||
unsigned char publicKey[] = {
|
||||
0x30, 0x5e, 0x30, 0x10, 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x05, 0x2b,
|
||||
0x81, 0x04, 0x00, 0x11, 0x03, 0x4a, 0x00, 0x04, 0x07, 0xcb, 0x2a, 0xe7, 0x24, 0x5c, 0xb0, 0x6f,
|
||||
0xe0, 0x74, 0xa5, 0xc6, 0x95, 0x44, 0x72, 0x0e, 0x70, 0x46, 0xa8, 0xdc, 0xeb, 0x52, 0x31, 0x22,
|
||||
0x49, 0x66, 0x29, 0x6e, 0x20, 0xc9, 0x9e, 0xd5, 0xa1, 0x3e, 0xdb, 0x45, 0x00, 0xd1, 0xcd, 0x3e,
|
||||
0xda, 0xef, 0x8c, 0xe9, 0xb3, 0x22, 0xd3, 0xbd, 0x97, 0xad, 0x72, 0xdf, 0xf0, 0xab, 0x9d, 0x70,
|
||||
0x0c, 0x62, 0x84, 0x6f, 0xda, 0xa8, 0x2a, 0x9b, 0x55, 0x56, 0x52, 0xea, 0x2d, 0x74, 0x49, 0x23 };
|
||||
|
||||
unsigned char password[] = {
|
||||
0xe7, 0x3d, 0xb5, 0x72, 0x34, 0x90, 0x05, 0xf1, 0xc4, 0x19, 0x79, 0xba, 0xf8, 0x16, 0x6a, 0x09,
|
||||
0x00, 0x74, 0x51, 0x19, 0xfa, 0x09, 0x6b, 0x9c, 0x3e, 0xfb, 0xce, 0xe1, 0x1d, 0xdd, 0x8b, 0x88 };
|
||||
/* unsigned char encrypted[] = {
|
||||
0x5d, 0xc1, 0x4e, 0xaf, 0x95, 0xf0, 0x1d, 0x84, 0x09, 0x71, 0x66, 0x0f, 0x87, 0x19, 0x7a, 0xa1,
|
||||
0x6a, 0x77, 0x39, 0x1e, 0x0a, 0xde, 0x93, 0x0c, 0xda, 0xa8, 0x62, 0x76, 0x53, 0xcb, 0xa7, 0x9f,
|
||||
0x8d, 0x36, 0x2a, 0x74, 0xcd, 0x5d, 0x78, 0x6e, 0x83, 0x14, 0xa4, 0x21, 0x3c }; */
|
||||
/* {
|
||||
unsigned char encrypted[] = {
|
||||
0x88, 0x5d, 0x38, 0xfe, 0xfc, 0x51, 0x7d, 0x3c, 0xb5, 0x95, 0x49, 0xae, 0xa4, 0x6a, 0xa4, 0x7e,
|
||||
0xda, 0x5d, 0x29, 0x84, 0xc2, 0x85, 0xb6, 0x18, 0x6b, 0xd6, 0x40, 0x77, 0x28, 0xc3, 0xa4, 0x0c,
|
||||
0xd1, 0x47, 0x78, 0xf9, 0xce, 0xe4, 0x22, 0xec, 0x68, 0x3f, 0x34, 0xe3, 0xa0, 0x23, 0x42, 0xcc,
|
||||
0x35, 0x50, 0x2a, 0x34, 0xa5, 0xc3, 0x0b, 0x77, 0xa6, 0xb1, 0x00, 0x53, 0xf7, 0x86, 0x08, 0x94,
|
||||
0x72, 0x99, 0x88, 0xc6, 0x07, 0x18, 0x2b, 0xb0, 0xd9, 0xd2, 0x1d, 0xea, 0x5c, 0x96, 0x14, 0x25,
|
||||
0x70, 0xd8, 0x02, 0xb6, 0xc7, 0xa2, 0xae, 0x9e, 0x89, 0x87, 0xb9, 0x9f, 0xad, 0xd6, 0xc6, 0x8a,
|
||||
0xb2, 0x53, 0x8f, 0xfb, 0x3d, 0x4b, 0x21, 0xd3, 0xa1, 0x43, 0x88, 0xef, 0x16, 0x20, 0x19, 0xa2,
|
||||
0x6c, 0x36, 0xc4, 0xfd, 0x17, 0x0c, 0xad, 0x30, 0xef, 0xfc, 0x6c, 0xe8, 0x2c, 0x3a, 0x55, 0x18,
|
||||
0x00, 0x8a, 0x15, 0x46, 0xd6, 0x36, 0x03, 0xb6, 0x8f, 0xb9, 0x86, 0x29, 0x1f, 0x9e, 0xc2, 0x89,
|
||||
0xa2, 0x71, 0x49, 0x64, 0xc7, 0xa6, 0x70, 0x80, 0x00, 0x4c, 0x5d, 0x7c, 0x22, 0x6b, 0xdd, 0x0e,
|
||||
0x2d, 0x17, 0xab, 0xe6, 0xf8, 0x75, 0x8b, 0xd2, 0x5d, 0x2d, 0x40, 0xd6, 0xea, 0x1b, 0x4f, 0xca,
|
||||
0x02, 0x2e, 0x98, 0x16, 0x99, 0xdb, 0x14, 0x67, 0x90, 0xd6, 0x8f, 0xbf, 0xc6, 0x4d, 0xd2, 0x92,
|
||||
0xd2, 0x7b, 0x37, 0x5c, 0x60, 0x7b, 0x78, 0x90, 0x47, 0x73, 0x0a, 0xda, 0x4d, 0xa5, 0x31, 0x51,
|
||||
0x0c, 0xb6, 0x88, 0x93, 0x37, 0x4e, 0x39, 0x5c, 0x06, 0x90, 0x49, 0xd7, 0x48, 0x67, 0x60, 0xfc,
|
||||
0x9f, 0x40, 0xaf, 0x50, 0x67, 0xc0, 0xf5, 0xb4, 0xab, 0xac, 0xa1, 0x1c, 0x95, 0xd8, 0x57, 0x15,
|
||||
0x7d, 0xe8, 0xa7, 0x7f, 0x1a, 0xad, 0x64, 0x7d, 0xa9, 0x3d, 0x38, 0xa6, 0x06, 0xc2, 0x5a, 0x46,
|
||||
0xae, 0x07, 0x53, 0x97, 0x68, 0x6c, 0xc5, 0xf8, 0x2a, 0xb4, 0x86, 0x8e, 0x9a, 0x7b, 0x48, 0x51,
|
||||
0xb4, 0x76, 0x8d, 0x9e, 0x6d, 0x47, 0xa8, 0x55, 0x39, 0x73, 0x1d, 0x35, 0x7c, 0xd2, 0xc1, 0x6a,
|
||||
0x22, 0x91, 0x59, 0x4d, 0xaa, 0x69, 0x11, 0xdf, 0xf3, 0x4f, 0x41, 0x04, 0xff, 0xb4, 0x5d, 0x42,
|
||||
0x42, 0x73, 0x07, 0xc4, 0xfc, 0xac, 0xa4, 0x98, 0x40, 0x24, 0x1f, 0x0a, 0x86, 0xda, 0x06 };
|
||||
|
||||
|
||||
std::ofstream ofs("license.dat", std::ofstream::binary);
|
||||
ofs.write((const char*)encrypted, sizeof(encrypted));
|
||||
} */
|
||||
|
||||
SecByteBlock key(sizeof(password));
|
||||
key.Assign(password, sizeof(password));
|
||||
|
||||
std::string encrypted = readBinaryFile(m_licenseFile);
|
||||
if (std::size(encrypted) < initializationVectorSize)
|
||||
{
|
||||
throw std::runtime_error("Invalid license file");
|
||||
}
|
||||
|
||||
std::string recoveredData;
|
||||
|
||||
GCM<AES>::Decryption d;
|
||||
d.SetKeyWithIV(key, key.size(), (const CryptoPP::byte*)encrypted.data(), initializationVectorSize);
|
||||
|
||||
AuthenticatedDecryptionFilter df(d,
|
||||
new StringSink(recoveredData),
|
||||
AuthenticatedDecryptionFilter::MAC_AT_BEGIN |
|
||||
AuthenticatedDecryptionFilter::THROW_EXCEPTION, macTagSize
|
||||
); // AuthenticatedDecryptionFilter
|
||||
|
||||
// The StringSource dtor will be called immediately
|
||||
// after construction below. This will cause the
|
||||
// destruction of objects it owns. To stop the
|
||||
// behavior so we can get the decoding result from
|
||||
// the DecryptionFilter, we must use a redirector
|
||||
// or manually Put(...) into the filter without
|
||||
// using a StringSource.
|
||||
StringSource ss2((const CryptoPP::byte*)encrypted.data() + initializationVectorSize, encrypted.size() - initializationVectorSize, true,
|
||||
new Redirector(df /*, PASS_EVERYTHING */)
|
||||
); // StringSource
|
||||
|
||||
if (!df.GetLastResult())
|
||||
{
|
||||
throw std::runtime_error("Unable to decrypt data");
|
||||
}
|
||||
|
||||
boost::iostreams::array_source src{ recoveredData.data(), recoveredData.size() };
|
||||
boost::iostreams::filtering_istream is;
|
||||
boost::iostreams::zlib_params zlibParams;
|
||||
zlibParams.noheader = true;
|
||||
is.push(boost::iostreams::zlib_decompressor{zlibParams});
|
||||
is.push(src);
|
||||
|
||||
SignedData signedData;
|
||||
{
|
||||
pt::ptree root;
|
||||
pt::read_json(is, root);
|
||||
deserialize(root, signedData);
|
||||
}
|
||||
|
||||
ECDSA<EC2N, SHA256>::PublicKey pubKey;
|
||||
//CryptoPP::FileSource fs("c:\\work\\ccengine\\openssl\\bin\\ccengine-pub.der", true /*binary*/);
|
||||
CryptoPP::ArraySource arraySource(static_cast<const CryptoPP::byte*>(publicKey), sizeof(publicKey), true);
|
||||
pubKey.Load(arraySource);
|
||||
ECDSA<EC2N, SHA256>::Verifier verifier(pubKey);
|
||||
|
||||
std::string signatureDer;
|
||||
StringSource ss(signedData.signature, true,
|
||||
new HexDecoder(
|
||||
new StringSink(signatureDer)
|
||||
) // HexDecoder
|
||||
); // StringSource
|
||||
|
||||
byte signature[ecdsaSignatureSize] = { 0 };
|
||||
size_t signLength = CryptoPP::DSAConvertSignatureFormat(signature, sizeof(signature), CryptoPP::DSA_P1363,
|
||||
(const CryptoPP::byte*)signatureDer.data(), signatureDer.size(), CryptoPP::DSA_DER);
|
||||
|
||||
bool result = verifier.VerifyMessage((const byte*)signedData.data.data(), signedData.data.size(), signature, signLength);
|
||||
if (!result)
|
||||
{
|
||||
throw std::runtime_error("Signature could not be verified");
|
||||
}
|
||||
|
||||
ActivationData activationData;
|
||||
std::istringstream iss(signedData.data);
|
||||
{
|
||||
pt::ptree root;
|
||||
pt::read_json(iss, root);
|
||||
deserialize(root, activationData);
|
||||
}
|
||||
|
||||
if (!validateActivationData(activationData))
|
||||
{
|
||||
throw std::runtime_error("You system is not genuine. Please contact support!");
|
||||
}
|
||||
|
||||
m_activationData = std::move(activationData);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool LicenseClient::validateActivationData(const ActivationData & activationData)
|
||||
{
|
||||
if (activationData.systemParams.empty())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (activationData.productId != productId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// activation parameters must match system parameters
|
||||
for (const auto& entry : activationData.systemParams)
|
||||
{
|
||||
auto it = m_systemParams.find(entry.first);
|
||||
if (it == m_systemParams.end() || it->second != entry.second)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
42
CMakeProject1/LicenseClient.h
Normal file
42
CMakeProject1/LicenseClient.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "SystemParamsProvider.h"
|
||||
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
struct ActivationData
|
||||
{
|
||||
std::string activationId;
|
||||
std::string productId;
|
||||
SystemParams systemParams;
|
||||
std::set<std::string> licensedModules;
|
||||
};
|
||||
|
||||
std::optional<std::string> validateLicenseKey(const std::string& licenseKey);
|
||||
|
||||
class LicenseClient
|
||||
{
|
||||
public:
|
||||
explicit LicenseClient(SystemParamsProvider& systemParamsProvider, const std::string& licenseFile);
|
||||
virtual ~LicenseClient();
|
||||
|
||||
public:
|
||||
void init();
|
||||
std::string buildActivationRequest();
|
||||
bool isActivated() const { return m_activationData.has_value(); }
|
||||
std::optional<std::string> activationNumber() const { return m_activationData.has_value() ? m_activationData->activationId : std::optional<std::string>(); }
|
||||
auto licensedModules() { if (!isActivated()) { throw std::runtime_error("Not active"); } return m_activationData->licensedModules; }
|
||||
|
||||
private:
|
||||
bool loadActivationData();
|
||||
bool validateActivationData(const ActivationData& activationData);
|
||||
|
||||
private:
|
||||
SystemParamsProvider& m_systemParamsProvider;
|
||||
SystemParams m_systemParams;
|
||||
std::string m_licenseFile;
|
||||
std::optional<ActivationData> m_activationData;
|
||||
};
|
||||
@ -1,180 +0,0 @@
|
||||
# CMAKE generated file: DO NOT EDIT!
|
||||
# Generated by "Unix Makefiles" Generator, CMake Version 3.16
|
||||
|
||||
# Default target executed when no arguments are given to make.
|
||||
default_target: all
|
||||
|
||||
.PHONY : default_target
|
||||
|
||||
# Allow only one "make -f Makefile2" at a time, but pass parallelism.
|
||||
.NOTPARALLEL:
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Special targets provided by cmake.
|
||||
|
||||
# Disable implicit rules so canonical targets will work.
|
||||
.SUFFIXES:
|
||||
|
||||
|
||||
# Remove some rules from gmake that .SUFFIXES does not remove.
|
||||
SUFFIXES =
|
||||
|
||||
.SUFFIXES: .hpux_make_needs_suffix_list
|
||||
|
||||
|
||||
# Suppress display of executed commands.
|
||||
$(VERBOSE).SILENT:
|
||||
|
||||
|
||||
# A target that is always out of date.
|
||||
cmake_force:
|
||||
|
||||
.PHONY : cmake_force
|
||||
|
||||
#=============================================================================
|
||||
# Set environment variables for the build.
|
||||
|
||||
# The shell in which to execute make rules.
|
||||
SHELL = /bin/sh
|
||||
|
||||
# The CMake executable.
|
||||
CMAKE_COMMAND = /usr/bin/cmake
|
||||
|
||||
# The command to remove a file.
|
||||
RM = /usr/bin/cmake -E remove -f
|
||||
|
||||
# Escaping for special characters.
|
||||
EQUALS = =
|
||||
|
||||
# The top-level source directory on which CMake was run.
|
||||
CMAKE_SOURCE_DIR = /mnt/c/Users/petos/source/repos/CMakeProject1
|
||||
|
||||
# The top-level build directory on which CMake was run.
|
||||
CMAKE_BINARY_DIR = /mnt/c/Users/petos/source/repos/CMakeProject1
|
||||
|
||||
#=============================================================================
|
||||
# Targets provided globally by CMake.
|
||||
|
||||
# Special rule for the target rebuild_cache
|
||||
rebuild_cache:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "Running CMake to regenerate build system..."
|
||||
/usr/bin/cmake -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR)
|
||||
.PHONY : rebuild_cache
|
||||
|
||||
# Special rule for the target rebuild_cache
|
||||
rebuild_cache/fast: rebuild_cache
|
||||
|
||||
.PHONY : rebuild_cache/fast
|
||||
|
||||
# Special rule for the target edit_cache
|
||||
edit_cache:
|
||||
@$(CMAKE_COMMAND) -E cmake_echo_color --switch=$(COLOR) --cyan "No interactive CMake dialog available..."
|
||||
/usr/bin/cmake -E echo No\ interactive\ CMake\ dialog\ available.
|
||||
.PHONY : edit_cache
|
||||
|
||||
# Special rule for the target edit_cache
|
||||
edit_cache/fast: edit_cache
|
||||
|
||||
.PHONY : edit_cache/fast
|
||||
|
||||
# The main all target
|
||||
all: cmake_check_build_system
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(CMAKE_COMMAND) -E cmake_progress_start /mnt/c/Users/petos/source/repos/CMakeProject1/CMakeFiles /mnt/c/Users/petos/source/repos/CMakeProject1/CMakeProject1/CMakeFiles/progress.marks
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeFiles/Makefile2 CMakeProject1/all
|
||||
$(CMAKE_COMMAND) -E cmake_progress_start /mnt/c/Users/petos/source/repos/CMakeProject1/CMakeFiles 0
|
||||
.PHONY : all
|
||||
|
||||
# The main clean target
|
||||
clean:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeFiles/Makefile2 CMakeProject1/clean
|
||||
.PHONY : clean
|
||||
|
||||
# The main clean target
|
||||
clean/fast: clean
|
||||
|
||||
.PHONY : clean/fast
|
||||
|
||||
# Prepare targets for installation.
|
||||
preinstall: all
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeFiles/Makefile2 CMakeProject1/preinstall
|
||||
.PHONY : preinstall
|
||||
|
||||
# Prepare targets for installation.
|
||||
preinstall/fast:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeFiles/Makefile2 CMakeProject1/preinstall
|
||||
.PHONY : preinstall/fast
|
||||
|
||||
# clear depends
|
||||
depend:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 1
|
||||
.PHONY : depend
|
||||
|
||||
# Convenience name for target.
|
||||
CMakeProject1/CMakeFiles/CMakeProject1.dir/rule:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeFiles/Makefile2 CMakeProject1/CMakeFiles/CMakeProject1.dir/rule
|
||||
.PHONY : CMakeProject1/CMakeFiles/CMakeProject1.dir/rule
|
||||
|
||||
# Convenience name for target.
|
||||
CMakeProject1: CMakeProject1/CMakeFiles/CMakeProject1.dir/rule
|
||||
|
||||
.PHONY : CMakeProject1
|
||||
|
||||
# fast build rule for target.
|
||||
CMakeProject1/fast:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeProject1/CMakeFiles/CMakeProject1.dir/build.make CMakeProject1/CMakeFiles/CMakeProject1.dir/build
|
||||
.PHONY : CMakeProject1/fast
|
||||
|
||||
CMakeProject1.o: CMakeProject1.cpp.o
|
||||
|
||||
.PHONY : CMakeProject1.o
|
||||
|
||||
# target to build an object file
|
||||
CMakeProject1.cpp.o:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeProject1/CMakeFiles/CMakeProject1.dir/build.make CMakeProject1/CMakeFiles/CMakeProject1.dir/CMakeProject1.cpp.o
|
||||
.PHONY : CMakeProject1.cpp.o
|
||||
|
||||
CMakeProject1.i: CMakeProject1.cpp.i
|
||||
|
||||
.PHONY : CMakeProject1.i
|
||||
|
||||
# target to preprocess a source file
|
||||
CMakeProject1.cpp.i:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeProject1/CMakeFiles/CMakeProject1.dir/build.make CMakeProject1/CMakeFiles/CMakeProject1.dir/CMakeProject1.cpp.i
|
||||
.PHONY : CMakeProject1.cpp.i
|
||||
|
||||
CMakeProject1.s: CMakeProject1.cpp.s
|
||||
|
||||
.PHONY : CMakeProject1.s
|
||||
|
||||
# target to generate assembly for a file
|
||||
CMakeProject1.cpp.s:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(MAKE) -f CMakeProject1/CMakeFiles/CMakeProject1.dir/build.make CMakeProject1/CMakeFiles/CMakeProject1.dir/CMakeProject1.cpp.s
|
||||
.PHONY : CMakeProject1.cpp.s
|
||||
|
||||
# Help Target
|
||||
help:
|
||||
@echo "The following are some of the valid targets for this Makefile:"
|
||||
@echo "... all (the default if no target is provided)"
|
||||
@echo "... clean"
|
||||
@echo "... depend"
|
||||
@echo "... rebuild_cache"
|
||||
@echo "... edit_cache"
|
||||
@echo "... CMakeProject1"
|
||||
@echo "... CMakeProject1.o"
|
||||
@echo "... CMakeProject1.i"
|
||||
@echo "... CMakeProject1.s"
|
||||
.PHONY : help
|
||||
|
||||
|
||||
|
||||
#=============================================================================
|
||||
# Special targets to cleanup operation of make.
|
||||
|
||||
# Special rule to run CMake to check the build system integrity.
|
||||
# No rule that depends on this can have commands that come from listfiles
|
||||
# because they might be regenerated.
|
||||
cmake_check_build_system:
|
||||
cd /mnt/c/Users/petos/source/repos/CMakeProject1 && $(CMAKE_COMMAND) -S$(CMAKE_SOURCE_DIR) -B$(CMAKE_BINARY_DIR) --check-build-system CMakeFiles/Makefile.cmake 0
|
||||
.PHONY : cmake_check_build_system
|
||||
|
||||
5
CMakeProject1/OSUtils.h
Normal file
5
CMakeProject1/OSUtils.h
Normal file
@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
boost::filesystem::path ensureLogFolder(const std::string& appName);
|
||||
34
CMakeProject1/OSUtils_win.cpp
Normal file
34
CMakeProject1/OSUtils_win.cpp
Normal file
@ -0,0 +1,34 @@
|
||||
#include "OSUtils.h"
|
||||
|
||||
struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive-
|
||||
#include <ShlObj.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
boost::filesystem::path ensureLogFolder(const std::string& appName)
|
||||
{
|
||||
char szPath[MAX_PATH] = { 0 };
|
||||
|
||||
if (SUCCEEDED(SHGetFolderPathA(NULL,
|
||||
CSIDL_APPDATA | CSIDL_FLAG_CREATE,
|
||||
NULL,
|
||||
0,
|
||||
szPath)))
|
||||
{
|
||||
auto logPath = fs::path(szPath) / appName / "Log";
|
||||
if (!fs::exists(logPath))
|
||||
{
|
||||
fs::create_directories(logPath);
|
||||
}
|
||||
if (!fs::is_directory(logPath))
|
||||
{
|
||||
throw std::runtime_error("Could not access log directory");
|
||||
}
|
||||
|
||||
return logPath;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Could not find application data folder");
|
||||
}
|
||||
11
CMakeProject1/SystemParams.cpp
Normal file
11
CMakeProject1/SystemParams.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "SystemParams.h"
|
||||
|
||||
const std::string SystemParamTypes::biosSerialNum{ "biosSerialNum" };
|
||||
const std::string SystemParamTypes::computerUUID{ "computerUUID" };
|
||||
const std::string SystemParamTypes::computerSerial{ "computerSerial" };
|
||||
const std::string SystemParamTypes::diskSerialNum{ "diskSerialNum" };
|
||||
const std::string SystemParamTypes::osId{ "osId" };
|
||||
const std::string SystemParamTypes::nicMac{ "nicMac" };
|
||||
const std::string SystemParamTypes::mainboardSerialNum{ "mainboardSerialNum" };
|
||||
const std::string SystemParamTypes::cpuIdModel{ "cpuIdModel" };
|
||||
const std::string SystemParamTypes::cpuIdHypervisor{ "cpuIdHypervisor" };
|
||||
19
CMakeProject1/SystemParams.h
Normal file
19
CMakeProject1/SystemParams.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
struct SystemParamTypes
|
||||
{
|
||||
static const std::string biosSerialNum;
|
||||
static const std::string computerUUID;
|
||||
static const std::string computerSerial;
|
||||
static const std::string diskSerialNum;
|
||||
static const std::string osId;
|
||||
static const std::string nicMac;
|
||||
static const std::string mainboardSerialNum;
|
||||
static const std::string cpuIdModel;
|
||||
static const std::string cpuIdHypervisor;
|
||||
};
|
||||
|
||||
typedef std::map<std::string, std::string> SystemParams;
|
||||
13
CMakeProject1/SystemParamsProvider.h
Normal file
13
CMakeProject1/SystemParamsProvider.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include "SystemParamsProvider_win.h"
|
||||
typedef SystemParamsProvider_win SystemParamsProvider;
|
||||
|
||||
#else
|
||||
|
||||
#include "SystemParamsProvider_linux.h"
|
||||
typedef SystemParamsProvider_linux SystemParamsProvider;
|
||||
|
||||
#endif // WIN32
|
||||
468
CMakeProject1/SystemParamsProvider_linux.cpp
Normal file
468
CMakeProject1/SystemParamsProvider_linux.cpp
Normal file
@ -0,0 +1,468 @@
|
||||
#include "SystemParamsProvider_linux.h"
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <cpuid.h>
|
||||
|
||||
#include <future>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <regex>
|
||||
#include <sstream>
|
||||
|
||||
namespace bp = boost::process; //we will assume this for all further examples
|
||||
|
||||
namespace
|
||||
{
|
||||
template< typename T >
|
||||
std::string intToHex( T i )
|
||||
{
|
||||
std::ostringstream stream;
|
||||
stream << std::setfill ('0') << std::setw(sizeof(T)*2)
|
||||
<< std::hex << i;
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
std::vector<std::string> splitString(const std::string& str, char c = ' ')
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
|
||||
auto it = str.cbegin();
|
||||
do
|
||||
{
|
||||
auto firstIt = it;
|
||||
|
||||
while(*it != c && it != str.cend()) {
|
||||
++it;
|
||||
}
|
||||
|
||||
result.emplace_back(firstIt, it);
|
||||
} while (it++ != str.cend());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<std::string> readFileLine(const std::string& fileName)
|
||||
{
|
||||
std::string line;
|
||||
std::ifstream myfile(fileName);
|
||||
if (myfile.is_open()) {
|
||||
std::cout << "File " << fileName << " successfully open" << std::endl;
|
||||
if (getline (myfile,line)) {
|
||||
return line;
|
||||
}
|
||||
myfile.close();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::string> loadOsId()
|
||||
{
|
||||
auto machineId = readFileLine("/var/lib/dbus/machine-id");
|
||||
if (machineId.value_or("").empty()) {
|
||||
machineId = readFileLine("/etc/machine-id");
|
||||
}
|
||||
return machineId;
|
||||
}
|
||||
|
||||
std::optional<std::string> loadBoardSerial()
|
||||
{
|
||||
return readFileLine("/sys/class/dmi/id/board_serial");
|
||||
}
|
||||
|
||||
std::optional<std::string> loadComputerUUID()
|
||||
{
|
||||
return readFileLine("/sys/class/dmi/id/product_uuid");
|
||||
}
|
||||
|
||||
std::optional<std::string> loadComputerSerial()
|
||||
{
|
||||
auto productSerial = readFileLine("/sys/class/dmi/id/product_serial");
|
||||
|
||||
if(!productSerial.value_or("").empty()) {
|
||||
auto productFamily = readFileLine("/sys/class/dmi/id/product_family");
|
||||
auto productName = readFileLine("/sys/class/dmi/id/product_name");
|
||||
|
||||
std::ostringstream os;
|
||||
os << productFamily.value() << "/" << productName.value() << "/" << productSerial.value();
|
||||
return os.str();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
struct CpuIdInfo {
|
||||
uint32_t vendorId;
|
||||
std::string vendorString;
|
||||
uint32_t modelId;
|
||||
bool isHypervisor;
|
||||
std::string serialNumber;
|
||||
};
|
||||
|
||||
CpuIdInfo loadCpuId()
|
||||
{
|
||||
uint32_t a, b, c, d;
|
||||
__cpuid (0 /* vendor string */, a, b, c, d);
|
||||
std::cout << "EAX: " << std::hex << std::setw(8) << std::setfill('0') << a << "\nEBX: " << b << "\nECX: " << c << "\nEDX: " << d << "\n";
|
||||
uint32_t vendorId = a;
|
||||
uint32_t vendorString[] = {b, d, c, 0};
|
||||
|
||||
__cpuid (1 /* Processor Info and Feature Bits */, a, b, c, d);
|
||||
std::cout << "EAX: " << std::hex << std::setw(8) << std::setfill('0') << a << "\nEBX: " << b << "\nECX: " << c << "\nEDX: " << d << "\n";
|
||||
bool isHypervisor = c & 0x80000000;
|
||||
uint32_t modelId = a & 0b00001111111111110011111111111111;
|
||||
|
||||
__cpuid (3 /* Processor Serial Number */, a, b, c, d);
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::setw(8) << std::setfill('0') << a << "-"
|
||||
<< std::hex << std::setw(8) << std::setfill('0') << b << "-"
|
||||
<< std::hex << std::setw(8) << std::setfill('0') << c << "-"
|
||||
<< std::hex << std::setw(8) << std::setfill('0') << d;
|
||||
|
||||
return CpuIdInfo {vendorId, std::string((const char*)vendorString), modelId, isHypervisor, oss.str()};
|
||||
}
|
||||
|
||||
std::optional<std::pair<std::string, std::string>> matchParameter(
|
||||
const std::string& line,
|
||||
const std::string& parameterRegex,
|
||||
const std::string& valueRegex = "([0-9a-fA-F\\-_]+)$"
|
||||
)
|
||||
{
|
||||
std::regex line_regex(parameterRegex + ": " + valueRegex);
|
||||
std::smatch line_match;
|
||||
if(std::regex_search(line, line_match, line_regex)) {
|
||||
std::cout << "DEBUG: Found " << line_match[1] << ": " << line_match[2] << std::endl;
|
||||
return std::make_pair<std::string, std::string>(line_match[1], line_match[2]);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
struct DmiDecodeParamTypes
|
||||
{
|
||||
static const std::string biosSerialNum;
|
||||
static const std::string systemUUID;
|
||||
static const std::string systemSerialNum;
|
||||
static const std::string systemFamily;
|
||||
static const std::string systemProductNumber;
|
||||
static const std::string baseboardSerialNumber;
|
||||
};
|
||||
|
||||
const std::string DmiDecodeParamTypes::systemUUID = "systemUUID";
|
||||
const std::string DmiDecodeParamTypes::systemSerialNum = "systemSerialNum";
|
||||
const std::string DmiDecodeParamTypes::systemFamily = "systemFamily";
|
||||
const std::string DmiDecodeParamTypes::systemProductNumber = "systemProductNumber";
|
||||
const std::string DmiDecodeParamTypes::baseboardSerialNumber = "baseboardSerialNumber";
|
||||
|
||||
std::map<std::string, std::string> read_dmidecode()
|
||||
{
|
||||
std::error_code ec;
|
||||
std::map<std::string, std::string> output;
|
||||
bp::ipstream is; //reading pipe-stream
|
||||
bp::child c("/usr/sbin/dmidecode", ec, bp::std_out > is, bp::std_err > bp::null);
|
||||
|
||||
if(ec) {
|
||||
return output;
|
||||
}
|
||||
|
||||
std::regex section_regex("DMI type ([0-9]+)");
|
||||
|
||||
std::string line;
|
||||
int section = -1;
|
||||
while (std::getline(is, line)) {
|
||||
if (!line.empty() && line[0] != '\t') {
|
||||
std::smatch section_match;
|
||||
if(std::regex_search(line, section_match, section_regex)) {
|
||||
section = std::atoi(section_match[1].str().c_str());
|
||||
std::cout << "DEBUG: Found section: " << section_match[1] << std::endl;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (section == 1) {
|
||||
{
|
||||
const auto matchedParameter = matchParameter(line, "(UUID)");
|
||||
if (matchedParameter.has_value()) {
|
||||
output["systemUUID"] = matchedParameter.value().second;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto matchedParameter = matchParameter(line, "(Serial Number)", "([0-9a-zA-Z\\-_]+)$");
|
||||
if (matchedParameter.has_value()) {
|
||||
output["systemSerialNumber"] = matchedParameter.value().second;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto matchedParameter = matchParameter(line, "(Family)", "([0-9a-zA-Z\\-_ ]+)$");
|
||||
if (matchedParameter.has_value()) {
|
||||
output["systemFamily"] = matchedParameter.value().second;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto matchedParameter = matchParameter(line, "(Product name)", "([0-9a-zA-Z\\-_ ]+)$");
|
||||
if (matchedParameter.has_value()) {
|
||||
output["systemProductName"] = matchedParameter.value().second;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (section == 2) {
|
||||
{
|
||||
const auto matchedParameter = matchParameter(line, "(Serial Number)", "([0-9a-zA-Z\\-_]+)$");
|
||||
if (matchedParameter.has_value()) {
|
||||
output["baseboardSerialNumber"] = matchedParameter.value().second;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
c.wait(ec);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> readMacAddresses()
|
||||
{
|
||||
std::error_code ec;
|
||||
std::map<std::string, std::string> output;
|
||||
bp::ipstream is; //reading pipe-stream
|
||||
bp::child c("/usr/bin/find /sys/class/net -mindepth 1 -maxdepth 1 ! -name lo -printf \"%P: \" -execdir /usr/bin/cat {}/address ;", ec, bp::std_out > is, bp::std_err > bp::null);
|
||||
if (ec) {
|
||||
return output;
|
||||
}
|
||||
|
||||
std::regex section_regex("([0-9a-zA-Z\\-_]+): ([0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2})");
|
||||
|
||||
std::string line;
|
||||
int section = -1;
|
||||
while (std::getline(is, line)) {
|
||||
if (!line.empty() && line[0] == 'e') {
|
||||
std::smatch section_match;
|
||||
if(std::regex_match(line, section_match, section_regex)) {
|
||||
std::cout << "DEBUG: Found device: " << section_match[1] << " with MAC: " << section_match[2] << std::endl;
|
||||
output[section_match[1]] = section_match[2];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
c.wait(ec);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
struct LsBlkResultEntry{
|
||||
std::string mountPoint;
|
||||
std::string parentName;
|
||||
std::string name;
|
||||
std::string model;
|
||||
std::string serial;
|
||||
std::string type;
|
||||
};
|
||||
|
||||
std::optional<LsBlkResultEntry> parseLsBlkResultEntry(const std::string& line)
|
||||
{
|
||||
auto cols = splitString(line, ' ');
|
||||
if(cols.size() == 6) {
|
||||
return LsBlkResultEntry{
|
||||
cols[0],cols[1],cols[2],cols[3],cols[4],cols[5]
|
||||
};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<std::string> readDiskSerial()
|
||||
{
|
||||
std::error_code ec;
|
||||
bp::ipstream is; //reading pipe-stream
|
||||
bp::child c("/usr/bin/lsblk -oMOUNTPOINT,PKNAME,NAME,MODEL,SERIAL,TYPE --raw", ec, bp::std_out > is, bp::std_err > bp::null);
|
||||
|
||||
if (ec) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<LsBlkResultEntry> cmdOut;
|
||||
|
||||
std::string line;
|
||||
int section = -1;
|
||||
while (std::getline(is, line)) {
|
||||
if (!line.empty()) {
|
||||
const auto entry = parseLsBlkResultEntry(line);
|
||||
if (entry.has_value()) {
|
||||
cmdOut.push_back(entry.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
c.wait(ec);
|
||||
if(ec) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Find best mountpoint
|
||||
LsBlkResultEntry const* bestEntry = nullptr;
|
||||
for (const auto& entry: cmdOut) {
|
||||
if(entry.mountPoint == "/") {
|
||||
bestEntry = &entry;
|
||||
}
|
||||
else if(entry.mountPoint == "/boot" && (bestEntry == nullptr || bestEntry->mountPoint == "/sysroot")) {
|
||||
bestEntry = &entry;
|
||||
}
|
||||
else if(entry.mountPoint == "/sysroot" && bestEntry == nullptr) {
|
||||
bestEntry = &entry;
|
||||
}
|
||||
}
|
||||
|
||||
if(bestEntry == nullptr)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
std::cout << "Found best mount point: " << bestEntry->mountPoint << std::endl;
|
||||
|
||||
int depth = 0;
|
||||
while(depth < 10 && !bestEntry->parentName.empty()) {
|
||||
++depth;
|
||||
bool found = false;
|
||||
for (const auto& entry: cmdOut) {
|
||||
if (entry.name == bestEntry->parentName) {
|
||||
bestEntry = &entry;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (bestEntry->type == "disk" && !bestEntry->serial.empty()) {
|
||||
return bestEntry->serial;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class SystemParamsProvider_linuxImpl final
|
||||
{
|
||||
public:
|
||||
SystemParamsProvider_linuxImpl()
|
||||
{
|
||||
}
|
||||
|
||||
~SystemParamsProvider_linuxImpl()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
SystemParams retrieveSystemParams()
|
||||
{
|
||||
SystemParams result;
|
||||
// result[SystemParamTypes::biosSerialNum] = processiosData(biosFuture.get());
|
||||
{
|
||||
const auto val = loadComputerUUID();
|
||||
if (val.has_value()) {
|
||||
result[SystemParamTypes::computerUUID] = val.value();
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto val = loadComputerSerial();
|
||||
if (val.has_value()) {
|
||||
result[SystemParamTypes::computerSerial] = val.value();
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto val = loadOsId();
|
||||
if (val.has_value()) {
|
||||
result[SystemParamTypes::osId] = val.value();
|
||||
}
|
||||
}
|
||||
{
|
||||
const auto val = loadBoardSerial();
|
||||
if (val.has_value()) {
|
||||
result[SystemParamTypes::mainboardSerialNum] = val.value();
|
||||
}
|
||||
}
|
||||
|
||||
auto cpuIdInfo = loadCpuId();
|
||||
std::cout << "Vendor ID: " << cpuIdInfo.vendorId << std::endl;
|
||||
std::cout << "Model ID: " << cpuIdInfo.modelId << std::endl;
|
||||
std::cout << "Vendor String: " << cpuIdInfo.vendorString << std::endl;
|
||||
std::cout << "Is hypervisor: " << cpuIdInfo.isHypervisor << std::endl;
|
||||
std::cout << "Serial number: " << cpuIdInfo.serialNumber << std::endl;
|
||||
|
||||
result[SystemParamTypes::cpuIdModel] = intToHex(cpuIdInfo.vendorId) + intToHex(cpuIdInfo.modelId);
|
||||
if(cpuIdInfo.isHypervisor) {
|
||||
result[SystemParamTypes::cpuIdHypervisor] = "true";
|
||||
}
|
||||
|
||||
const auto macAddresses = readMacAddresses();
|
||||
if(macAddresses.size() > 0)
|
||||
{
|
||||
result[SystemParamTypes::nicMac] = macAddresses.begin()->second;
|
||||
}
|
||||
|
||||
const auto diskSerial = readDiskSerial();
|
||||
if (diskSerial.has_value()) {
|
||||
result[SystemParamTypes::diskSerialNum] = diskSerial.value();
|
||||
}
|
||||
|
||||
auto result2 = read_dmidecode();
|
||||
for (auto it = result2.cbegin(); it != result2.cend(); ++it) {
|
||||
std::cout << it->first << ": " << it->second << std::endl;
|
||||
}
|
||||
|
||||
if (result.find(SystemParamTypes::mainboardSerialNum) == result.end() &&
|
||||
result2.find(DmiDecodeParamTypes::baseboardSerialNumber) != result2.end()) {
|
||||
result[SystemParamTypes::mainboardSerialNum] = result2[DmiDecodeParamTypes::baseboardSerialNumber];
|
||||
}
|
||||
|
||||
if (result.find(SystemParamTypes::computerUUID) == result.end() &&
|
||||
result2.find(DmiDecodeParamTypes::systemUUID) != result2.end()) {
|
||||
result[SystemParamTypes::computerUUID] = result2[DmiDecodeParamTypes::systemUUID];
|
||||
}
|
||||
|
||||
if (result.find(SystemParamTypes::computerSerial) == result.end() &&
|
||||
result2.find(DmiDecodeParamTypes::systemSerialNum) != result2.end()) {
|
||||
if(!result2[DmiDecodeParamTypes::systemUUID].empty()) {
|
||||
auto productFamily = result2.find(DmiDecodeParamTypes::systemFamily);
|
||||
auto productName = result2.find(DmiDecodeParamTypes::systemProductNumber);
|
||||
|
||||
std::ostringstream os;
|
||||
os << ((productFamily != result2.end()) ? productFamily->second : "")
|
||||
<< "/" << ((productName != result2.end()) ? productName->second : "")
|
||||
<< "/" << result2[DmiDecodeParamTypes::systemUUID];
|
||||
result[SystemParamTypes::computerSerial] = os.str();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
|
||||
private:
|
||||
};
|
||||
}
|
||||
|
||||
SystemParamsProvider_linux::SystemParamsProvider_linux()
|
||||
: m_impl(std::make_unique<detail::SystemParamsProvider_linuxImpl>())
|
||||
{
|
||||
}
|
||||
|
||||
SystemParamsProvider_linux::~SystemParamsProvider_linux()
|
||||
{
|
||||
}
|
||||
|
||||
SystemParams SystemParamsProvider_linux::retrieveSystemParams()
|
||||
{
|
||||
return m_impl->retrieveSystemParams();
|
||||
}
|
||||
23
CMakeProject1/SystemParamsProvider_linux.h
Normal file
23
CMakeProject1/SystemParamsProvider_linux.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "SystemParams.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class SystemParamsProvider_linuxImpl;
|
||||
}
|
||||
|
||||
class SystemParamsProvider_linux final
|
||||
{
|
||||
public:
|
||||
SystemParamsProvider_linux();
|
||||
~SystemParamsProvider_linux();
|
||||
|
||||
public:
|
||||
SystemParams retrieveSystemParams();
|
||||
private:
|
||||
std::unique_ptr<detail::SystemParamsProvider_linuxImpl> m_impl;
|
||||
};
|
||||
420
CMakeProject1/SystemParamsProvider_win.cpp
Normal file
420
CMakeProject1/SystemParamsProvider_win.cpp
Normal file
@ -0,0 +1,420 @@
|
||||
#include "SystemParamsProvider_win.h"
|
||||
|
||||
struct IUnknown; // Workaround for "combaseapi.h(229): error C2187: syntax error: 'identifier' was unexpected here" when using /permissive-
|
||||
#define _WIN32_DCOM
|
||||
#include <comdef.h>
|
||||
#include <Wbemidl.h>
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
|
||||
#include <future>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
#pragma comment(lib, "wbemuuid.lib")
|
||||
|
||||
namespace
|
||||
{
|
||||
std::string convertWCSToMBS(const wchar_t* pstr, long wslen)
|
||||
{
|
||||
int len = ::WideCharToMultiByte(CP_ACP, 0, pstr, wslen, NULL, 0, NULL, NULL);
|
||||
|
||||
std::string dblstr(len, '\0');
|
||||
len = ::WideCharToMultiByte(CP_ACP, 0 /* no flags */,
|
||||
pstr, wslen /* not necessary NULL-terminated */,
|
||||
&dblstr[0], len,
|
||||
NULL, NULL /* no default char */);
|
||||
|
||||
return dblstr;
|
||||
}
|
||||
|
||||
std::string convertBSTRToMBS(BSTR bstr)
|
||||
{
|
||||
int wslen = ::SysStringLen(bstr);
|
||||
return convertWCSToMBS((wchar_t*)bstr, wslen);
|
||||
}
|
||||
|
||||
BSTR convertMBSToBSTR(const std::string& str)
|
||||
{
|
||||
int wslen = ::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
|
||||
str.data(), static_cast<int>(str.length()),
|
||||
NULL, 0);
|
||||
|
||||
BSTR wsdata = ::SysAllocStringLen(NULL, wslen);
|
||||
::MultiByteToWideChar(CP_ACP, 0 /* no flags */,
|
||||
str.data(), static_cast<int>(str.length()),
|
||||
wsdata, wslen);
|
||||
return wsdata;
|
||||
}
|
||||
|
||||
class QuerySink final : public IWbemObjectSink
|
||||
{
|
||||
public:
|
||||
typedef std::vector<std::string> Fields_type;
|
||||
typedef std::vector<std::vector<std::string>> Result_type;
|
||||
|
||||
public:
|
||||
QuerySink(const std::string& wmiClass, const Fields_type& fields)
|
||||
: m_wmiClass(wmiClass)
|
||||
, m_fields(fields)
|
||||
{
|
||||
m_lRef = 0;
|
||||
m_bDone = false;
|
||||
InitializeCriticalSection(&m_threadLock);
|
||||
}
|
||||
~QuerySink() {
|
||||
m_bDone = true;
|
||||
DeleteCriticalSection(&m_threadLock);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
virtual ULONG STDMETHODCALLTYPE AddRef() override
|
||||
{
|
||||
return InterlockedIncrement(&m_lRef);
|
||||
}
|
||||
|
||||
virtual ULONG STDMETHODCALLTYPE Release() override
|
||||
{
|
||||
LONG lRef = InterlockedDecrement(&m_lRef);
|
||||
if (lRef == 0)
|
||||
delete this;
|
||||
return lRef;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppv) override
|
||||
{
|
||||
if (riid == IID_IUnknown || riid == IID_IWbemObjectSink)
|
||||
{
|
||||
*ppv = (IWbemObjectSink *)this;
|
||||
AddRef();
|
||||
return WBEM_S_NO_ERROR;
|
||||
}
|
||||
else return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE Indicate(
|
||||
LONG lObjectCount,
|
||||
IWbemClassObject __RPC_FAR *__RPC_FAR *apObjArray
|
||||
) override
|
||||
{
|
||||
for (int i = 0; i < lObjectCount; i++)
|
||||
{
|
||||
std::vector<std::string> lineResult;
|
||||
lineResult.reserve(m_fields.size());
|
||||
for (const auto& field : m_fields)
|
||||
{
|
||||
HRESULT hres = S_OK;
|
||||
VARIANT varName;
|
||||
hres = apObjArray[i]->Get(convertMBSToBSTR(field),
|
||||
0, &varName, 0, 0);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << "Failed to get the data from the query. Error code = 0x"
|
||||
<< std::hex << hres;
|
||||
std::cerr << ostr.str() << std::endl;
|
||||
return WBEM_E_FAILED; // Program has failed.
|
||||
}
|
||||
|
||||
lineResult.push_back(convertBSTRToMBS(V_BSTR(&varName)));
|
||||
}
|
||||
|
||||
m_result.push_back(lineResult);
|
||||
}
|
||||
|
||||
return WBEM_S_NO_ERROR;
|
||||
}
|
||||
|
||||
virtual HRESULT STDMETHODCALLTYPE SetStatus(
|
||||
/* [in] */ LONG lFlags,
|
||||
/* [in] */ HRESULT hResult,
|
||||
/* [in] */ BSTR strParam,
|
||||
/* [in] */ IWbemClassObject __RPC_FAR *pObjParam
|
||||
) override
|
||||
{
|
||||
if (lFlags == WBEM_STATUS_COMPLETE)
|
||||
{
|
||||
// Call complete
|
||||
EnterCriticalSection(&m_threadLock);
|
||||
m_bDone = true;
|
||||
LeaveCriticalSection(&m_threadLock);
|
||||
m_resultPromise.set_value(std::move(m_result));
|
||||
}
|
||||
else if (lFlags == WBEM_STATUS_PROGRESS)
|
||||
{
|
||||
// Call in progress...
|
||||
}
|
||||
|
||||
return WBEM_S_NO_ERROR;
|
||||
}
|
||||
|
||||
std::future<Result_type> getFuture()
|
||||
{
|
||||
return m_resultPromise.get_future();
|
||||
}
|
||||
|
||||
bool IsDone() const
|
||||
{
|
||||
bool done = true;
|
||||
|
||||
EnterCriticalSection(&m_threadLock);
|
||||
done = m_bDone;
|
||||
LeaveCriticalSection(&m_threadLock);
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
private:
|
||||
LONG m_lRef;
|
||||
bool m_bDone;
|
||||
mutable CRITICAL_SECTION m_threadLock; // for thread safety
|
||||
const std::string m_wmiClass;
|
||||
const Fields_type m_fields;
|
||||
std::vector<std::vector<std::string>> m_result;
|
||||
std::promise<Result_type> m_resultPromise;
|
||||
};
|
||||
|
||||
void initializeCOM()
|
||||
{
|
||||
// We need to initialize COM for SystemParamsProvider
|
||||
HRESULT hres = 0;
|
||||
|
||||
// Initialize COM. ------------------------------------------
|
||||
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
|
||||
if (FAILED(hres))
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr << "Failed to initialize COM library. Error code = 0x" << std::hex << hres;
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
|
||||
// Set general COM security levels --------------------------
|
||||
hres = CoInitializeSecurity(NULL,
|
||||
-1, // COM authentication
|
||||
NULL, // Authentication services
|
||||
NULL, // Reserved
|
||||
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation
|
||||
NULL, // Authentication info
|
||||
EOAC_NONE, // Additional capabilities
|
||||
NULL); // Reserved
|
||||
|
||||
if (FAILED(hres) && hres != RPC_E_TOO_LATE) // Ignore error if the security has already been initialized
|
||||
{
|
||||
CoUninitialize();
|
||||
std::ostringstream ostr;
|
||||
ostr << "Failed to initialize security. Error code = 0x" << std::hex << hres;
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class SystemParamsProvider_winImpl final
|
||||
{
|
||||
public:
|
||||
SystemParamsProvider_winImpl()
|
||||
{
|
||||
HRESULT hres = 0;
|
||||
|
||||
initializeCOM();
|
||||
|
||||
// Obtain the initial locator to WMI -------------------------
|
||||
hres = CoCreateInstance(
|
||||
CLSID_WbemLocator,
|
||||
0,
|
||||
CLSCTX_INPROC_SERVER,
|
||||
IID_IWbemLocator, (LPVOID *)&m_pLoc);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
CoUninitialize();
|
||||
std::ostringstream ostr;
|
||||
ostr << "Failed to create IWbemLocator object. Err code = 0x" << std::hex << hres;
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
|
||||
// Connect to WMI through the IWbemLocator::ConnectServer method
|
||||
// Connect to the local root\cimv2 namespace
|
||||
// and obtain pointer pSvc to make IWbemServices calls.
|
||||
hres = m_pLoc->ConnectServer(_bstr_t(L"ROOT\\CIMV2"),
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
0,
|
||||
&m_pSvc);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
m_pLoc->Release();
|
||||
CoUninitialize();
|
||||
std::ostringstream ostr;
|
||||
ostr << "Could not connect. Error code = 0x" << std::hex << hres;
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
|
||||
// Set security levels on the proxy -------------------------
|
||||
hres = CoSetProxyBlanket(m_pSvc, // Indicates the proxy to set
|
||||
RPC_C_AUTHN_WINNT, // RPC_C_AUTHN_xxx
|
||||
RPC_C_AUTHZ_NONE, // RPC_C_AUTHZ_xxx
|
||||
NULL, // Server principal name
|
||||
RPC_C_AUTHN_LEVEL_CALL, // RPC_C_AUTHN_LEVEL_xxx
|
||||
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
|
||||
NULL, // client identity
|
||||
EOAC_NONE); // proxy capabilities
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
m_pSvc->Release();
|
||||
m_pLoc->Release();
|
||||
CoUninitialize();
|
||||
std::ostringstream ostr;
|
||||
ostr << "Could not set proxy blanket. Error code = 0x" << std::hex << hres;
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
~SystemParamsProvider_winImpl()
|
||||
{
|
||||
m_pSvc->Release();
|
||||
m_pLoc->Release();
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
public:
|
||||
SystemParams retrieveSystemParams()
|
||||
{
|
||||
auto biosFuture = queryWmiInfo("Win32_BIOS", { "SerialNumber" });
|
||||
auto computerSystemProductFuture = queryWmiInfo("Win32_ComputerSystemProduct", { "UUID" });
|
||||
auto diskDriveFuture = queryWmiInfo("Win32_DiskDrive", { "SerialNumber" }, "DeviceId = \"\\\\\\\\.\\\\PHYSICALDRIVE0\"");
|
||||
auto osFuture = queryWmiInfo("Win32_OperatingSystem", { "SerialNumber" });
|
||||
auto nicFuture = queryWmiInfo("Win32_NetworkAdapter", { "MACAddress" }, "PhysicalAdapter = TRUE");
|
||||
auto mainboardFuture = queryWmiInfo("Win32_BaseBoard", { "SerialNumber" });
|
||||
|
||||
SystemParams result;
|
||||
result[SystemParamTypes::biosSerialNum] = processBiosData(biosFuture.get());
|
||||
result[SystemParamTypes::computerUUID] = processComputerSystemProductData(computerSystemProductFuture.get());
|
||||
result[SystemParamTypes::diskSerialNum] = processDiskDrive(diskDriveFuture.get());
|
||||
result[SystemParamTypes::osId] = processOs(osFuture.get());
|
||||
result[SystemParamTypes::nicMac] = processNic(nicFuture.get());
|
||||
result[SystemParamTypes::mainboardSerialNum] = processMainBoard(mainboardFuture.get());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef std::vector<std::vector<std::string>> QueryResult_type;
|
||||
|
||||
private:
|
||||
std::future<QueryResult_type> queryWmiInfo(const std::string& wmiClass, const std::vector<std::string>& fieldNames, const std::string& condition = "")
|
||||
{
|
||||
HRESULT hres = 0;
|
||||
|
||||
std::ostringstream queryStr;
|
||||
queryStr << "SELECT " << boost::algorithm::join(fieldNames, ",") << " FROM " << wmiClass;
|
||||
|
||||
if (!condition.empty())
|
||||
{
|
||||
queryStr << " WHERE " << condition;
|
||||
}
|
||||
|
||||
// Use the IWbemServices pointer to make requests of WMI ----
|
||||
QuerySink* pResponseSink = new QuerySink(wmiClass, fieldNames);
|
||||
pResponseSink->AddRef();
|
||||
auto resultFuture = pResponseSink->getFuture();
|
||||
hres = m_pSvc->ExecQueryAsync(bstr_t("WQL"),
|
||||
convertMBSToBSTR(queryStr.str()),
|
||||
WBEM_FLAG_BIDIRECTIONAL,
|
||||
NULL,
|
||||
pResponseSink);
|
||||
|
||||
if (FAILED(hres))
|
||||
{
|
||||
pResponseSink->Release();
|
||||
std::ostringstream ostr;
|
||||
ostr << "Query for " << boost::algorithm::join(fieldNames, ", ") << " failed. Error code = 0x" << std::hex << hres;
|
||||
throw std::runtime_error(ostr.str());
|
||||
}
|
||||
|
||||
return resultFuture;
|
||||
}
|
||||
|
||||
static std::string processBiosData(const QueryResult_type& biosInfo)
|
||||
{
|
||||
if (biosInfo.size() > 0)
|
||||
{
|
||||
return biosInfo[0][0];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::string processComputerSystemProductData(const QueryResult_type& csInfo)
|
||||
{
|
||||
if (csInfo.size() > 0)
|
||||
{
|
||||
return csInfo[0][0];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::string processDiskDrive(const QueryResult_type& csInfo)
|
||||
{
|
||||
if (csInfo.size() > 0)
|
||||
{
|
||||
return csInfo[0][0];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::string processOs(const QueryResult_type& csInfo)
|
||||
{
|
||||
if (csInfo.size() > 0)
|
||||
{
|
||||
return csInfo[0][0];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::string processNic(const QueryResult_type& csInfo)
|
||||
{
|
||||
if (csInfo.size() > 0)
|
||||
{
|
||||
return csInfo[0][0];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static std::string processMainBoard(const QueryResult_type& csInfo)
|
||||
{
|
||||
if (csInfo.size() > 0)
|
||||
{
|
||||
return csInfo[0][0];
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
IWbemLocator* m_pLoc = nullptr;
|
||||
IWbemServices *m_pSvc = nullptr;
|
||||
};
|
||||
}
|
||||
|
||||
SystemParamsProvider_win::SystemParamsProvider_win()
|
||||
: m_impl(std::make_unique<detail::SystemParamsProvider_winImpl>())
|
||||
{
|
||||
}
|
||||
|
||||
SystemParamsProvider_win::~SystemParamsProvider_win()
|
||||
{
|
||||
}
|
||||
|
||||
SystemParams SystemParamsProvider_win::retrieveSystemParams()
|
||||
{
|
||||
return m_impl->retrieveSystemParams();
|
||||
}
|
||||
23
CMakeProject1/SystemParamsProvider_win.h
Normal file
23
CMakeProject1/SystemParamsProvider_win.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "SystemParams.h"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace detail
|
||||
{
|
||||
class SystemParamsProvider_winImpl;
|
||||
}
|
||||
|
||||
class SystemParamsProvider_win final
|
||||
{
|
||||
public:
|
||||
SystemParamsProvider_win();
|
||||
~SystemParamsProvider_win();
|
||||
|
||||
public:
|
||||
SystemParams retrieveSystemParams();
|
||||
private:
|
||||
std::unique_ptr<detail::SystemParamsProvider_winImpl> m_impl;
|
||||
};
|
||||
Loading…
Reference in New Issue
Block a user