/* Copyright (C) 2022 The Qt Company Ltd. * * SPDX-License-Identifier: GPL-3.0-only WITH Qt-GPL-exception-1.0 */ #include "utils.h" #include "commonsetup.h" #include "hmac_sha256.h" #include namespace QLicenseService { namespace utils { // Trim whitespaces from start of a string void trimLeft(std::string &s) { s.erase(s.begin(), std::find_if (s.begin(), s.end(), [](unsigned char ch) { return !std::isspace(ch); })); } // Trim whitespaces from end of a string void trimRight(std::string &s) { s.erase(std::find_if (s.rbegin(), s.rend(), [](unsigned char ch) { return !std::isspace(ch); }) .base(), s.end()); } // Trim whitespaces from both ends of a string std::string trimStr(const std::string &s) { std::string trimmed = s; trimLeft(trimmed); trimRight(trimmed); return trimmed; } // Split a string by a char (Defaults to a space) std::vector splitStr(const std::string &str, const char delimiter) { std::vector strings; std::istringstream ss(str); std::string tmpStr; while (getline(ss, tmpStr, delimiter)) { tmpStr = trimStr(tmpStr); strings.push_back(tmpStr); } return strings; } // Convert string to lower case std::string strToLower(const std::string &str) { std::string ret = str; std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower); return ret; } // Convert string to upper case std::string strToUpper(const std::string &str) { std::string ret = str; std::transform(ret.begin(), ret.end(), ret.begin(), ::toupper); return ret; } // String to int: Because stoi() raises an exception upon failing int strToInt(const std::string &str) { int retVal = 0; try { retVal = stoi(str); } catch (...) { printf("ERROR: Unable to convert '%s' to an int\n", str.c_str()); } return retVal; } std::string getUserHomeDir() { // Try to find current user's home std::string retVal = ""; const char* homedir; #if __linux__ || __APPLE__ || __MACH__ // Linux and Mac homedir = std::getenv("HOME"); if (homedir == nullptr) { homedir = getpwuid(getuid())->pw_dir; } #else // Windows homedir = getenv("HOMEPATH"); if (homedir != nullptr) { retVal = SYSTEM_ROOT; } #endif if (homedir == nullptr) { printf("ERROR Not able to determine user's home directory\n"); return "Not able to get homedir"; } retVal += std::string(homedir); return retVal; } // Write data to the file int writeToFile(const std::string &filepath, const std::string &data, bool append) { std::ofstream file; // can't enable exception now because of gcc bug that raises ios_base::failure with useless message if (append) { file.open(filepath, std::ios::out | std::ios::app); } else { file.open(filepath, std::ios::out); } if (file.fail()) { return -1; } try { file << data << std::endl; } catch (...) { file.close(); std::cout << "Failed to write data in file " << filepath << std::endl; return -1; } file.close(); return 0; } int createDir(const std::string &filepath, uint16_t user, uint16_t group) { std::vector pathVector = utils::splitStr(filepath, DIR_SEPARATOR); std::string path; for (const std::string &dir : pathVector) { path += SYSTEM_ROOT; path += dir; if (!utils::fileExists(path)) { #if __linux__ || __APPLE__ || __MACH__ if (mkdir(path.c_str(), 0777) != 0) { return -1; } chown(path.c_str(), user, group); #else printf("WARNING: Unimplemented: createDir() for Windows\n"); #endif } } return 0; } int readFile(std::string &str, const std::string &filepath) { std::ifstream file; std::stringstream ss; file.open(filepath, std::ios::in); if (file.is_open()) { std::string line; while (getline(file, line)) { ss << line << std::endl; } file.close(); } else { return -1; } str = ss.str(); return 0; } bool fileExists(const std::string &name) { #if __linux__ || __APPLE__ || __MACH__ struct stat buffer; return (stat (name.c_str(), &buffer) == 0); #else if (_access(name.c_str(), 0) == -1) { std::cout << "File " << name << " doesn't exist\n"; return false; // not accessible } return true; #endif } std::string getFileOwnerName(const std::string &filename) { std::string retVal; #if __linux__ || __APPLE__ || __MACH__ struct stat info; stat(filename.c_str(), &info); // Error check omitted struct passwd *pw = getpwuid(info.st_uid); if (pw != 0) retVal = pw->pw_name; // contains the user name #else printf("WARNING! Uniplemented: Win version of getFileOwnerName()\n"); retVal = "NULL"; #endif return retVal; } int getFileOwner(const std::string &filename, uint16_t &owner, uint16_t &group) { #if __linux__ || __APPLE__ || __MACH__ struct stat info; stat(filename.c_str(), &info); // Error check omitted owner = info.st_uid; group = info.st_gid; #else printf("WARNING! Uniplemented: Win version of getFileOwner()\n"); #endif return 0; } std::vector getDirListing(const std::string &directory, const std::string &filter) { /* Open directory stream */ DIR *dir = opendir(directory.c_str()); if (!dir) { /* Could not open directory */ std::cout << "Cannot open directory" << directory << std::endl;; } /* Gather files and directories within the directory */ std::vector files; struct dirent *ent; while ((ent = readdir(dir)) != NULL) { if (ent->d_type == DT_REG) { std::string name = ent->d_name; if (name.substr(0, filter.length()) == filter || filter.empty()) { files.push_back(name); } } } closedir(dir); return files; } int deleteFile(const std::string &filepath) { if (fileExists(filepath)) { std::remove(filepath.c_str()); // delete file return 0; } std::cout << "No file " << filepath << " found to delete\n"; return 1; } void doHmacHashSha256(const std::string &payload, const std::string &secret, std::string &authKey) { std::stringstream ss_result; ss_result << ""; // Allocate memory for the HMAC std::vector out(SHA256_HASH_SIZE); // Call hmac-sha256 function hmac_sha256(secret.data(), secret.size(), payload.data(), payload.size(), out.data(), out.size()); // Convert to string with std::hex for (uint8_t x : out) { ss_result << std::hex << std::setfill('0') << std::setw(2) << (int)x; } authKey = ss_result.str(); } std::string getOsName() { #if _WIN32 return "Windows"; #elif __APPLE__ || __MACH__ return "macOS"; #elif __linux__ return "Linux"; #elif __FreeBSD__ return "FreeBSD"; #elif __unix || __unix__ return "Unix"; #else return "Unknown OS"; #endif } std::string getSystemHwInfoString() { // Trying to get individual HW string, using network parameters and current time (epoch) std::stringstream hwInfo; std::string ip_mac; #if _WIN32 system("ipconfig > hw.txt"); #elif __APPLE__ || __MACH__ system("ifconfig > hw.txt"); #elif __linux__ system("ip addr > hw.txt"); #endif readFile(ip_mac, "hw.txt"); hwInfo << getTimestampNow() << std::endl << ip_mac; deleteFile("hw.txt"); return hwInfo.str(); } #if _WIN32 /* * Windows implementation of missing POSIX strptime() */ char* strptime(const char* s, const char* f, struct tm* tm) { std::istringstream input(s); input.imbue(std::locale(setlocale(LC_ALL, nullptr))); input >> std::get_time(tm, f); if (input.fail()) { return nullptr; } return (char*)(s + input.tellg()); } #endif std::string epochToString(time_t epochTime, const char* format) { char timestamp[64] = {0}; strftime(timestamp, sizeof(timestamp), format, localtime(&epochTime)); return timestamp; } time_t stringToEpoch(const char* theTime, const char* format) { std::tm tmTime; memset(&tmTime, 0, sizeof(tmTime)); strptime(theTime, format, &tmTime); return mktime(&tmTime); } #ifndef __TIME_IMP #define __TIME_IMP #if _WIN32 typedef struct timeval { long tv_sec; long tv_usec; } timeval; /* * Windows implementation of missing POSIX gettimeofday() */ inline int gettimeofday(struct timeval * tp, struct timezone * tzp) { // Note: some broken versions only have 8 trailing zero's, the correct epoch has 9 trailing zero's // This magic number is the number of 100 nanosecond intervals since January 1, 1601 (UTC) // until 00:00:00 January 1, 1970 static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); SYSTEMTIME system_time; FILETIME file_time; uint64_t time; GetSystemTime( &system_time ); SystemTimeToFileTime( &system_time, &file_time ); time = ((uint64_t)file_time.dwLowDateTime ) ; time += ((uint64_t)file_time.dwHighDateTime) << 32; tp->tv_sec = (long) ((time - EPOCH) / 10000000L); tp->tv_usec = (long) (system_time.wMilliseconds * 1000); return 0; } #endif #endif uint64_t getTimestampNow() { // Get current time struct timeval tp; gettimeofday(&tp, NULL); return (uint64_t)tp.tv_sec; } /* * App-specific utils here (not generic) */ } } // namespace QLicenseService::utils