From 3a18039c53ca2bc8c90bf8efb0dda969575e6394 Mon Sep 17 00:00:00 2001 From: bunnei Date: Fri, 8 Nov 2019 22:38:48 -0500 Subject: [PATCH 1/2] citra_qt: configure_web: Use Base64 encoded token for simplifying user experience. --- src/citra_qt/configuration/configure_web.cpp | 74 ++++++++++++++------ src/citra_qt/configuration/configure_web.ui | 12 +--- 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/citra_qt/configuration/configure_web.cpp b/src/citra_qt/configuration/configure_web.cpp index 2ad70ce8b6..cc7ca675f1 100644 --- a/src/citra_qt/configuration/configure_web.cpp +++ b/src/citra_qt/configuration/configure_web.cpp @@ -11,6 +11,31 @@ #include "core/telemetry_session.h" #include "ui_configure_web.h" +static constexpr char token_delimiter{':'}; + +static std::string GenerateDisplayToken(const std::string& username, const std::string& token) { + if (username.empty() || token.empty()) { + return {}; + } + + const std::string unencoded_display_token{username + token_delimiter + token}; + QByteArray b{unencoded_display_token.c_str()}; + QByteArray b64 = b.toBase64(); + return b64.toStdString(); +} + +static std::string UsernameFromDisplayToken(const std::string& display_token) { + const std::string unencoded_display_token{ + QByteArray::fromBase64(display_token.c_str()).toStdString()}; + return unencoded_display_token.substr(0, unencoded_display_token.find(token_delimiter)); +} + +static std::string TokenFromDisplayToken(const std::string& display_token) { + const std::string unencoded_display_token{ + QByteArray::fromBase64(display_token.c_str()).toStdString()}; + return unencoded_display_token.substr(unencoded_display_token.find(token_delimiter) + 1); +} + ConfigureWeb::ConfigureWeb(QWidget* parent) : QWidget(parent), ui(std::make_unique()) { ui->setupUi(this); @@ -46,11 +71,18 @@ void ConfigureWeb::SetConfiguration() { "underline; color:#039be5;\">What is my token?")); 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)); + + if (Settings::values.citra_username.empty()) { + ui->username->setText(tr("Unspecified")); + } else { + ui->username->setText(QString::fromStdString(Settings::values.citra_username)); + } + + ui->edit_token->setText(QString::fromStdString( + GenerateDisplayToken(Settings::values.citra_username, Settings::values.citra_token))); + // Connect after setting the values, to avoid calling OnLoginChanged now connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged); - connect(ui->edit_username, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged); ui->label_telemetry_id->setText( tr("Telemetry ID: 0x%1").arg(QString::number(Core::GetTelemetryId(), 16).toUpper())); user_verified = true; @@ -62,12 +94,13 @@ void ConfigureWeb::ApplyConfiguration() { Settings::values.enable_telemetry = ui->toggle_telemetry->isChecked(); UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked(); if (user_verified) { - Settings::values.citra_username = ui->edit_username->text().toStdString(); - Settings::values.citra_token = ui->edit_token->text().toStdString(); + Settings::values.citra_username = + UsernameFromDisplayToken(ui->edit_token->text().toStdString()); + Settings::values.citra_token = TokenFromDisplayToken(ui->edit_token->text().toStdString()); } else { - QMessageBox::warning(this, tr("Username and token not verified"), - tr("Username and token were not verified. The changes to your " - "username and/or token have not been saved.")); + QMessageBox::warning( + this, tr("Token not verified"), + tr("Token was not verified. The change to your token has not been saved.")); } } @@ -78,17 +111,15 @@ void ConfigureWeb::RefreshTelemetryID() { } void ConfigureWeb::OnLoginChanged() { - if (ui->edit_username->text().isEmpty() && ui->edit_token->text().isEmpty()) { + if (ui->edit_token->text().isEmpty()) { user_verified = true; const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16); - ui->label_username_verified->setPixmap(pixmap); ui->label_token_verified->setPixmap(pixmap); } else { user_verified = false; const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16); - ui->label_username_verified->setPixmap(pixmap); ui->label_token_verified->setPixmap(pixmap); } } @@ -96,10 +127,11 @@ void ConfigureWeb::OnLoginChanged() { void ConfigureWeb::VerifyLogin() { ui->button_verify_login->setDisabled(true); ui->button_verify_login->setText(tr("Verifying...")); - verify_watcher.setFuture(QtConcurrent::run([username = ui->edit_username->text().toStdString(), - token = ui->edit_token->text().toStdString()] { - return Core::VerifyLogin(username, token); - })); + verify_watcher.setFuture(QtConcurrent::run( + [username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()), + token = TokenFromDisplayToken(ui->edit_token->text().toStdString())] { + return Core::VerifyLogin(username, token); + })); } void ConfigureWeb::OnLoginVerified() { @@ -109,16 +141,16 @@ void ConfigureWeb::OnLoginVerified() { user_verified = true; const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16); - ui->label_username_verified->setPixmap(pixmap); ui->label_token_verified->setPixmap(pixmap); + ui->username->setText( + QString::fromStdString(UsernameFromDisplayToken(ui->edit_token->text().toStdString()))); } else { const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16); - ui->label_username_verified->setPixmap(pixmap); ui->label_token_verified->setPixmap(pixmap); - QMessageBox::critical( - this, tr("Verification failed"), - tr("Verification failed. Check that you have entered your username and token " - "correctly, and that your internet connection is working.")); + ui->username->setText(tr("Unspecified")); + QMessageBox::critical(this, tr("Verification failed"), + tr("Verification failed. Check that you have entered your token " + "correctly, and that your internet connection is working.")); } } diff --git a/src/citra_qt/configuration/configure_web.ui b/src/citra_qt/configuration/configure_web.ui index ab35591574..372297dec9 100644 --- a/src/citra_qt/configuration/configure_web.ui +++ b/src/citra_qt/configuration/configure_web.ui @@ -55,11 +55,7 @@ - - - 36 - - + @@ -79,14 +75,10 @@ - - - - - 36 + 80 QLineEdit::Password From a1544d8669b53391167ef23b5b0f7fbc84449b52 Mon Sep 17 00:00:00 2001 From: bunnei Date: Sat, 9 Nov 2019 02:42:37 -0500 Subject: [PATCH 2/2] dedicated_room: Support single Base64 token. --- src/dedicated_room/CMakeLists.txt | 2 +- src/dedicated_room/citra-room.cpp | 40 ++++++++++++++++++++++++------- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/src/dedicated_room/CMakeLists.txt b/src/dedicated_room/CMakeLists.txt index 2492bc5234..2b91daa705 100644 --- a/src/dedicated_room/CMakeLists.txt +++ b/src/dedicated_room/CMakeLists.txt @@ -13,7 +13,7 @@ if (ENABLE_WEB_SERVICE) target_link_libraries(citra-room PRIVATE web_service) endif() -target_link_libraries(citra-room PRIVATE glad) +target_link_libraries(citra-room PRIVATE cryptopp glad) if (MSVC) target_link_libraries(citra-room PRIVATE getopt) endif() diff --git a/src/dedicated_room/citra-room.cpp b/src/dedicated_room/citra-room.cpp index 3ba3972acd..ea9262046f 100644 --- a/src/dedicated_room/citra-room.cpp +++ b/src/dedicated_room/citra-room.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #ifdef _WIN32 @@ -66,6 +67,24 @@ static void PrintVersion() { /// The magic text at the beginning of a citra-room ban list file. static constexpr char BanListMagic[] = "CitraRoom-BanList-1"; +static constexpr char token_delimiter{':'}; + +static std::string UsernameFromDisplayToken(const std::string& display_token) { + std::string unencoded_display_token; + CryptoPP::StringSource ss( + display_token, true, + new CryptoPP::Base64Decoder(new CryptoPP::StringSink(unencoded_display_token))); + return unencoded_display_token.substr(0, unencoded_display_token.find(token_delimiter)); +} + +static std::string TokenFromDisplayToken(const std::string& display_token) { + std::string unencoded_display_token; + CryptoPP::StringSource ss( + display_token, true, + new CryptoPP::Base64Decoder(new CryptoPP::StringSink(unencoded_display_token))); + return unencoded_display_token.substr(unencoded_display_token.find(token_delimiter) + 1); +} + static Network::Room::BanList LoadBanList(const std::string& path) { std::ifstream file; OpenFStream(file, path, std::ios_base::in); @@ -158,7 +177,7 @@ int main(int argc, char** argv) { {"password", required_argument, 0, 'w'}, {"preferred-game", required_argument, 0, 'g'}, {"preferred-game-id", required_argument, 0, 'i'}, - {"username", required_argument, 0, 'u'}, + {"username", optional_argument, 0, 'u'}, {"token", required_argument, 0, 't'}, {"web-api-url", required_argument, 0, 'a'}, {"ban-list-file", required_argument, 0, 'b'}, @@ -248,10 +267,6 @@ int main(int argc, char** argv) { "list.\nSet with --ban-list-file \n\n"; } bool announce = true; - if (username.empty()) { - announce = false; - std::cout << "username is empty: Hosting a private room\n\n"; - } if (token.empty() && announce) { announce = false; std::cout << "token is empty: Hosting a private room\n\n"; @@ -261,10 +276,17 @@ int main(int argc, char** argv) { std::cout << "endpoint url is empty: Hosting a private room\n\n"; } if (announce) { - std::cout << "Hosting a public room\n\n"; - Settings::values.web_api_url = web_api_url; - Settings::values.citra_username = username; - Settings::values.citra_token = token; + if (username.empty()) { + std::cout << "Hosting a public room\n\n"; + Settings::values.web_api_url = web_api_url; + Settings::values.citra_username = UsernameFromDisplayToken(token); + Settings::values.citra_token = TokenFromDisplayToken(token); + } else { + std::cout << "Hosting a public room\n\n"; + Settings::values.web_api_url = web_api_url; + Settings::values.citra_username = username; + Settings::values.citra_token = token; + } } if (!announce && enable_citra_mods) { enable_citra_mods = false;