From d6a819c7cb1ac00671b7e76b23d7d065d1fd76a3 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 22 Aug 2017 20:58:19 -0400 Subject: telemetry_session: Log telemetry ID. --- src/core/telemetry_session.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'src/core') diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 94483f385..61ba78457 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -3,8 +3,10 @@ // Refer to the license.txt file included. #include +#include #include "common/assert.h" +#include "common/file_util.h" #include "common/scm_rev.h" #include "common/x64/cpu_detect.h" #include "core/core.h" @@ -29,12 +31,46 @@ static const char* CpuVendorToStr(Common::CPUVendor vendor) { UNREACHABLE(); } +static u64 GenerateTelemetryId() { + u64 telemetry_id{}; + CryptoPP::AutoSeededRandomPool rng; + rng.GenerateBlock(reinterpret_cast(&telemetry_id), sizeof(u64)); + return telemetry_id; +} + +static u64 GetTelemetryId() { + u64 telemetry_id{}; + static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"}; + + if (FileUtil::Exists(filename)) { + FileUtil::IOFile file(filename, "rb"); + if (!file.IsOpen()) { + LOG_ERROR(WebService, "failed to open telemetry_id: %s", filename.c_str()); + return {}; + } + file.ReadBytes(&telemetry_id, sizeof(u64)); + } else { + FileUtil::IOFile file(filename, "wb"); + if (!file.IsOpen()) { + LOG_ERROR(WebService, "failed to open telemetry_id: %s", filename.c_str()); + return {}; + } + telemetry_id = GenerateTelemetryId(); + file.WriteBytes(&telemetry_id, sizeof(u64)); + } + + return telemetry_id; +} + TelemetrySession::TelemetrySession() { #ifdef ENABLE_WEB_SERVICE backend = std::make_unique(); #else backend = std::make_unique(); #endif + // Log one-time top-level information + AddField(Telemetry::FieldType::None, "TelemetryId", GetTelemetryId()); + // Log one-time session start information const s64 init_time{std::chrono::duration_cast( std::chrono::system_clock::now().time_since_epoch()) -- cgit v1.2.3 From c781aea947e275a970a3431a36160b769865993d Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 22 Aug 2017 22:37:03 -0400 Subject: settings: Add enable_telemetry, citra_username, and citra_token. --- src/citra/config.cpp | 4 ++++ src/citra/default_ini.h | 7 +++++++ src/citra_qt/configuration/config.cpp | 6 ++++++ src/core/settings.h | 3 +++ 4 files changed, 20 insertions(+) (limited to 'src/core') diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 73846ed91..3869b6b5d 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -156,8 +156,12 @@ void Config::ReadValues() { static_cast(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689)); // Web Service + Settings::values.enable_telemetry = + sdl2_config->GetBoolean("WebService", "enable_telemetry", true); Settings::values.telemetry_endpoint_url = sdl2_config->Get( "WebService", "telemetry_endpoint_url", "https://services.citra-emu.org/api/telemetry"); + Settings::values.citra_username = sdl2_config->Get("WebService", "citra_username", ""); + Settings::values.citra_token = sdl2_config->Get("WebService", "citra_token", ""); } void Config::Reload() { diff --git a/src/citra/default_ini.h b/src/citra/default_ini.h index 9ea779dd8..666a2ad70 100644 --- a/src/citra/default_ini.h +++ b/src/citra/default_ini.h @@ -176,7 +176,14 @@ use_gdbstub=false gdbstub_port=24689 [WebService] +# Whether or not to enable telemetry +# 0: No, 1 (default): Yes +enable_telemetry = # Endpoint URL for submitting telemetry data telemetry_endpoint_url = +# Username and token for Citra Web Service +# See https://services.citra-emu.org/ for more info +citra_username = +citra_token = )"; } diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 7386814b3..e2dceaa4c 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -139,10 +139,13 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("WebService"); + Settings::values.enable_telemetry = qt_config->value("enable_telemetry", true).toBool(); Settings::values.telemetry_endpoint_url = qt_config->value("telemetry_endpoint_url", "https://services.citra-emu.org/api/telemetry") .toString() .toStdString(); + Settings::values.citra_username = qt_config->value("citra_username").toString().toStdString(); + Settings::values.citra_token = qt_config->value("citra_token").toString().toStdString(); qt_config->endGroup(); qt_config->beginGroup("UI"); @@ -284,8 +287,11 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("WebService"); + qt_config->setValue("enable_telemetry", Settings::values.enable_telemetry); qt_config->setValue("telemetry_endpoint_url", QString::fromStdString(Settings::values.telemetry_endpoint_url)); + qt_config->setValue("citra_username", QString::fromStdString(Settings::values.citra_username)); + qt_config->setValue("citra_token", QString::fromStdString(Settings::values.citra_token)); qt_config->endGroup(); qt_config->beginGroup("UI"); diff --git a/src/core/settings.h b/src/core/settings.h index ca657719a..bf8014c5a 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -130,7 +130,10 @@ struct Values { u16 gdbstub_port; // WebService + bool enable_telemetry; std::string telemetry_endpoint_url; + std::string citra_username; + std::string citra_token; } extern values; // a special value for Values::region_value indicating that citra will automatically select a region -- cgit v1.2.3 From 9f0da33c3349df47580d93fcd25346be4d2b94a7 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 23 Aug 2017 00:08:07 -0400 Subject: qt: Add an option to view/regenerate telemetry ID. --- src/citra_qt/configuration/configure_web.cpp | 14 +++++++++++--- src/citra_qt/configuration/configure_web.h | 2 +- src/core/telemetry_session.cpp | 19 ++++++++++++++++--- src/core/telemetry_session.h | 12 ++++++++++++ 4 files changed, 40 insertions(+), 7 deletions(-) (limited to 'src/core') diff --git a/src/citra_qt/configuration/configure_web.cpp b/src/citra_qt/configuration/configure_web.cpp index fff466aaa..8715fb018 100644 --- a/src/citra_qt/configuration/configure_web.cpp +++ b/src/citra_qt/configuration/configure_web.cpp @@ -4,11 +4,15 @@ #include "citra_qt/configuration/configure_web.h" #include "core/settings.h" +#include "core/telemetry_session.h" #include "ui_configure_web.h" ConfigureWeb::ConfigureWeb(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { ui->setupUi(this); + connect(ui->button_regenerate_telemetry_id, &QPushButton::clicked, this, + &ConfigureWeb::refreshTelemetryID); + this->setConfiguration(); } @@ -30,8 +34,8 @@ void ConfigureWeb::setConfiguration() { ui->toggle_telemetry->setChecked(Settings::values.enable_telemetry); ui->edit_username->setText(QString::fromStdString(Settings::values.citra_username)); ui->edit_token->setText(QString::fromStdString(Settings::values.citra_token)); - - updateWeb(); + ui->label_telemetry_id->setText("Telemetry ID: 0x" + + QString::number(Core::GetTelemetryId(), 16).toUpper()); } void ConfigureWeb::applyConfiguration() { @@ -41,4 +45,8 @@ void ConfigureWeb::applyConfiguration() { Settings::Apply(); } -void ConfigureWeb::updateWeb() {} +void ConfigureWeb::refreshTelemetryID() { + const u64 new_telemetry_id{Core::RegenerateTelemetryId()}; + ui->label_telemetry_id->setText("Telemetry ID: 0x" + + QString::number(new_telemetry_id, 16).toUpper()); +} diff --git a/src/citra_qt/configuration/configure_web.h b/src/citra_qt/configuration/configure_web.h index 2c37b8f90..20bc254b9 100644 --- a/src/citra_qt/configuration/configure_web.h +++ b/src/citra_qt/configuration/configure_web.h @@ -21,7 +21,7 @@ public: void applyConfiguration(); public slots: - void updateWeb(); + void refreshTelemetryID(); private: void setConfiguration(); diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index 61ba78457..d0f257f58 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -38,21 +38,21 @@ static u64 GenerateTelemetryId() { return telemetry_id; } -static u64 GetTelemetryId() { +u64 GetTelemetryId() { u64 telemetry_id{}; static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"}; if (FileUtil::Exists(filename)) { FileUtil::IOFile file(filename, "rb"); if (!file.IsOpen()) { - LOG_ERROR(WebService, "failed to open telemetry_id: %s", filename.c_str()); + LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str()); return {}; } file.ReadBytes(&telemetry_id, sizeof(u64)); } else { FileUtil::IOFile file(filename, "wb"); if (!file.IsOpen()) { - LOG_ERROR(WebService, "failed to open telemetry_id: %s", filename.c_str()); + LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str()); return {}; } telemetry_id = GenerateTelemetryId(); @@ -62,6 +62,19 @@ static u64 GetTelemetryId() { return telemetry_id; } +u64 RegenerateTelemetryId() { + const u64 new_telemetry_id{GenerateTelemetryId()}; + static const std::string& filename{FileUtil::GetUserPath(D_CONFIG_IDX) + "telemetry_id"}; + + FileUtil::IOFile file(filename, "wb"); + if (!file.IsOpen()) { + LOG_ERROR(Core, "failed to open telemetry_id: %s", filename.c_str()); + return {}; + } + file.WriteBytes(&new_telemetry_id, sizeof(u64)); + return new_telemetry_id; +} + TelemetrySession::TelemetrySession() { #ifdef ENABLE_WEB_SERVICE backend = std::make_unique(); diff --git a/src/core/telemetry_session.h b/src/core/telemetry_session.h index cf53835c3..65613daae 100644 --- a/src/core/telemetry_session.h +++ b/src/core/telemetry_session.h @@ -35,4 +35,16 @@ private: std::unique_ptr backend; ///< Backend interface that logs fields }; +/** + * Gets TelemetryId, a unique identifier used for the user's telemetry sessions. + * @returns The current TelemetryId for the session. + */ +u64 GetTelemetryId(); + +/** + * Regenerates TelemetryId, a unique identifier used for the user's telemetry sessions. + * @returns The new TelemetryId that was generated. + */ +u64 RegenerateTelemetryId(); + } // namespace Core -- cgit v1.2.3 From 04bd0c957e583a518121626deb029f214cc98cf6 Mon Sep 17 00:00:00 2001 From: bunnei Date: Wed, 23 Aug 2017 21:09:34 -0400 Subject: web_services: Refactor to remove dependency on Core. --- src/core/telemetry_session.cpp | 8 +++++++- src/web_service/telemetry_json.cpp | 3 +-- src/web_service/telemetry_json.h | 7 ++++++- src/web_service/web_backend.cpp | 31 ++++++++++++++++--------------- src/web_service/web_backend.h | 6 +++++- 5 files changed, 35 insertions(+), 20 deletions(-) (limited to 'src/core') diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index d0f257f58..104a16cc9 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -77,7 +77,13 @@ u64 RegenerateTelemetryId() { TelemetrySession::TelemetrySession() { #ifdef ENABLE_WEB_SERVICE - backend = std::make_unique(); + if (Settings::values.enable_telemetry) { + backend = std::make_unique( + Settings::values.telemetry_endpoint_url, Settings::values.citra_username, + Settings::values.citra_token); + } else { + backend = std::make_unique(); + } #else backend = std::make_unique(); #endif diff --git a/src/web_service/telemetry_json.cpp b/src/web_service/telemetry_json.cpp index a2d007e77..6ad2ffcd4 100644 --- a/src/web_service/telemetry_json.cpp +++ b/src/web_service/telemetry_json.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include "common/assert.h" -#include "core/settings.h" #include "web_service/telemetry_json.h" #include "web_service/web_backend.h" @@ -81,7 +80,7 @@ void TelemetryJson::Complete() { SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback"); SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig"); SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem"); - PostJson(Settings::values.telemetry_endpoint_url, TopSection().dump()); + PostJson(endpoint_url, TopSection().dump(), true, username, token); } } // namespace WebService diff --git a/src/web_service/telemetry_json.h b/src/web_service/telemetry_json.h index 39038b4f9..9e78c6803 100644 --- a/src/web_service/telemetry_json.h +++ b/src/web_service/telemetry_json.h @@ -17,7 +17,9 @@ namespace WebService { */ class TelemetryJson : public Telemetry::VisitorInterface { public: - TelemetryJson() = default; + TelemetryJson(const std::string& endpoint_url, const std::string& username, + const std::string& token) + : endpoint_url(endpoint_url), username(username), token(token) {} ~TelemetryJson() = default; void Visit(const Telemetry::Field& field) override; @@ -49,6 +51,9 @@ private: nlohmann::json output; std::array sections; + std::string endpoint_url; + std::string username; + std::string token; }; } // namespace WebService diff --git a/src/web_service/web_backend.cpp b/src/web_service/web_backend.cpp index 96ddf6c3c..e50c3a301 100644 --- a/src/web_service/web_backend.cpp +++ b/src/web_service/web_backend.cpp @@ -5,36 +5,37 @@ #include #include #include "common/logging/log.h" -#include "core/settings.h" #include "web_service/web_backend.h" namespace WebService { static constexpr char API_VERSION[]{"1"}; -void PostJson(const std::string& url, const std::string& data) { - if (!Settings::values.enable_telemetry) { - // Telemetry disabled by user configuration +void PostJson(const std::string& url, const std::string& data, bool allow_anonymous, + const std::string& username, const std::string& token) { + if (url.empty()) { + LOG_ERROR(WebService, "URL is invalid"); return; } - if (url.empty()) { - LOG_ERROR(WebService, "URL is invalid"); + const bool are_credentials_provided{!token.empty() && !username.empty()}; + if (!allow_anonymous && !are_credentials_provided) { + LOG_ERROR(WebService, "Credentials must be provided for authenticated requests"); return; } - if (Settings::values.citra_token.empty() || Settings::values.citra_username.empty()) { - // Anonymous request if citra token or username are empty - cpr::PostAsync( - cpr::Url{url}, cpr::Body{data}, - cpr::Header{{"Content-Type", "application/json"}, {"api-version", API_VERSION}}); - } else { - // We have both, do an authenticated request + if (are_credentials_provided) { + // Authenticated request if credentials are provided cpr::PostAsync(cpr::Url{url}, cpr::Body{data}, cpr::Header{{"Content-Type", "application/json"}, - {"x-username", Settings::values.citra_username}, - {"x-token", Settings::values.citra_token}, + {"x-username", username}, + {"x-token", token}, {"api-version", API_VERSION}}); + } else { + // Otherwise, anonymous request + cpr::PostAsync( + cpr::Url{url}, cpr::Body{data}, + cpr::Header{{"Content-Type", "application/json"}, {"api-version", API_VERSION}}); } } diff --git a/src/web_service/web_backend.h b/src/web_service/web_backend.h index 08e384869..d17100398 100644 --- a/src/web_service/web_backend.h +++ b/src/web_service/web_backend.h @@ -13,7 +13,11 @@ namespace WebService { * Posts JSON to services.citra-emu.org. * @param url URL of the services.citra-emu.org endpoint to post data to. * @param data String of JSON data to use for the body of the POST request. + * @param allow_anonymous If true, allow anonymous unauthenticated requests. + * @param username Citra username to use for authentication. + * @param token Citra token to use for authentication. */ -void PostJson(const std::string& url, const std::string& data); +void PostJson(const std::string& url, const std::string& data, bool allow_anonymous, + const std::string& username = {}, const std::string& token = {}); } // namespace WebService -- cgit v1.2.3