diff --git a/rpcs3/main.cpp b/rpcs3/main.cpp index b5348bc9a0..038b8e8d81 100644 --- a/rpcs3/main.cpp +++ b/rpcs3/main.cpp @@ -24,6 +24,7 @@ #include "rpcs3qt/fatal_error_dialog.h" #include "rpcs3qt/curl_handle.h" #include "rpcs3qt/main_window.h" +#include "rpcs3qt/uuid.h" #include "headless_application.h" #include "Utilities/sema.h" @@ -869,6 +870,9 @@ int main(int argc, char** argv) return 0; } + // Log unique ID + gui::utils::log_uuid(); + std::string active_user; if (parser.isSet(arg_user_id)) diff --git a/rpcs3/rpcs3.vcxproj b/rpcs3/rpcs3.vcxproj index eab3c38693..f1cada13b2 100644 --- a/rpcs3/rpcs3.vcxproj +++ b/rpcs3/rpcs3.vcxproj @@ -654,6 +654,7 @@ + @@ -1258,6 +1259,7 @@ .\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp "$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\QTGeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" -D_WINDOWS -DUNICODE -DWIN32 -DWIN64 -DWIN32_LEAN_AND_MEAN -DHAVE_VULKAN -DWITH_DISCORD_RPC -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -DNDEBUG -DQT_WINEXTRAS_LIB -DQT_CONCURRENT_LIB -DQT_MULTIMEDIA_LIB -DQT_MULTIMEDIAWIDGETS_LIB -DQT_SVG_LIB -D%(PreprocessorDefinitions) "-I.\..\3rdparty\SoundTouch\soundtouch\include" "-I.\..\3rdparty\cubeb\extra" "-I.\..\3rdparty\cubeb\cubeb\include" "-I.\..\3rdparty\flatbuffers\include" "-I.\..\3rdparty\wolfssl\wolfssl" "-I.\..\3rdparty\curl\curl\include" "-I.\..\3rdparty\libusb\libusb\libusb" "-I$(VULKAN_SDK)\Include" "-I.\..\3rdparty\XAudio2Redist\include" "-I$(QTDIR)\include" "-I$(QTDIR)\include\QtWidgets" "-I$(QTDIR)\include\QtGui" "-I$(QTDIR)\include\QtANGLE" "-I$(QTDIR)\include\QtCore" "-I.\release" "-I$(QTDIR)\mkspecs\win32-msvc2015" "-I.\QTGeneratedFiles\$(ConfigurationName)" "-I.\QTGeneratedFiles" "-I$(QTDIR)\include\QtWinExtras" "-I$(QTDIR)\include\QtConcurrent" "-I$(QTDIR)\include\QtMultimedia" "-I$(QTDIR)\include\QtMultimediaWidgets" "-I$(QTDIR)\include\QtSvg" + $(QTDIR)\bin\moc.exe;%(FullPath) diff --git a/rpcs3/rpcs3.vcxproj.filters b/rpcs3/rpcs3.vcxproj.filters index ed4efaf2a1..3f4230c5e4 100644 --- a/rpcs3/rpcs3.vcxproj.filters +++ b/rpcs3/rpcs3.vcxproj.filters @@ -861,6 +861,9 @@ Generated Files\Release + + Gui\utils + @@ -1010,6 +1013,9 @@ Io\music + + Gui\utils + diff --git a/rpcs3/rpcs3qt/CMakeLists.txt b/rpcs3/rpcs3qt/CMakeLists.txt index a74f3c9140..9d2a06df9c 100644 --- a/rpcs3/rpcs3qt/CMakeLists.txt +++ b/rpcs3/rpcs3qt/CMakeLists.txt @@ -81,6 +81,7 @@ set(SRC_FILES update_manager.cpp user_account.cpp user_manager_dialog.cpp + uuid.cpp vfs_dialog.cpp vfs_dialog_path_widget.cpp vfs_dialog_tab.cpp diff --git a/rpcs3/rpcs3qt/uuid.cpp b/rpcs3/rpcs3qt/uuid.cpp new file mode 100644 index 0000000000..0ade0218d3 --- /dev/null +++ b/rpcs3/rpcs3qt/uuid.cpp @@ -0,0 +1,131 @@ +#include "stdafx.h" +#include "uuid.h" +#include "Utilities/StrUtil.h" + +#include +#include + +LOG_CHANNEL(uuid_log, "UUID"); + +namespace gui +{ + namespace utils + { + std::string get_uuid_path() + { +#ifdef _WIN32 + const std::string config_dir = fs::get_config_dir() + "config/"; + const std::string uuid_path = config_dir + "uuid"; + + if (!fs::create_path(config_dir)) + { + uuid_log.error("Could not create path: %s (%s)", uuid_path, fs::g_tls_error); + } + + return uuid_path; +#else + return fs::get_config_dir() + "uuid"; +#endif + } + + std::string make_uuid() + { + return QUuid::createUuid().toString().toStdString(); + } + + std::string load_uuid() + { + const std::string uuid_path = get_uuid_path(); + + if (!fs::is_file(uuid_path)) + { + uuid_log.notice("File does not exist: %s (%s)", uuid_path, fs::g_tls_error); + return {}; + } + + if (fs::file uuid_file = fs::file(uuid_path); uuid_file) + { + const std::string uuid = fmt::trim(uuid_file.to_string()); + + if (!validate_uuid(uuid)) + { + uuid_log.error("Invalid uuid '%s' found in file: %s", uuid, uuid_path); + return {}; + } + + return uuid; + } + + uuid_log.error("Could not open file: %s (%s)", uuid_path, fs::g_tls_error); + return {}; + } + + bool validate_uuid(const std::string& uuid) + { + const QRegularExpressionValidator validator(QRegularExpression("^[a-fA-F0-9{}-]*$")); + QString test_string = QString::fromStdString(uuid); + int pos = 0; + + if (uuid.empty() || !uuid.starts_with("{") || !uuid.ends_with("}") || validator.validate(test_string, pos) == QValidator::State::Invalid) + { + return false; + } + + return true; + } + + bool save_uuid(const std::string& uuid) + { + if (!validate_uuid(uuid)) + { + uuid_log.error("Can not save invalid uuid '%s'", uuid); + return false; + } + + const std::string uuid_path = get_uuid_path(); + + if (fs::file uuid_file(uuid_path, fs::rewrite); !uuid_file || !uuid_file.write(uuid)) + { + uuid_log.error("Could not write file: %s (%s)", uuid_path, fs::g_tls_error); + return false; + } + + uuid_log.notice("Wrote to file: %s", uuid_path); + return true; + } + + bool create_new_uuid(std::string& uuid) + { + uuid = make_uuid(); + + if (uuid.empty()) + { + uuid_log.error("Empty uuid"); + return false; + } + + if (!save_uuid(uuid)) + { + uuid_log.error("Failed to save uuid"); + return false; + } + + return true; + } + + void log_uuid() + { + std::string uuid = load_uuid(); + + if (uuid.empty()) + { + if (!create_new_uuid(uuid)) + { + return; + } + } + + uuid_log.notice("Installation ID: %s", uuid); + } + } +} diff --git a/rpcs3/rpcs3qt/uuid.h b/rpcs3/rpcs3qt/uuid.h new file mode 100644 index 0000000000..b12b605943 --- /dev/null +++ b/rpcs3/rpcs3qt/uuid.h @@ -0,0 +1,17 @@ +#pragma once + +namespace gui +{ + namespace utils + { + std::string get_uuid_path(); + std::string make_uuid(); + std::string load_uuid(); + + bool validate_uuid(const std::string& uuid); + bool save_uuid(const std::string& uuid); + bool create_new_uuid(std::string& uuid); + + void log_uuid(); + } +}